Skip to content

Commit 7320bfc

Browse files
g/jak1: Extract ambient data to json (#3945)
I added extraction of ambients to json files when extracting the levels. All of the ambient json files are written to the same folder as actors are. Ambients aren't used in jak2 and 3 so it only is used on jak1. ![image](https://github.com/user-attachments/assets/26e5d655-6a31-49eb-8514-3374b41f72dd) --------- Co-authored-by: Tyler Wilding <xtvaser@gmail.com>
1 parent 012ff7b commit 7320bfc

File tree

5 files changed

+246
-1
lines changed

5 files changed

+246
-1
lines changed

decompiler/level_extractor/BspHeader.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,13 @@ std::string DrawableActor::print(const PrintSettings& /*settings*/, int indent)
527527
return result;
528528
}
529529

530+
std::string DrawableAmbient::print(const PrintSettings& /*settings*/, int indent) const {
531+
std::string is(indent, ' ');
532+
std::string result;
533+
result += fmt::format("{}bsphere: {}", is, bsphere.print_meters());
534+
return result;
535+
}
536+
530537
void InstanceTie::read_from_file(TypedRef ref,
531538
const decompiler::DecompilerTypeSystem& dts,
532539
GameVersion /*version*/) {
@@ -1952,6 +1959,110 @@ void DrawableInlineArrayActor::read_from_file(TypedRef ref,
19521959
}
19531960
}
19541961

