1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-07-17 21:35:11 +00:00
oot/tools/assets/extract/extase_oot64/collision_resources.py
fig02 28cc9d68cf
Remove "z64" prefix from all headers (#2518)
* z64 - a

* z64 - b

* z64 - c

* z64 - d

* z64 - e

* z64 - f

* z64 - g

* z64 - h

* z64 - i

* z64 - l

* z64 - m

* z64 - o

* z64 - p

* z64 - q

* z64 - r

* z64 - s

* z64 - t

* z64 - v

* restore file

* fix merge

* fix merge

---------

Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com>
2025-06-04 14:38:33 -04:00

832 lines
28 KiB
Python

# SPDX-FileCopyrightText: © 2025 ZeldaRET
# SPDX-License-Identifier: CC0-1.0
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from ..extase.memorymap import MemoryContext
from ..extase import (
File,
RESOURCE_PARSE_SUCCESS,
ResourceParseInProgress,
ResourceParseWaiting,
)
from ..extase.cdata_resources import (
CDataResource,
CDataExt_Struct,
CDataExt_Array,
CDataExt_Value,
CDataExtWriteContext,
cdata_ext_Vec3s,
cdata_ext_Vec3s_aligned,
INDENT,
fmt_hex_u,
)
from .. import oot64_data
# TODO would be better for array resources to be of unknown size at instanciation
# and have their size set later, like LimbsArrayResource,
# which allows declaring them with offsets in xmls and have the data parsing
# fill in the length for both cases of it instantiating the array,
# and it being instantiated much earlier from the xml
class CollisionVtxListResource(CDataResource):
cdata_ext_elem = cdata_ext_Vec3s_aligned
def __init__(self, file: File, range_start: int, name: str, length: int):
self.cdata_ext = CDataExt_Array(self.cdata_ext_elem, length)
super().__init__(file, range_start, name)
def get_c_declaration_base(self):
if hasattr(self, "HACK_IS_STATIC_ON"):
return f"Vec3s {self.symbol_name}[{self.cdata_ext.length}]"
return f"Vec3s {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError()
def get_c_expression_length(self, resource_offset: int):
if resource_offset == 0:
return f"ARRAY_COUNT({self.symbol_name})"
else:
raise ValueError()
def get_h_includes(self):
return ("z_math.h",)
class CollisionPolyListResource(CDataResource):
def write_vtxData(
resource: "CollisionPolyListResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, list)
assert len(v) == 3
vtxData = v
f = wctx.f
f.write(wctx.line_prefix)
f.write("{\n")
for i in range(3):
vI = vtxData[i]
vtxId = vI & 0x1FFF
flags = (vI & 0xE000) >> 13
flags_str_list = []
if i == 0:
if flags & 1:
flags &= ~1
flags_str_list.append("COLPOLY_IGNORE_CAMERA")
if flags & 2:
flags &= ~2
flags_str_list.append("COLPOLY_IGNORE_ENTITY")
if flags & 4:
flags &= ~4
flags_str_list.append("COLPOLY_IGNORE_PROJECTILES")
elif i == 1:
if flags & 1:
flags &= ~1
flags_str_list.append("COLPOLY_IS_FLOOR_CONVEYOR")
if flags != 0:
flags_str_list.append(f"0x{flags:X}")
if flags_str_list:
flags_str = " | ".join(flags_str_list)
else:
flags_str = "0"
f.write(wctx.line_prefix)
f.write(INDENT)
f.write(f"COLPOLY_VTX({vtxId}, {flags_str}), // {i}\n")
f.write(wctx.line_prefix)
f.write("}")
return True
def write_normal_component(
resource: "CollisionPolyListResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
nf = v / 0x7FFF
if int(round(nf, 5) * 0x7FFF) != v:
if v < 0:
nf -= 0.000_01
elif v > 0:
nf += 0.000_01
ns = f"{nf:.5f}"
while ns[-1] == "0" and ns[-2] != ".":
ns = ns[:-1]
wctx.f.write(wctx.line_prefix)
wctx.f.write(f"COLPOLY_SNORMAL({ns})")
return True
normal_component = CDataExt_Value("h").set_write(write_normal_component)
cdata_ext_elem = CDataExt_Struct(
(
("type", CDataExt_Value.u16),
("vtxData", CDataExt_Array(CDataExt_Value.u16, 3).set_write(write_vtxData)),
(
"normal",
CDataExt_Struct(
(
("x", normal_component),
("y", normal_component),
("z", normal_component),
)
),
),
("dist", CDataExt_Value.s16),
)
)
def __init__(self, file: File, range_start: int, name: str, length: int):
self.cdata_ext = CDataExt_Array(self.cdata_ext_elem, length)
super().__init__(file, range_start, name)
def try_parse_data(self, memory_context):
super().try_parse_data(memory_context)
self.max_surface_type_index = max(elem["type"] for elem in self.cdata_unpacked)
assert isinstance(self.max_surface_type_index, int)
return RESOURCE_PARSE_SUCCESS
def get_c_declaration_base(self):
if hasattr(self, "HACK_IS_STATIC_ON"):
return f"CollisionPoly {self.symbol_name}[{self.cdata_ext.length}]"
return f"CollisionPoly {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError()
def get_c_expression_length(self, resource_offset: int):
if resource_offset == 0:
return f"ARRAY_COUNT({self.symbol_name})"
else:
raise ValueError()
def get_h_includes(self):
return ("bgcheck.h",)
class CollisionSurfaceTypeListResource(CDataResource):
def write_data(
resource: "CollisionSurfaceTypeListResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, list)
assert len(v) == 2
f = wctx.f
f.write(wctx.line_prefix)
f.write("{\n")
for i_data, bitfield_info in (
(
0,
(
(0x000000FF, 0, "bgCamIndex", int),
(0x00001F00, 8, "exitIndex", int),
(0x0003E000, 13, "floorType", oot64_data.misc_ids.FLOOR_TYPES),
(0x001C0000, 18, "unk18", int),
(0x03E00000, 21, "wallType", oot64_data.misc_ids.WALL_TYPES),
(
0x3C000000,
26,
"floorProperty",
oot64_data.misc_ids.FLOOR_PROPERTIES,
),
(0x40000000, 30, "isSoft", bool),
(0x80000000, 31, "isHorseBlocked", bool),
),
),
(
1,
(
(0x0000000F, 0, "material", oot64_data.misc_ids.SURFACE_MATERIALS),
(0x00000030, 4, "floorEffect", oot64_data.misc_ids.FLOOR_EFFECTS),
(0x000007C0, 6, "lightSetting", int),
(0x0001F800, 11, "echo", int),
(0x00020000, 17, "canHookshot", bool),
(
0x001C0000,
18,
"conveyorSpeed",
oot64_data.misc_ids.CONVEYOR_SPEEDS,
),
(
0x07E00000,
21,
"conveyorDirection",
lambda val: f"CONVEYOR_DIRECTION_FROM_BINANG({fmt_hex_u(val * (0x10000 // 64))})",
),
(0x08000000, 27, "unk27", bool),
),
),
):
data_val = v[i_data]
f.write(wctx.line_prefix)
f.write(INDENT)
f.write(f"SURFACETYPE{i_data}(\n")
lines = []
for mask, shift, name, fmt_info in bitfield_info:
val = (data_val & mask) >> shift
if fmt_info == int:
lines.append(f"/* {name} */ {val}")
elif fmt_info == bool:
assert val in {0, 1}
lines.append(f"/* {name} */ {'true' if val else 'false'}")
elif isinstance(fmt_info, dict):
lines.append(fmt_info[val])
elif callable(fmt_info):
lines.append(fmt_info(val))
else:
lines.append(f"/* {name} */ {val}")
f.write(",\n".join(f"{wctx.line_prefix}{INDENT * 2}{_l}" for _l in lines))
f.write("\n")
f.write(wctx.line_prefix)
f.write(INDENT)
f.write("),\n")
f.write(wctx.line_prefix)
f.write("}")
return True
cdata_ext_elem = CDataExt_Struct(
(("data", CDataExt_Array(CDataExt_Value.u32, 2).set_write(write_data)),)
)
def __init__(self, file: File, range_start: int, name: str, length: int):
self.cdata_ext = CDataExt_Array(self.cdata_ext_elem, length)
super().__init__(file, range_start, name)
def try_parse_data(self, memory_context):
super().try_parse_data(memory_context)
self.max_bgCamIndex = max(
elem["data"][0] & 0xFF for elem in self.cdata_unpacked
)
self.max_exitIndex = max(
(elem["data"][0] & 0x00001F00) >> 8 for elem in self.cdata_unpacked
)
return RESOURCE_PARSE_SUCCESS
def get_c_declaration_base(self):
if hasattr(self, "HACK_IS_STATIC_ON"):
return f"SurfaceType {self.symbol_name}[{self.cdata_ext.length}]"
return f"SurfaceType {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError()
def get_c_includes(self):
return ("stdbool.h",)
def get_h_includes(self):
return ("bgcheck.h",)
class BgCamFuncDataResource(CDataResource):
element_cdata_ext = cdata_ext_Vec3s
def __init__(self, file: File, range_start: int, range_end: int, name: str):
count = (range_end - range_start) // self.element_cdata_ext.size
self.cdata_ext = CDataExt_Array(self.element_cdata_ext, count)
super().__init__(file, range_start, name)
def get_c_declaration_base(self):
if hasattr(self, "HACK_IS_STATIC_ON"):
return f"Vec3s {self.symbol_name}[{self.cdata_ext.length}]"
return f"Vec3s {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset % self.element_cdata_ext.size != 0:
raise ValueError(
"unaligned offset into Vec3s array (BgCamFuncData)",
hex(resource_offset),
self.element_cdata_ext.size,
)
index = resource_offset // self.element_cdata_ext.size
return f"&{self.symbol_name}[{index}]"
def get_h_includes(self):
return ("z_math.h",)
class CollisionBgCamListResource(CDataResource):
def write_bgCamFuncData(
resource: "CollisionSurfaceTypeListResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
address = v
wctx.f.write(wctx.line_prefix)
if address != 0:
wctx.f.write(memory_context.get_c_reference_at_segmented(address))
else:
wctx.f.write("NULL")
return True
cdata_ext_elem = CDataExt_Struct(
(
(
"setting",
CDataExt_Value("H").set_write_str_v(
lambda v: oot64_data.get_camera_setting_type_name(v)
),
),
("count", CDataExt_Value.s16),
(
"bgCamFuncData",
CDataExt_Value("I").set_write(write_bgCamFuncData),
), # Vec3s*
)
)
def __init__(self, file: File, range_start: int, name: str, length: int):
self.cdata_ext = CDataExt_Array(self.cdata_ext_elem, length)
super().__init__(file, range_start, name)
def try_parse_data(self, memory_context):
super().try_parse_data(memory_context)
# Note: operating directly on the segmented addresses here,
# so assuming from the start all bgCamFuncData use the same segment
bgCamFuncData_buffer_start = None
bgCamFuncData_buffer_end = None
for bgCamInfo in self.cdata_unpacked:
count = bgCamInfo["count"]
assert isinstance(count, int)
bgCamFuncData = bgCamInfo["bgCamFuncData"]
assert isinstance(bgCamFuncData, int)
if bgCamFuncData == 0:
continue
if bgCamFuncData_buffer_start is None:
bgCamFuncData_buffer_start = bgCamFuncData
bgCamFuncData_buffer_end = (
bgCamFuncData + count * BgCamFuncDataResource.element_cdata_ext.size
)
continue
assert bgCamFuncData_buffer_start is not None
assert bgCamFuncData_buffer_end is not None
if bgCamFuncData != bgCamFuncData_buffer_end:
raise NotImplementedError(
"bgCamFuncData buffer not used in the same order as its elements"
)
bgCamFuncData_buffer_end += (
count * BgCamFuncDataResource.element_cdata_ext.size
)
if bgCamFuncData_buffer_start is not None:
assert bgCamFuncData_buffer_end is not None
memory_context.report_resource_at_segmented(
self,
bgCamFuncData_buffer_start,
BgCamFuncDataResource,
lambda file, offset: BgCamFuncDataResource(
file,
offset,
offset + bgCamFuncData_buffer_end - bgCamFuncData_buffer_start,
f"{self.name}_{bgCamFuncData_buffer_start:08X}_BgCamFuncData",
),
)
return RESOURCE_PARSE_SUCCESS
def get_c_declaration_base(self):
if hasattr(self, "HACK_IS_STATIC_ON"):
return f"BgCamInfo {self.symbol_name}[{self.cdata_ext.length}]"
return f"BgCamInfo {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError()
def get_c_includes(self):
return ("camera.h",)
def get_h_includes(self):
return ("bgcheck.h",)
class CollisionWaterBoxesResource(CDataResource):
def write_properties(v):
bgCamIndex = (v >> 0) & 0xFF
lightIndex = (v >> 8) & 0x1F
room = (v >> 13) & 0x3F
setFlag19 = (v >> 19) & 1
return f"WATERBOX_PROPERTIES(/* bgCamIndex */ {bgCamIndex}, /* lightIndex */ {lightIndex}, /* room */ {room}, /* setFlag19 */ {'true' if setFlag19 else 'false'})"
elem_cdata_ext = CDataExt_Struct(
(
("xMin", CDataExt_Value.s16),
("ySurface", CDataExt_Value.s16),
("zMin", CDataExt_Value.s16),
("xLength", CDataExt_Value.s16),
("zLength", CDataExt_Value.s16),
("pad12", CDataExt_Value.pad16),
("properties", CDataExt_Value("I").set_write_str_v(write_properties)),
)
)
def __init__(self, file: File, range_start: int, name: str, length: int):
self.cdata_ext = CDataExt_Array(self.elem_cdata_ext, length)
super().__init__(file, range_start, name)
def get_c_declaration_base(self):
return f"WaterBox {self.symbol_name}[]"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError
def get_c_expression_length(self, resource_offset: int):
if resource_offset == 0:
return f"ARRAY_COUNT({self.symbol_name})"
else:
raise ValueError
def get_c_includes(self):
return ("stdbool.h",)
def get_h_includes(self):
return ("bgcheck.h",)
def transfer_HACK_IS_STATIC_ON(source, dest):
if hasattr(source, "HACK_IS_STATIC_ON"):
dest.HACK_IS_STATIC_ON = source.HACK_IS_STATIC_ON
return dest
class CollisionResource(CDataResource):
def write_numVertices(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
wctx.f.write(wctx.line_prefix)
wctx.f.write(
memory_context.get_c_expression_length_at_segmented(
resource.cdata_unpacked["vtxList"]
)
)
return True
def report_vtxList(
resource: "CollisionResource", memory_context: "MemoryContext", v
):
assert isinstance(v, int)
address = v
memory_context.report_resource_at_segmented(
resource,
address,
CollisionVtxListResource,
lambda file, offset: transfer_HACK_IS_STATIC_ON(
resource,
CollisionVtxListResource(
file,
offset,
(
f"{resource.name.removesuffix('Col')}VtxList"
if resource.name.endswith("Col")
else f"{resource.name}_{address:08X}_VtxList"
),
resource.cdata_unpacked["numVertices"],
),
),
)
def write_vtxList(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
wctx.f.write(wctx.line_prefix)
wctx.f.write(memory_context.get_c_reference_at_segmented(v))
return True
def write_numPolygons(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
wctx.f.write(wctx.line_prefix)
wctx.f.write(
memory_context.get_c_expression_length_at_segmented(
resource.cdata_unpacked["polyList"]
)
)
return True
def report_polyList(
resource: "CollisionResource", memory_context: "MemoryContext", v
):
assert isinstance(v, int)
address = v
resource.resource_polyList = memory_context.report_resource_at_segmented(
resource,
address,
CollisionPolyListResource,
lambda file, offset: transfer_HACK_IS_STATIC_ON(
resource,
CollisionPolyListResource(
file,
offset,
(
f"{resource.name.removesuffix('Col')}PolyList"
if resource.name.endswith("Col")
else f"{resource.name}_{address:08X}_PolyList"
),
resource.cdata_unpacked["numPolygons"],
),
),
)
def write_polyList(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
address = v
wctx.f.write(wctx.line_prefix)
wctx.f.write(memory_context.get_c_reference_at_segmented(address))
return True
def write_numWaterBoxes(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
wctx.f.write(wctx.line_prefix)
length = resource.cdata_unpacked["numWaterBoxes"]
if length != 0:
wctx.f.write(
memory_context.get_c_expression_length_at_segmented(
resource.cdata_unpacked["waterBoxes"]
)
)
else:
wctx.f.write("0")
return True
def report_waterBoxes(
resource: "CollisionResource", memory_context: "MemoryContext", v
):
assert isinstance(v, int)
address = v
length = resource.cdata_unpacked["numWaterBoxes"]
if length != 0:
assert address != 0, address # should not be NULL
memory_context.report_resource_at_segmented(
resource,
address,
CollisionWaterBoxesResource,
lambda file, offset: transfer_HACK_IS_STATIC_ON(
resource,
CollisionWaterBoxesResource(
file,
offset,
(
f"{resource.name.removesuffix('Col')}WaterBoxes"
if resource.name.endswith("Col")
else f"{resource.name}_{address:08X}_WaterBoxes"
),
length,
),
),
)
def write_surfaceTypeList(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
wctx.f.write(wctx.line_prefix)
wctx.f.write(memory_context.get_c_reference_at_segmented(v))
return True
def write_bgCamList(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
wctx.f.write(wctx.line_prefix)
wctx.f.write(memory_context.get_c_reference_at_segmented(v))
return True
def write_waterBoxes(
resource: "CollisionResource",
memory_context: "MemoryContext",
v,
wctx: CDataExtWriteContext,
):
assert isinstance(v, int)
length = resource.cdata_unpacked["numWaterBoxes"]
f = wctx.f
f.write(wctx.line_prefix)
if length != 0:
f.write(memory_context.get_c_reference_at_segmented(v))
else:
if v == 0:
f.write("NULL")
else:
f.write(f"0x{v:08X}")
return True
cdata_ext = CDataExt_Struct(
(
("minBounds", cdata_ext_Vec3s),
("maxBounds", cdata_ext_Vec3s),
("numVertices", CDataExt_Value("H").set_write(write_numVertices)),
("pad14", CDataExt_Value.pad16),
(
"vtxList",
CDataExt_Value("I").set_report(report_vtxList).set_write(write_vtxList),
), # Vec3s*
("numPolygons", CDataExt_Value("H").set_write(write_numPolygons)),
("pad22", CDataExt_Value.pad16),
(
"polyList",
CDataExt_Value("I")
.set_report(report_polyList)
.set_write(write_polyList),
), # CollisionPoly*
(
"surfaceTypeList",
CDataExt_Value("I").set_write(write_surfaceTypeList),
), # SurfaceType*
("bgCamList", CDataExt_Value("I").set_write(write_bgCamList)), # BgCamInfo*
("numWaterBoxes", CDataExt_Value("H").set_write(write_numWaterBoxes)),
("pad38", CDataExt_Value.pad16),
(
"waterBoxes",
CDataExt_Value("I")
.set_report(report_waterBoxes)
.set_write(write_waterBoxes),
), # WaterBox*
)
)
def __init__(self, file: File, range_start: int, name: str):
super().__init__(file, range_start, name)
self.length_exitList: Optional[int] = None
self.resource_polyList: Optional[CollisionPolyListResource] = None
self.resource_surfaceTypeList: Optional[CollisionSurfaceTypeListResource] = None
self.resource_bgCamList: Optional[CollisionBgCamListResource] = None
def try_parse_data(self, memory_context):
super().try_parse_data(memory_context)
assert self.resource_polyList is not None
new_progress_done = []
waiting_for = []
# If the CollisionPolyListResource is parsed
if self.resource_polyList.is_data_parsed:
# report surfaceTypeList based on its length guessed from polyList data
length_surfaceTypeList = self.resource_polyList.max_surface_type_index + 1
surfaceTypeList_address = self.cdata_unpacked["surfaceTypeList"]
assert isinstance(surfaceTypeList_address, int)
self.resource_surfaceTypeList = memory_context.report_resource_at_segmented(
self,
surfaceTypeList_address,
CollisionSurfaceTypeListResource,
lambda file, offset: transfer_HACK_IS_STATIC_ON(
self,
CollisionSurfaceTypeListResource(
file,
offset,
(
f"{self.name.removesuffix('Col')}SurfaceTypes"
if self.name.endswith("Col")
else f"{self.name}_{surfaceTypeList_address:08X}_SurfaceTypes"
),
length_surfaceTypeList, # TODO change CollisionSurfaceTypeListResource to a CDataArrayResource (same with more resources)
),
),
)
new_progress_done.append("reported CollisionSurfaceTypeListResource")
else:
waiting_for.append(
(
"waiting for CollisionPolyListResource"
" to be parsed to report CollisionSurfaceTypeListResource",
self.resource_polyList,
)
)
if self.resource_surfaceTypeList is not None:
# If the CollisionSurfaceTypeListResource is parsed
if self.resource_surfaceTypeList.is_data_parsed:
# report bgCamList based on its length guessed from surfaceTypeList data
length_bgCamList = self.resource_surfaceTypeList.max_bgCamIndex + 1
bgCamList_address = self.cdata_unpacked["bgCamList"]
assert isinstance(bgCamList_address, int)
self.resource_bgCamList = memory_context.report_resource_at_segmented(
self,
bgCamList_address,
CollisionBgCamListResource,
lambda file, offset: transfer_HACK_IS_STATIC_ON(
self,
CollisionBgCamListResource(
file,
offset,
(
f"{self.name.removesuffix('Col')}BgCamList"
if self.name.endswith("Col")
else f"{self.name}_{bgCamList_address:08X}_BgCamList"
),
length_bgCamList,
),
),
)
# exitIndex is 1-indexed, so e.g. if the max is 1 the list is of length 1.
self.length_exitList = self.resource_surfaceTypeList.max_exitIndex
new_progress_done.append("reported CollisionBgCamListResource")
else:
waiting_for.append(
(
"waiting for CollisionSurfaceTypeListResource"
" to be parsed to report CollisionBgCamListResource",
self.resource_surfaceTypeList,
)
)
else:
waiting_for.append("self.resource_surfaceTypeList")
if waiting_for:
if new_progress_done:
raise ResourceParseInProgress(
new_progress_done=new_progress_done, waiting_for=waiting_for
)
else:
raise ResourceParseWaiting(waiting_for=waiting_for)
assert (
self.resource_surfaceTypeList is not None
and self.resource_bgCamList is not None
and self.length_exitList is not None
)
return RESOURCE_PARSE_SUCCESS
def get_c_declaration_base(self):
return f"CollisionHeader {self.symbol_name}"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return f"&{self.symbol_name}"
else:
raise ValueError()
def get_c_includes(self):
return ("array_count.h",)
def get_h_includes(self):
return ("bgcheck.h",)