From 49382e811c7e589b9d6eb69e3c052aa204e86042 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 12 Aug 2019 19:41:24 +0200 Subject: [PATCH] Parse Tile Entities and Weighed Pressure Plate data --- lihzahrd/{entities => npcs}/__init__.py | 2 +- lihzahrd/{entities => npcs}/mob.py | 5 +- lihzahrd/{entities => npcs}/npc.py | 5 +- .../entitytype.py => npcs/npctype.py} | 0 lihzahrd/pressureplates/__init__.py | 3 + .../pressureplates/weighedpressureplate.py | 13 +++ lihzahrd/signs/sign.py | 3 + lihzahrd/tileentities/__init__.py | 6 ++ lihzahrd/tileentities/itemframe.py | 11 +++ lihzahrd/tileentities/logicsensor.py | 11 +++ lihzahrd/tileentities/targetdummy.py | 8 ++ lihzahrd/tileentities/tileentity.py | 22 +++++ lihzahrd/world.py | 88 ++++++++++++++++--- 13 files changed, 162 insertions(+), 15 deletions(-) rename lihzahrd/{entities => npcs}/__init__.py (70%) rename lihzahrd/{entities => npcs}/mob.py (87%) rename lihzahrd/{entities => npcs}/npc.py (90%) rename lihzahrd/{entities/entitytype.py => npcs/npctype.py} (100%) create mode 100644 lihzahrd/pressureplates/__init__.py create mode 100644 lihzahrd/pressureplates/weighedpressureplate.py create mode 100644 lihzahrd/tileentities/__init__.py create mode 100644 lihzahrd/tileentities/itemframe.py create mode 100644 lihzahrd/tileentities/logicsensor.py create mode 100644 lihzahrd/tileentities/targetdummy.py create mode 100644 lihzahrd/tileentities/tileentity.py diff --git a/lihzahrd/entities/__init__.py b/lihzahrd/npcs/__init__.py similarity index 70% rename from lihzahrd/entities/__init__.py rename to lihzahrd/npcs/__init__.py index 17b8aa4..15f4695 100644 --- a/lihzahrd/entities/__init__.py +++ b/lihzahrd/npcs/__init__.py @@ -1,5 +1,5 @@ from .npc import NPC from .mob import Mob -from .entitytype import EntityType +from .npctype import EntityType __all__ = ["NPC", "Mob", "EntityType"] diff --git a/lihzahrd/entities/mob.py b/lihzahrd/npcs/mob.py similarity index 87% rename from lihzahrd/entities/mob.py rename to lihzahrd/npcs/mob.py index a71178b..4651d9f 100644 --- a/lihzahrd/entities/mob.py +++ b/lihzahrd/npcs/mob.py @@ -1,10 +1,13 @@ import typing -from .entitytype import EntityType +from .npctype import EntityType from ..fileutils import Coordinates class Mob: """A Mob somewhere in the world.""" + + __slots__ = "type", "position" + def __init__(self, type_: int, position: Coordinates, ): diff --git a/lihzahrd/entities/npc.py b/lihzahrd/npcs/npc.py similarity index 90% rename from lihzahrd/entities/npc.py rename to lihzahrd/npcs/npc.py index aa2b296..9493438 100644 --- a/lihzahrd/entities/npc.py +++ b/lihzahrd/npcs/npc.py @@ -1,10 +1,13 @@ import typing -from .entitytype import EntityType +from .npctype import EntityType from ..fileutils import Coordinates class NPC: """A NPC somewhere in the world.""" + + __slots__ = "type", "name", "position", "home" + def __init__(self, type_: EntityType, name: str, diff --git a/lihzahrd/entities/entitytype.py b/lihzahrd/npcs/npctype.py similarity index 100% rename from lihzahrd/entities/entitytype.py rename to lihzahrd/npcs/npctype.py diff --git a/lihzahrd/pressureplates/__init__.py b/lihzahrd/pressureplates/__init__.py new file mode 100644 index 0000000..f3ce0b9 --- /dev/null +++ b/lihzahrd/pressureplates/__init__.py @@ -0,0 +1,3 @@ +from .weighedpressureplate import WeighedPressurePlate + +__all__ = ["WeighedPressurePlate"] diff --git a/lihzahrd/pressureplates/weighedpressureplate.py b/lihzahrd/pressureplates/weighedpressureplate.py new file mode 100644 index 0000000..6e04fcd --- /dev/null +++ b/lihzahrd/pressureplates/weighedpressureplate.py @@ -0,0 +1,13 @@ +from ..fileutils import Coordinates + + +class WeighedPressurePlate: + """A single pressure plate placed in the world.""" + + __slots__ = "position" + + def __init__(self, position: Coordinates): + self.position: Coordinates = position + + def __repr__(self): + return f"PressurePlate(position={self.position})" diff --git a/lihzahrd/signs/sign.py b/lihzahrd/signs/sign.py index cac95c2..f2b9839 100644 --- a/lihzahrd/signs/sign.py +++ b/lihzahrd/signs/sign.py @@ -3,6 +3,9 @@ from ..fileutils import Coordinates class Sign: """A sign with something written on it.""" + + __slots__ = "position", "text" + def __init__(self, position: Coordinates, text: str = ""): self.position: Coordinates = position self.text: str = text diff --git a/lihzahrd/tileentities/__init__.py b/lihzahrd/tileentities/__init__.py new file mode 100644 index 0000000..7947236 --- /dev/null +++ b/lihzahrd/tileentities/__init__.py @@ -0,0 +1,6 @@ +from .tileentity import TileEntity +from .itemframe import ItemFrame +from .logicsensor import LogicSensor +from .targetdummy import TargetDummy + +__all__ = ["TileEntity", "ItemFrame", "LogicSensor", "TargetDummy"] diff --git a/lihzahrd/tileentities/itemframe.py b/lihzahrd/tileentities/itemframe.py new file mode 100644 index 0000000..cc9be1e --- /dev/null +++ b/lihzahrd/tileentities/itemframe.py @@ -0,0 +1,11 @@ +from ..chests import ItemStack + + +class ItemFrame: + __slots__ = "item" + + def __init__(self, item: ItemStack): + self.item: ItemStack = item + + def __repr__(self): + return f"" diff --git a/lihzahrd/tileentities/logicsensor.py b/lihzahrd/tileentities/logicsensor.py new file mode 100644 index 0000000..211f131 --- /dev/null +++ b/lihzahrd/tileentities/logicsensor.py @@ -0,0 +1,11 @@ +class LogicSensor: + """Data pertaining to a Logic Sensor (https://terraria.gamepedia.com/Sensors).""" + + __slots__ = "logic_check", "enabled" + + def __init__(self, logic_check: int, enabled: bool): + self.logic_check: int = logic_check + self.enabled: bool = enabled + + def __repr__(self): + return f"LogicSensor(logic_check={self.logic_check}, enabled={self.enabled})" diff --git a/lihzahrd/tileentities/targetdummy.py b/lihzahrd/tileentities/targetdummy.py new file mode 100644 index 0000000..8d2a748 --- /dev/null +++ b/lihzahrd/tileentities/targetdummy.py @@ -0,0 +1,8 @@ +class TargetDummy: + """Data pertaining to a Target Dummy (https://terraria.gamepedia.com/Target_Dummy)""" + + def __init__(self, npc: int): + self.npc: int = npc + + def __repr__(self): + return f"{self.__class__.__name__}(npc={self.npc})" diff --git a/lihzahrd/tileentities/tileentity.py b/lihzahrd/tileentities/tileentity.py new file mode 100644 index 0000000..0d3d44d --- /dev/null +++ b/lihzahrd/tileentities/tileentity.py @@ -0,0 +1,22 @@ +import typing +from ..fileutils import Coordinates +from .targetdummy import TargetDummy +from .itemframe import ItemFrame +from .logicsensor import LogicSensor + + +class TileEntity: + """A TileEntity, such as a Training Dummy, an Item Frame or a Logic Sensor.""" + + __slots__ = "id", "position", "data" + + def __init__(self, + id_: int, + position: Coordinates, + extra: typing.Union[TargetDummy, ItemFrame, LogicSensor]): + self.id: int = id_ + self.position: Coordinates = position + self.data: typing.Union[TargetDummy, ItemFrame, LogicSensor] = extra + + def __repr__(self): + return f"" diff --git a/lihzahrd/world.py b/lihzahrd/world.py index 5733eaf..e14f2b8 100644 --- a/lihzahrd/world.py +++ b/lihzahrd/world.py @@ -6,7 +6,9 @@ from .header import * from .tiles import * from .chests import * from .signs import * -from .entities import * +from .npcs import * +from .tileentities import * +from .pressureplates import * from .timer import Timer @@ -48,10 +50,18 @@ class World: signs: typing.List[Sign], npcs: typing.List[NPC], mobs: typing.List[Mob], - unknown_file_format_data: bytearray, - unknown_world_header_data: bytearray, - unknown_world_tiles_data: bytearray, - unknown_chests_data: bytearray): + tile_entities: typing.List[TileEntity], + weighed_pressure_plates: typing.List[WeighedPressurePlate], + unknown_file_format_data: bytes = b"", + unknown_world_header_data: bytes = b"", + unknown_world_tiles_data: bytes = b"", + unknown_chests_data: bytes = b"", + unknown_signs_data: bytes = b"", + unknown_npcs_data: bytes = b"", + unknown_tile_entities_data: bytes = b"", + unknown_pressure_plates_data: bytes = b"", + unknown_town_manager_data: bytes = b"", + unknown_footer_data: bytes = b""): self.version: Version = version """The game version when this savefile was last saved.""" @@ -147,13 +157,26 @@ class World: """A list of all the NPCs currently living in the world, including the Old Man.""" self.mobs: typing.List[Mob] = mobs + """A list of mobs in the world...?""" + + self.tile_entities: typing.List[TileEntity] = tile_entities + """A list of tile entities in the world, such as Training Dummies, Item Frames and Logic Sensors.""" + + self.weighed_pressure_plates: typing.List[WeighedPressurePlate] = weighed_pressure_plates + """A list of all Weighed Pressure Plates in the world.""" self.clouds: Clouds = clouds self.cultist_delay: int = cultist_delay - self.unknown_file_format_data: bytearray = unknown_file_format_data - self.unknown_world_header_data: bytearray = unknown_world_header_data - self.unknown_world_tiles_data: bytearray = unknown_world_tiles_data - self.unknown_chests_data: bytearray = unknown_chests_data + self.unknown_file_format_data: bytes = unknown_file_format_data + self.unknown_world_header_data: bytes = unknown_world_header_data + self.unknown_world_tiles_data: bytes = unknown_world_tiles_data + self.unknown_chests_data: bytes = unknown_chests_data + self.unknown_signs_data: bytes = unknown_signs_data + self.unknown_npcs_data: bytes = unknown_npcs_data + self.unknown_tile_entities_data: bytes = unknown_tile_entities_data + self.unknown_pressure_plates_data: bytes = unknown_pressure_plates_data + self.unknown_town_manager_data: bytes = unknown_town_manager_data + self.unknown_footer_data: bytes = unknown_footer_data def __repr__(self): return f'' @@ -568,7 +591,41 @@ class World: position=npc_position) mobs.append(mob) - unknown_npcs_data = f.read_until(pointers) + unknown_npcs_data = f.read_until(pointers.tile_entities) + + with Timer("Tile Entities", display=True): + tile_entities_count = f.int4() + tile_entities = [] + + for _ in range(tile_entities_count): + te_type = f.uint1() + te_id = f.int4() + te_position = Coordinates(f.int2(), f.int2()) + if te_type == 0: + te_extra = TargetDummy(npc=f.int2()) + elif te_type == 1: + te_extra = ItemFrame(item=ItemStack(type_=ItemType(f.int2()), + modifier=f.uint1(), + quantity=f.int2())) + elif te_type == 2: + te_extra = LogicSensor(logic_check=f.uint1(), enabled=f.bool()) + tile_entity = TileEntity(id_=te_id, position=te_position, extra=te_extra) + tile_entities.append(tile_entity) + + unknown_tile_entities_data = f.read_until(pointers.pressure_plates) + + with Timer("Weighed Pressure Plates", display=True): + weighed_pressure_plates_count = f.int4() + weighed_pressure_plates = [] + + for _ in range(weighed_pressure_plates_count): + wpp = WeighedPressurePlate(position=Coordinates(f.int4(), f.int4())) + weighed_pressure_plates.append(wpp) + + unknown_pressure_plates_data = f.read_until(pointers.town_manager) + + # with Timer("Town Manager", display=True): + world = World(version=version, savefile_type=savefile_type, revision=revision, is_favorite=is_favorite, name=name, generator=generator, uuid_=uuid_, id_=id_, bounds=bounds, size=world_size, @@ -577,9 +634,16 @@ class World: time=time, events=events, dungeon_point=dungeon_point, world_evil=world_evil, saved_npcs=saved_npcs, altars_smashed=altars_smashed, is_hardmode=is_hardmode, shadow_orbs=shadow_orbs, bosses_defeated=bosses_defeated, anglers_quest=anglers_quest, - clouds=clouds, cultist_delay=cultist_delay, tiles=tiles, chests=chests, + clouds=clouds, cultist_delay=cultist_delay, tiles=tiles, chests=chests, npcs=npcs, mobs=mobs, + tile_entities=tile_entities, weighed_pressure_plates=weighed_pressure_plates, unknown_file_format_data=unknown_file_format_data, unknown_world_header_data=unknown_world_header_data, unknown_world_tiles_data=unknown_world_tiles_data, - unknown_chests_data=unknown_chests_data) + unknown_chests_data=unknown_chests_data, + unknown_signs_data=unknown_signs_data, + unknown_npcs_data=unknown_npcs_data, + unknown_tile_entities_data=unknown_tile_entities_data, + unknown_pressure_plates_data=unknown_pressure_plates_data, + unknown_town_manager_data=unknown_town_manager_data, + unknown_footer_data=unknown_footer_data) return world