Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some fixes and features to make it easier to access data #5

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

/.cache/
/dist/
/build/
/?venv/

*.egg-info/
Expand Down
1 change: 1 addition & 0 deletions src/zenkit/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
DLL: Final[CDLL] = CDLL(str(_PATH))

PathOrFileLike = Union[str, PathLike, "Read", bytes, bytearray, "VfsNode"]
DaedalusSymbolValue = Union[float, int, str, "DaedalusInstance", None]


class GameVersion(IntEnum):
Expand Down
9 changes: 9 additions & 0 deletions src/zenkit/daedalus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@
DaedalusInstanceType.SOUND_EFFECT: SoundEffectInstance,
DaedalusInstanceType.SOUND_SYSTEM: SoundSystemInstance,
}

_CLASS_TYPES = {
"C_NPC": DaedalusInstanceType.NPC,
"C_MISSION": DaedalusInstanceType.MISSION,
"C_ITEM": DaedalusInstanceType.ITEM,
"C_INFO": DaedalusInstanceType.INFO,
"C_ITEMREACT": DaedalusInstanceType.ITEM_REACT,
"C_FOCUS": DaedalusInstanceType.FOCUS,
}
42 changes: 38 additions & 4 deletions src/zenkit/daedalus_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
]

from abc import abstractmethod
from collections.abc import Generator
from ctypes import Structure
from ctypes import c_float
from ctypes import c_int
Expand All @@ -20,8 +21,10 @@
from typing import ClassVar

from zenkit import _native
from zenkit.daedalus import _CLASS_TYPES
from zenkit._core import DLL
from zenkit._core import PathOrFileLike
from zenkit._core import DaedalusSymbolValue
from zenkit._native import ZkPointer
from zenkit._native import ZkString
from zenkit.daedalus.base import DaedalusInstance
Expand Down Expand Up @@ -124,17 +127,28 @@ def set_string(self, val: str, i: int = 0, ctx: DaedalusInstance | None = None)
)

def get_int(self, i: int = 0, ctx: DaedalusInstance | None = None) -> int:
return DLL.ZkDaedalusSymbol_getInt(self._handle, c_uint16(i), ctx.handle if ctx else None).value
return DLL.ZkDaedalusSymbol_getInt(self._handle, c_uint16(i), ctx.handle if ctx else None)

def set_int(self, val: int, i: int = 0, ctx: DaedalusInstance | None = None) -> None:
DLL.ZkDaedalusSymbol_setInt(self._handle, c_int32(val), c_uint16(i), ctx.handle if ctx else None)

def get_float(self, i: int = 0, ctx: DaedalusInstance | None = None) -> float:
return DLL.ZkDaedalusSymbol_getFloat(self._handle, c_uint16(i), ctx.handle if ctx else None).value
return DLL.ZkDaedalusSymbol_getFloat(self._handle, c_uint16(i), ctx.handle if ctx else None)

def set_float(self, val: float, i: int = 0, ctx: DaedalusInstance | None = None) -> None:
DLL.ZkDaedalusSymbol_setFloat(self._handle, c_float(val), c_uint16(i), ctx.handle if ctx else None)

def get_parent_as_symbol(self, find_root: bool = False) -> "DaedalusSymbol | None":
if self.parent < 0:
return None

handle = self._keepalive.get_symbol_by_index(self.parent)

while find_root and handle and handle.parent >= 0:
handle = self._keepalive.get_symbol_by_index(handle.parent)

return handle

@property
def is_const(self) -> bool:
return DLL.ZkDaedalusSymbol_getIsConst(self._handle) != 0
Expand Down Expand Up @@ -187,9 +201,29 @@ def index(self) -> int:
def return_type(self) -> DaedalusDataType:
return DaedalusDataType(DLL.ZkDaedalusSymbol_getReturnType(self._handle))

@property
def value(self) -> DaedalusSymbolValue:
if self.type == DaedalusDataType.FLOAT:
return self.get_float()
if self.type == DaedalusDataType.INT:
return self.get_int()
if self.type == DaedalusDataType.STRING:
return self.get_string()
if self.type == DaedalusDataType.INSTANCE and self.is_const and hasattr(self._keepalive, "init_instance"):
class_sym = self.get_parent_as_symbol(find_root=True)
if class_sym: # Instances always have parent symbols, except for .PAR instances in functions...
typ = _CLASS_TYPES.get(class_sym.name)
if typ: # Unknow classes ex. from Ikarus aren't linked to a type
return self._keepalive.init_instance(self, typ)
return None

def __repr__(self) -> str:
return f"<{self.__class__.__name__} handle={self._handle} name={self.name!r} type={self.type.name}>"

def __str__(self) -> str:
value = self.value
return value.__str__() if value is not None else self.__repr__()


class DaedalusInstruction(Structure):
_fields_: ClassVar[tuple[str, Any]] = [
Expand Down Expand Up @@ -248,9 +282,9 @@ def load(path_or_file_like: PathOrFileLike) -> "DaedalusScript":
return DaedalusScript(_handle=handle, _delete=True)

@property
def symbols(self) -> list[DaedalusSymbol]:
def symbols(self) -> Generator[DaedalusSymbol]:
count = DLL.ZkDaedalusScript_getSymbolCount(self._handle)
return [self.get_symbol_by_index(i) for i in range(count)]
return (self.get_symbol_by_index(i) for i in range(count))

def get_instruction(self, address: int) -> DaedalusInstruction:
return DLL.ZkDaedalusScript_getInstruction(self._handle, c_size_t(address))
Expand Down