1962+
void EntityAmbient::read_from_file(TypedRef ref,
1963+
const decompiler::DecompilerTypeSystem& dts,
1964+
GameVersion /*version*/) {
1965+
trans.read_from_file(get_field_ref(ref, "trans", dts));
1966+
aid = read_plain_data_field<u32>(ref, "aid", dts);
1967+
// ambientData = read_plain_data_field<u128>(ref, "extra", dts); // to-do: get ambient-data, not
1968+
// sure if nessecary tho
1969+
1970+
int res_length = read_plain_data_field<int32_t>(ref, "length", dts);
1971+
// int res_allocated_length = read_plain_data_field<int32_t>(ref, "allocated-length", dts);
1972+
1973+
auto tags = deref_label(get_field_ref(ref, "tag", dts));
1974+
auto data_base = deref_label(get_field_ref(ref, "data-base", dts));
1975+
1976+
for (int i = 0; i < res_length; i++) {
1977+
auto& res = res_list.emplace_back();
1978+
res.name = read_symbol(tags);
1979+
tags.byte_offset += 4;
1980+
res.key_frame = deref_float(tags, 0);
1981+
tags.byte_offset += 4;
1982+
res.elt_type = read_type(tags);
1983+
tags.byte_offset += 4;
1984+
const u32 vals = deref_u32(tags, 0);
1985+
const u32 offset = vals & 0xffff; // 16 bits
1986+
res.count = (vals >> 16) & 0x7fff; // 15 bits
1987+
res.inlined = vals & 0x8000'0000;
1988+
1989+
Ref data = data_base;
1990+
data.byte_offset += offset;
1991+
1992+
if (res.elt_type == "string") {
1993+
ASSERT(!res.inlined);
1994+
for (int j = 0; j < res.count; j++) {
1995+
res.strings.push_back(read_string_ref(data));
1996+
data.byte_offset += 4;
1997+
}
1998+
} else if (res.elt_type == "symbol") {
1999+
ASSERT(!res.inlined);
2000+
for (int j = 0; j < res.count; j++) {
2001+
res.strings.push_back(read_symbol(data));
2002+
data.byte_offset += 4;
2003+
}
2004+
} else if (res.elt_type == "type") {
2005+
ASSERT(!res.inlined);
2006+
for (int j = 0; j < res.count; j++) {
2007+
res.strings.push_back(read_type(data));
2008+
data.byte_offset += 4;
2009+
}
2010+
} else if (res.elt_type == "vector") {
2011+
ASSERT(res.inlined);
2012+
res.inlined_storage = bytes_from_plain_data(data, 16 * res.count);
2013+
} else if (res.elt_type == "float") {
2014+
fill_res_with_value_types<float>(res, data);
2015+
} else if (res.elt_type == "int32") {
2016+
fill_res_with_value_types<int32_t>(res, data);
2017+
} else if (res.elt_type == "int16") {
2018+
fill_res_with_value_types<int16_t>(res, data);
2019+
} else if (res.elt_type == "int8") {
2020+
fill_res_with_value_types<int8_t>(res, data);
2021+
} else if (res.elt_type == "uint32") {
2022+
fill_res_with_value_types<uint32_t>(res, data);
2023+
} else if (res.elt_type == "uint8") {
2024+
fill_res_with_value_types<uint8_t>(res, data);
2025+
} else if (res.elt_type == "actor-group") {
2026+
// TODO: unsupported.
2027+
} else if (res.elt_type == "pair") {
2028+
ASSERT(res.count == 1);
2029+
ASSERT(!res.inlined);
2030+
data = deref_label(data);
2031+
res.script = data.data->to_form_script(data.seg, (data.byte_offset) / 4, nullptr);
2032+
} else {
2033+
fmt::print("unhandled elt_type: {}\n", res.elt_type);
2034+
ASSERT_NOT_REACHED();
2035+
}
2036+
2037+
tags.byte_offset += 4;
2038+
}
2039+
}
2040+
2041+
void DrawableAmbient::read_from_file(TypedRef ref,
2042+
const decompiler::DecompilerTypeSystem& dts,
2043+
GameVersion version) {
2044+
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
2045+
ambient.read_from_file(get_and_check_ref_to_basic(ref, "ambient", "entity-ambient", dts), dts,
2046+
version);
2047+
}
2048+
2049+
void DrawableInlineArrayAmbient::read_from_file(TypedRef ref,
2050+
const decompiler::DecompilerTypeSystem& dts,
2051+
GameVersion version) {
2052+
int numAmbients = read_plain_data_field<int16_t>(ref, "length", dts);
2053+
auto data_ref = get_field_ref(ref, "data", dts);
2054+
for (int i = 0; i < numAmbients; i++) {
2055+
Ref obj_ref = data_ref;
2056+
obj_ref.byte_offset += 32 * i; // todo not a constant here
2057+
auto type = get_type_of_basic(obj_ref);
2058+
if (type != "drawable-ambient") {
2059+
throw Error("bad drawable-ambient type: {}", type);
2060+
}
2061+
drawable_ambients.emplace_back();
2062+
drawable_ambients.back().read_from_file(typed_ref_from_basic(obj_ref, dts), dts, version);
2063+
}
2064+
}
2065+
19552066
void CollideHash::read_from_file(TypedRef ref,
19562067
const decompiler::DecompilerTypeSystem& dts,
19572068
GameVersion /*version*/) {
@@ -2065,6 +2176,11 @@ void BspHeader::read_from_file(const decompiler::LinkedObjectFile& file,
20652176
actors.read_from_file(
20662177
get_and_check_ref_to_basic(ref, "actors", "drawable-inline-array-actor", dts), dts,
20672178
version);
2179+
if (get_word_kind_for_field(ref, "ambients", dts) == decompiler::LinkedWord::PTR) {
2180+
ambients.read_from_file(
2181+
get_and_check_ref_to_basic(ref, "ambients", "drawable-inline-array-ambient", dts), dts,
2182+
version);
2183+
}
20682184
}
20692185

20702186
if (version > GameVersion::Jak1 &&

decompiler/level_extractor/BspHeader.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,31 @@ struct DrawableActor : public Drawable {
189189
std::string my_type() const override { return "drawable-actor"; }
190190
};
191191

192+
struct EntityAmbient {
193+
Vector trans;
194+
u32 aid = 0;
195+
196+
u128 ambientData;
197+
198+
std::vector<Res> res_list;
199+
200+
void read_from_file(TypedRef ref,
201+
const decompiler::DecompilerTypeSystem& dts,
202+
GameVersion version);
203+
};
204+
205+
struct DrawableAmbient : public Drawable {
206+
Vector bsphere;
207+
208+
EntityAmbient ambient;
209+
210+
void read_from_file(TypedRef ref,
211+
const decompiler::DecompilerTypeSystem& dts,
212+
GameVersion version) override;
213+
std::string print(const PrintSettings& settings, int indent) const override;
214+
std::string my_type() const override { return "drawable-ambient"; }
215+
};
216+
192217
struct DrawableTreeActor : public DrawableTree {
193218
void read_from_file(TypedRef ref,
194219
const decompiler::DecompilerTypeSystem& dts,
@@ -765,6 +790,13 @@ struct DrawableInlineArrayActor {
765790
GameVersion version);
766791
};
767792

793+
struct DrawableInlineArrayAmbient {
794+
std::vector<DrawableAmbient> drawable_ambients;
795+
void read_from_file(TypedRef ref,
796+
const decompiler::DecompilerTypeSystem& dts,
797+
GameVersion version);
798+
};
799+
768800
struct CollideHash {
769801
Ref item_array;
770802
int num_items = 0;
@@ -912,6 +944,7 @@ struct BspHeader {
912944
// (boxes box8s-array :offset-assert 148)
913945
// (current-bsp-back-flags uint32 :offset-assert 152)
914946
// (ambients drawable-inline-array-ambient :offset-assert 156)
947+
DrawableInlineArrayAmbient ambients;
915948
// (unk-data-4 float :offset-assert 160)
916949
// (unk-data-5 float :offset-assert 164)
917950
// (adgifs adgif-shader-array :offset-assert 168)

decompiler/level_extractor/extract_actors.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,95 @@ std::string extract_actors_to_json(const level_tools::DrawableInlineArrayActor&
146146
return json.dump(2);
147147
}
148148

149+
std::string extract_ambients_to_json(const level_tools::DrawableInlineArrayAmbient& actors) {
150+
nlohmann::json json;
151+
152+
for (const auto& damb : actors.drawable_ambients) {
153+
const auto& ambient = damb.ambient;
154+
auto& json_ambient = json.emplace_back();
155+
json_ambient["bsphere"] = vectorm_json(damb.bsphere);
156+
// drawable ID?
157+
158+
json_ambient["trans"] = vectorm_json(ambient.trans);
159+
json_ambient["aid"] = ambient.aid; // aid
160+
161+
auto& json_lump = json_ambient["lump"];
162+
163+
nlohmann::json effects;
164+
int effectCount = 0,
165+
effectParamCount =
166+
0; // just to keep track since names cound all be together and then params
167+
168+
for (const auto& res : ambient.res_list) {
169+
if (res.elt_type == "string") {
170+
if (res.name == "name")
171+
json_lump[res.name] = strings_json(res.strings, false);
172+
else
173+
json_lump[res.name] = strings_json(res.strings, true);
174+
} else if (res.elt_type == "symbol") {
175+
if (res.name == "effect-name") {
176+
if (++effectCount > effectParamCount) {
177+
nlohmann::json effect;
178+
effect["name"] = strings_json(res.strings, false);
179+
effects.push_back(effect);
180+
} else {
181+
auto& effect = effects[effectCount - 1];
182+
effect["name"] = strings_json(res.strings, false);
183+
}
184+
} else {
185+
json_lump[res.name] = strings_json(res.strings, false);
186+
}
187+
} else if (res.elt_type == "type") {
188+
// TODO: confusion with symbols
189+
json_lump[res.name] = strings_json(res.strings, true);
190+
} else if (res.elt_type == "vector") {
191+
const float* data = (const float*)res.inlined_storage.data();
192+
if (res.count == 1) {
193+
json_lump[res.name] = vector_json(data);
194+
} else {
195+
for (int i = 0; i < res.count; i++) {
196+
json_lump[res.name].push_back(vector_json(data + 4 * i));
197+
}
198+
}
199+
} else if (res.elt_type == "pair") {
200+
json_lump[res.name] = pretty_print::to_string(res.script);
201+
} else if (res.elt_type == "float") {
202+
if (res.name == "effect-param") {
203+
if (++effectParamCount > effectCount) {
204+
nlohmann::json effect;
205+
effect["params"] = value_json<float>(res.inlined_storage, res.count);
206+
effects.push_back(effect);
207+
} else {
208+
auto& effect = effects[effectParamCount - 1];
209+
effect["params"] = value_json<float>(res.inlined_storage, res.count);
210+
}
211+
} else {
212+
json_lump[res.name] = value_json<float>(res.inlined_storage, res.count);
213+
}
214+
} else if (res.elt_type == "int32") {
215+
json_lump[res.name] = value_json<int32_t>(res.inlined_storage, res.count);
216+
} else if (res.elt_type == "int16") {
217+
json_lump[res.name] = value_json<int16_t>(res.inlined_storage, res.count);
218+
} else if (res.elt_type == "int8") {
219+
json_lump[res.name] = value_json<int8_t>(res.inlined_storage, res.count);
220+
} else if (res.elt_type == "uint32") {
221+
json_lump[res.name] = value_json<uint32_t>(res.inlined_storage, res.count);
222+
} else if (res.elt_type == "uint16") {
223+
json_lump[res.name] = value_json<uint16_t>(res.inlined_storage, res.count);
224+
} else if (res.elt_type == "uint8") {
225+
json_lump[res.name] = value_json<uint8_t>(res.inlined_storage, res.count);
226+
} else if (res.elt_type == "actor-group") {
227+
// not supported.
228+
} else {
229+
ASSERT_NOT_REACHED();
230+
}
231+
}
232+
233+
if (effectCount || effectParamCount)
234+
json_lump["effects"] = effects;
235+
}
236+
237+
return json.dump(2);
238+
}
239+
149240
} // namespace decompiler

decompiler/level_extractor/extract_actors.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
namespace decompiler {
66

77
std::string extract_actors_to_json(const level_tools::DrawableInlineArrayActor& actors);
8+
std::string extract_ambients_to_json(const level_tools::DrawableInlineArrayAmbient& actors);
89

9-
}
10+
} // namespace decompiler

decompiler/level_extractor/extract_level.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ void extract_from_level(const ObjectFileDB& db,
389389
}
390390
file_util::write_text_file(entities_folder / fmt::format("{}-actors.json", level_data.level_name),
391391
extract_actors_to_json(bsp_header.actors));
392+
if (config.game_version == GameVersion::Jak1)
393+
file_util::write_text_file(
394+
entities_folder / fmt::format("{}-ambients.json", level_data.level_name),
395+
extract_ambients_to_json(bsp_header.ambients));
392396
}
393397

394398
void extract_all_levels(const ObjectFileDB& db,

0 commit comments

Comments
 (0)