From 740577f57890f7b078615b41b2c789570ff89170 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 10 Aug 2019 19:59:37 +0200 Subject: [PATCH] Correctly parse WorldTiles data --- lihzahrd/fileutils/__init__.py | 5 + .../{savedata => fileutils}/filereader.py | 23 +- lihzahrd/fileutils/pointers.py | 22 + lihzahrd/{savedata => fileutils}/rect.py | 0 lihzahrd/header/__init__.py | 2 - lihzahrd/header/anglerquestfish.py | 2 +- lihzahrd/header/backgrounds.py | 4 +- lihzahrd/header/hardmodeore.py | 6 +- lihzahrd/header/moonstyle.py | 2 +- lihzahrd/header/sandstorm.py | 3 +- lihzahrd/header/worldeviltype.py | 2 +- lihzahrd/savedata/__init__.py | 0 lihzahrd/tiles/__init__.py | 12 +- lihzahrd/tiles/block.py | 18 + lihzahrd/tiles/blocktype.py | 478 +++++++++++++++++ lihzahrd/tiles/frameimportantdata.py | 7 + lihzahrd/tiles/liquid.py | 21 +- lihzahrd/tiles/liquidtype.py | 21 + lihzahrd/tiles/tile.py | 27 +- lihzahrd/tiles/wall.py | 8 + lihzahrd/tiles/walltype.py | 237 +++++++++ lihzahrd/tiles/wires.py | 3 + lihzahrd/timer.py | 30 ++ lihzahrd/world.py | 487 ++++++++++-------- 24 files changed, 1151 insertions(+), 269 deletions(-) create mode 100644 lihzahrd/fileutils/__init__.py rename lihzahrd/{savedata => fileutils}/filereader.py (86%) create mode 100644 lihzahrd/fileutils/pointers.py rename lihzahrd/{savedata => fileutils}/rect.py (100%) delete mode 100644 lihzahrd/savedata/__init__.py create mode 100644 lihzahrd/tiles/block.py create mode 100644 lihzahrd/tiles/blocktype.py create mode 100644 lihzahrd/tiles/frameimportantdata.py create mode 100644 lihzahrd/tiles/liquidtype.py create mode 100644 lihzahrd/tiles/wall.py create mode 100644 lihzahrd/tiles/walltype.py create mode 100644 lihzahrd/timer.py diff --git a/lihzahrd/fileutils/__init__.py b/lihzahrd/fileutils/__init__.py new file mode 100644 index 0000000..c68a609 --- /dev/null +++ b/lihzahrd/fileutils/__init__.py @@ -0,0 +1,5 @@ +from .filereader import FileReader +from .rect import Rect +from .pointers import Pointers + +__all__ = ["FileReader", "Rect", "Pointers"] diff --git a/lihzahrd/savedata/filereader.py b/lihzahrd/fileutils/filereader.py similarity index 86% rename from lihzahrd/savedata/filereader.py rename to lihzahrd/fileutils/filereader.py index b5bdcca..37d3f9a 100644 --- a/lihzahrd/savedata/filereader.py +++ b/lihzahrd/fileutils/filereader.py @@ -44,14 +44,14 @@ class FileReader: def bits(self) -> typing.Tuple[bool, bool, bool, bool, bool, bool, bool, bool]: data = struct.unpack("B", self.file.read(1))[0] - return (bool(data & 0b1000_0000), - bool(data & 0b0100_0000), - bool(data & 0b0010_0000), - bool(data & 0b0001_0000), - bool(data & 0b0000_1000), - bool(data & 0b0000_0100), + return (bool(data & 0b0000_0001), bool(data & 0b0000_0010), - bool(data & 0b0000_0001)) + bool(data & 0b0000_0100), + bool(data & 0b0000_1000), + bool(data & 0b0001_0000), + bool(data & 0b0010_0000), + bool(data & 0b0100_0000), + bool(data & 0b1000_0000)) def rect(self) -> Rect: left, right, top, bottom = struct.unpack("iiii", self.file.read(16)) @@ -73,3 +73,12 @@ class FileReader: # https://docs.microsoft.com/it-it/dotnet/api/system.datetime.kind?view=netframework-4.8#System_DateTime_Kind datetime_bytes = self.file.read(8) return datetime_bytes + + def read_until(self, address: int) -> bytearray: + data = bytearray() + while self.file.tell() < address: + data += self.file.read(1) + return data + + def __repr__(self): + return f"" diff --git a/lihzahrd/fileutils/pointers.py b/lihzahrd/fileutils/pointers.py new file mode 100644 index 0000000..5633731 --- /dev/null +++ b/lihzahrd/fileutils/pointers.py @@ -0,0 +1,22 @@ +import typing + + +class Pointers: + def __init__(self, + world_header: int, + world_tiles: int, + chests: int, + signs: int, + npcs: int, + entities: int, + footer: int, + *unknown): + self.file_format: int = 0 + self.world_header: int = world_header + self.world_tiles: int = world_tiles + self.chests: int = chests + self.signs: int = signs + self.npcs: int = npcs + self.entities: int = entities + self.footer: int = footer + self.unknown: typing.List[int] = list(unknown) diff --git a/lihzahrd/savedata/rect.py b/lihzahrd/fileutils/rect.py similarity index 100% rename from lihzahrd/savedata/rect.py rename to lihzahrd/fileutils/rect.py diff --git a/lihzahrd/header/__init__.py b/lihzahrd/header/__init__.py index d1a5ce8..b04adbf 100644 --- a/lihzahrd/header/__init__.py +++ b/lihzahrd/header/__init__.py @@ -35,7 +35,6 @@ __all__ = [ "Clouds", "Coordinates", "Events", - "FileReader", "FourPartSplit", "GeneratorInfo", "HardmodeTier1Ore", @@ -50,7 +49,6 @@ __all__ = [ "Party", "PillarsInfo", "Rain", - "Rect", "Sandstorm", "SavedNPCs", "ShadowOrbs", diff --git a/lihzahrd/header/anglerquestfish.py b/lihzahrd/header/anglerquestfish.py index 24e3d22..ed30ae1 100644 --- a/lihzahrd/header/anglerquestfish.py +++ b/lihzahrd/header/anglerquestfish.py @@ -43,4 +43,4 @@ class AnglerQuestFish(enum.IntEnum): TROPICAL_BARRACUDA = 38 def __repr__(self): - return f"AnglerQuestFish('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/header/backgrounds.py b/lihzahrd/header/backgrounds.py index 94ff954..c116339 100644 --- a/lihzahrd/header/backgrounds.py +++ b/lihzahrd/header/backgrounds.py @@ -25,4 +25,6 @@ class Backgrounds: self.bg_ocean: int = bg_ocean def __repr__(self): - return f"WorldBackgrounds({self.bg_underground_snow}, {self.bg_underground_jungle}, {self.bg_hell}, {self.bg_forest}, {self.bg_corruption}, {self.bg_jungle}, {self.bg_snow}, {self.bg_hallow}, {self.bg_crimson}, {self.bg_desert}, {self.bg_ocean})" + return f"WorldBackgrounds({self.bg_underground_snow}, {self.bg_underground_jungle}, {self.bg_hell}," \ + f" {self.bg_forest}, {self.bg_corruption}, {self.bg_jungle}, {self.bg_snow}, {self.bg_hallow}," \ + f" {self.bg_crimson}, {self.bg_desert}, {self.bg_ocean})" diff --git a/lihzahrd/header/hardmodeore.py b/lihzahrd/header/hardmodeore.py index 8c3dfd1..ec0c68c 100644 --- a/lihzahrd/header/hardmodeore.py +++ b/lihzahrd/header/hardmodeore.py @@ -7,7 +7,7 @@ class HardmodeTier1Ore(enum.IntEnum): PALLADIUM = 221 def __repr__(self): - return f"HardmodeTier1Ore('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" class HardmodeTier2Ore(enum.IntEnum): @@ -16,7 +16,7 @@ class HardmodeTier2Ore(enum.IntEnum): ORICHALCUM = 222 def __repr__(self): - return f"HardmodeTier2Ore('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" class HardmodeTier3Ore(enum.IntEnum): @@ -26,4 +26,4 @@ class HardmodeTier3Ore(enum.IntEnum): TITANIUM = 223 def __repr__(self): - return f"HardmodeTier3Ore('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/header/moonstyle.py b/lihzahrd/header/moonstyle.py index 418a035..c6b4ecc 100644 --- a/lihzahrd/header/moonstyle.py +++ b/lihzahrd/header/moonstyle.py @@ -8,4 +8,4 @@ class MoonStyle(enum.IntEnum): RINGED_GREEN = 2 def __repr__(self): - return f"MoonStyle('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/header/sandstorm.py b/lihzahrd/header/sandstorm.py index a6e1e76..f43403b 100644 --- a/lihzahrd/header/sandstorm.py +++ b/lihzahrd/header/sandstorm.py @@ -15,4 +15,5 @@ class Sandstorm: self.intended_severity: float = intended_severity def __repr__(self): - return f"WorldSandstorm(is_active={self.is_active}, time_left={self.time_left}, severity={self.severity}, intended_severity={self.intended_severity})" + return f"WorldSandstorm(is_active={self.is_active}, time_left={self.time_left}," \ + f" severity={self.severity}, intended_severity={self.intended_severity})" diff --git a/lihzahrd/header/worldeviltype.py b/lihzahrd/header/worldeviltype.py index 418dca9..a7631a5 100644 --- a/lihzahrd/header/worldeviltype.py +++ b/lihzahrd/header/worldeviltype.py @@ -6,4 +6,4 @@ class WorldEvilType(enum.Enum): CRIMSON = True def __repr__(self): - return f"CorruptionType('{self.name}')" + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/savedata/__init__.py b/lihzahrd/savedata/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lihzahrd/tiles/__init__.py b/lihzahrd/tiles/__init__.py index 93d5bb1..3486288 100644 --- a/lihzahrd/tiles/__init__.py +++ b/lihzahrd/tiles/__init__.py @@ -1,6 +1,14 @@ -from .liquid import Liquid +from .liquidtype import LiquidType from .rleencoding import RLEEncoding from .shape import Shape from .wires import Wires +from .blocktype import BlockType +from .frameimportantdata import FrameImportantData +from .walltype import WallType +from .block import Block +from .wall import Wall +from .liquid import Liquid +from .tile import Tile -__all__ = ["Liquid", "RLEEncoding", "Shape", "Wires"] +__all__ = ["LiquidType", "RLEEncoding", "Shape", "Wires", "BlockType", "FrameImportantData", "WallType", "Block", + "Wall", "Liquid", "Tile"] diff --git a/lihzahrd/tiles/block.py b/lihzahrd/tiles/block.py new file mode 100644 index 0000000..a093235 --- /dev/null +++ b/lihzahrd/tiles/block.py @@ -0,0 +1,18 @@ +import typing +from .blocktype import BlockType +from .frameimportantdata import FrameImportantData + + +class Block: + def __init__(self, + type_: BlockType, + frame: typing.Optional[FrameImportantData], + paint: typing.Optional[int], + is_active: bool = True): + self.type: BlockType = type_ + self.frame: typing.Optional[FrameImportantData] = frame + self.paint: typing.Optional[int] = paint + self.is_active: bool = is_active + + def __repr__(self): + return f"Block(type_={repr(self.type)}, frame={self.frame}, paint={self.paint}, is_active={self.is_active})" diff --git a/lihzahrd/tiles/blocktype.py b/lihzahrd/tiles/blocktype.py new file mode 100644 index 0000000..6105518 --- /dev/null +++ b/lihzahrd/tiles/blocktype.py @@ -0,0 +1,478 @@ +import enum + + +class BlockType(enum.IntEnum): + DIRT = 0 + STONE = 1 + GRASS = 2 + PLANTS = 3 + TORCHES = 4 + TREES = 5 + IRON = 6 + COPPER = 7 + GOLD = 8 + SILVER = 9 + CLOSED_DOOR = 10 + OPEN_DOOR = 11 + HEART = 12 + BOTTLES = 13 + TABLES = 14 + CHAIRS = 15 + ANVILS = 16 + FURNACES = 17 + WORK_BENCHES = 18 + PLATFORMS = 19 + SAPLINGS = 20 + CONTAINERS = 21 + DEMONITE = 22 + CORRUPT_GRASS = 23 + CORRUPT_PLANTS = 24 + EBONSTONE = 25 + DEMON_ALTAR = 26 + SUNFLOWER = 27 + POTS = 28 + PIGGY_BANK = 29 + WOOD_BLOCK = 30 + SHADOW_ORBS = 31 + CORRUPT_THORNS = 32 + CANDLES = 33 + CHANDELIERS = 34 + JACKOLANTERNS = 35 + PRESENTS = 36 + METEORITE = 37 + GRAY_BRICK = 38 + RED_BRICK = 39 + CLAY_BLOCK = 40 + BLUE_DUNGEON_BRICK = 41 + HANGING_LANTERNS = 42 + GREEN_DUNGEON_BRICK = 43 + PINK_DUNGEON_BRICK = 44 + GOLD_BRICK = 45 + SILVER_BRICK = 46 + COPPER_BRICK = 47 + SPIKES = 48 + WATER_CANDLE = 49 + BOOKS = 50 + COBWEB = 51 + VINES = 52 + SAND = 53 + GLASS = 54 + SIGNS = 55 + OBSIDIAN = 56 + ASH = 57 + HELLSTONE = 58 + MUD = 59 + JUNGLE_GRASS = 60 + JUNGLE_PLANTS = 61 + JUNGLE_VINES = 62 + SAPPHIRE = 63 + RUBY = 64 + EMERALD = 65 + TOPAZ = 66 + AMETHYST = 67 + DIAMOND = 68 + JUNGLE_THORNS = 69 + MUSHROOM_GRASS = 70 + MUSHROOM_PLANTS = 71 + MUSHROOM_TREES = 72 + PLANTS2 = 73 + JUNGLE_PLANTS2 = 74 + OBSIDIAN_BRICK = 75 + HELLSTONE_BRICK = 76 + HELLFORGE = 77 + CLAY_POT = 78 + BEDS = 79 + CACTUS = 80 + CORAL = 81 + IMMATURE_HERBS = 82 + MATURE_HERBS = 83 + BLOOMING_HERBS = 84 + TOMBSTONES = 85 + LOOM = 86 + PIANOS = 87 + DRESSERS = 88 + BENCHES = 89 + BATHTUBS = 90 + BANNERS = 91 + LAMPPOSTS = 92 + LAMPS = 93 + KEGS = 94 + CHINESE_LANTERNS = 95 + COOKING_POTS = 96 + SAFES = 97 + SKULL_LANTERNS = 98 + TRASH_CAN = 99 + CANDELABRAS = 100 + BOOKCASES = 101 + THRONES = 102 + BOWLS = 103 + GRANDFATHER_CLOCKS = 104 + STATUES = 105 + SAWMILL = 106 + COBALT = 107 + MYTHRIL = 108 + HALLOWED_GRASS = 109 + HALLOWED_PLANTS = 110 + ADAMANTITE = 111 + EBONSAND = 112 + HALLOWED_PLANTS2 = 113 + TINKERERS_WORKBENCH = 114 + HALLOWED_VINES = 115 + PEARLSAND = 116 + PEARLSTONE = 117 + PEARLSTONE_BRICK = 118 + IRIDESCENT_BRICK = 119 + MUDSTONE = 120 + COBALT_BRICK = 121 + MYTHRIL_BRICK = 122 + SILT = 123 + WOODEN_BEAM = 124 + CRYSTAL_BALL = 125 + DISCO_BALL = 126 + MAGICAL_ICE_BLOCK = 127 + MANNEQUIN = 128 + CRYSTALS = 129 + ACTIVE_STONE_BLOCK = 130 + INACTIVE_STONE_BLOCK = 131 + LEVER = 132 + ADAMANTITE_FORGE = 133 + MYTHRIL_ANVIL = 134 + PRESSURE_PLATES = 135 + SWITCHES = 136 + TRAPS = 137 + BOULDER = 138 + MUSIC_BOXES = 139 + DEMONITE_BRICK = 140 + EXPLOSIVES = 141 + INLET_PUMP = 142 + OUTLET_PUMP = 143 + TIMERS = 144 + CANDY_CANE_BLOCK = 145 + GREEN_CANDY_CANE_BLOCK = 146 + SNOW_BLOCK = 147 + SNOW_BRICK = 148 + HOLIDAY_LIGHTS = 149 + ADAMANTITE_BEAM = 150 + SANDSTONE_BRICK = 151 + EBONSTONE_BRICK = 152 + RED_STUCCO = 153 + YELLOW_STUCCO = 154 + GREEN_STUCCO = 155 + GRAY_STUCCO = 156 + EBONWOOD = 157 + RICH_MAHOGANY = 158 + PEARLWOOD = 159 + RAINBOW_BRICK = 160 + ICE_BLOCK = 161 + BREAKABLE_ICE = 162 + CORRUPT_ICE = 163 + HALLOWED_ICE = 164 + STALACTITE = 165 + TIN = 166 + LEAD = 167 + TUNGSTEN = 168 + PLATINUM = 169 + PINE_TREE = 170 + CHRISTMAS_TREE = 171 + SINKS = 172 + PLATINUM_CANDELABRA = 173 + PLATINUM_CANDLE = 174 + TIN_BRICK = 175 + TUNGSTEN_BRICK = 176 + PLATINUM_BRICK = 177 + EXPOSED_GEMS = 178 + GREEN_MOSS = 179 + BROWN_MOSS = 180 + RED_MOSS = 181 + BLUE_MOSS = 182 + PURPLE_MOSS = 183 + LONG_MOSS = 184 + SMALL_PILES = 185 + LARGE_PILES = 186 + LARGE_PILES2 = 187 + CACTUS_BLOCK = 188 + CLOUD = 189 + MUSHROOM_BLOCK = 190 + LIVING_WOOD = 191 + LEAF_BLOCK = 192 + SLIME_BLOCK = 193 + BONE_BLOCK = 194 + FLESH_BLOCK = 195 + RAIN_CLOUD = 196 + FROZEN_SLIME_BLOCK = 197 + ASPHALT = 198 + FLESH_GRASS = 199 + FLESH_ICE = 200 + FLESH_WEEDS = 201 + SUNPLATE = 202 + CRIMSTONE = 203 + CRIMTANE = 204 + CRIMSON_VINES = 205 + ICE_BRICK = 206 + WATER_FOUNTAIN = 207 + SHADEWOOD = 208 + CANNON = 209 + LAND_MINE = 210 + CHLOROPHYTE = 211 + SNOWBALL_LAUNCHER = 212 + ROPE = 213 + CHAIN = 214 + CAMPFIRE = 215 + FIREWORK = 216 + BLENDOMATIC = 217 + MEAT_GRINDER = 218 + EXTRACTINATOR = 219 + SOLIDIFIER = 220 + PALLADIUM = 221 + ORICHALCUM = 222 + TITANIUM = 223 + SLUSH = 224 + HIVE = 225 + LIHZAHRD_BRICK = 226 + DYE_PLANTS = 227 + DYE_VAT = 228 + HONEY_BLOCK = 229 + CRISPY_HONEY_BLOCK = 230 + LARVA = 231 + WOODEN_SPIKES = 232 + PLANT_DETRITUS = 233 + CRIMSAND = 234 + TELEPORTER = 235 + LIFE_FRUIT = 236 + LIHZAHRD_ALTAR = 237 + PLANTERA_BULB = 238 + METAL_BARS = 239 + PAINTING3X3 = 240 + PAINTING4X3 = 241 + PAINTING6X4 = 242 + IMBUING_STATION = 243 + BUBBLE_MACHINE = 244 + PAINTING2X3 = 245 + PAINTING3X2 = 246 + AUTOHAMMER = 247 + PALLADIUM_COLUMN = 248 + BUBBLEGUM_BLOCK = 249 + TITANSTONE = 250 + PUMPKIN_BLOCK = 251 + HAY_BLOCK = 252 + SPOOKY_WOOD = 253 + PUMPKINS = 254 + AMETHYST_GEMSPARK_OFF = 255 + TOPAZ_GEMSPARK_OFF = 256 + SAPPHIRE_GEMSPARK_OFF = 257 + EMERALD_GEMSPARK_OFF = 258 + RUBY_GEMSPARK_OFF = 259 + DIAMOND_GEMSPARK_OFF = 260 + AMBER_GEMSPARK_OFF = 261 + AMETHYST_GEMSPARK = 262 + TOPAZ_GEMSPARK = 263 + SAPPHIRE_GEMSPARK = 264 + EMERALD_GEMSPARK = 265 + RUBY_GEMSPARK = 266 + DIAMOND_GEMSPARK = 267 + AMBER_GEMSPARK = 268 + WOMANNEQUIN = 269 + FIREFLYINA_BOTTLE = 270 + LIGHTNING_BUGINA_BOTTLE = 271 + COG = 272 + STONE_SLAB = 273 + SAND_STONE_SLAB = 274 + BUNNY_CAGE = 275 + SQUIRREL_CAGE = 276 + MALLARD_DUCK_CAGE = 277 + DUCK_CAGE = 278 + BIRD_CAGE = 279 + BLUE_JAY = 280 + CARDINAL_CAGE = 281 + FISH_BOWL = 282 + HEAVY_WORK_BENCH = 283 + COPPER_PLATING = 284 + SNAIL_CAGE = 285 + GLOWING_SNAIL_CAGE = 286 + AMMO_BOX = 287 + MONARCH_BUTTERFLY_JAR = 288 + PURPLE_EMPEROR_BUTTERFLY_JAR = 289 + RED_ADMIRAL_BUTTERFLY_JAR = 290 + ULYSSES_BUTTERFLY_JAR = 291 + SULPHUR_BUTTERFLY_JAR = 292 + TREE_NYMPH_BUTTERFLY_JAR = 293 + ZEBRA_SWALLOWTAIL_BUTTERFLY_JAR = 294 + JULIA_BUTTERFLY_JAR = 295 + SCORPION_CAGE = 296 + BLACK_SCORPION_CAGE = 297 + FROG_CAGE = 298 + MOUSE_CAGE = 299 + BONE_WELDER = 300 + FLESH_CLONING_VAT = 301 + GLASS_KILN = 302 + LIHZAHRD_FURNACE = 303 + LIVING_LOOM = 304 + SKY_MILL = 305 + ICE_MACHINE = 306 + STEAMPUNK_BOILER = 307 + HONEY_DISPENSER = 308 + PENGUIN_CAGE = 309 + WORM_CAGE = 310 + DYNASTY_WOOD = 311 + RED_DYNASTY_SHINGLES = 312 + BLUE_DYNASTY_SHINGLES = 313 + MINECART_TRACK = 314 + CORALSTONE = 315 + BLUE_JELLYFISH_BOWL = 316 + GREEN_JELLYFISH_BOWL = 317 + PINK_JELLYFISH_BOWL = 318 + SHIP_IN_ABOTTLE = 319 + SEAWEED_PLANTER = 320 + BOREAL_WOOD = 321 + PALM_WOOD = 322 + PALM_TREE = 323 + BEACH_PILES = 324 + TIN_PLATING = 325 + WATERFALL = 326 + LAVAFALL = 327 + CONFETTI = 328 + CONFETTI_BLACK = 329 + COPPER_COIN_PILE = 330 + SILVER_COIN_PILE = 331 + GOLD_COIN_PILE = 332 + PLATINUM_COIN_PILE = 333 + WEAPONS_RACK = 334 + FIREWORKS_BOX = 335 + LIVING_FIRE = 336 + ALPHABET_STATUES = 337 + FIREWORK_FOUNTAIN = 338 + GRASSHOPPER_CAGE = 339 + LIVING_CURSED_FIRE = 340 + LIVING_DEMON_FIRE = 341 + LIVING_FROST_FIRE = 342 + LIVING_ICHOR = 343 + LIVING_ULTRABRIGHT_FIRE = 344 + HONEYFALL = 345 + CHLOROPHYTE_BRICK = 346 + CRIMTANE_BRICK = 347 + SHROOMITE_PLATING = 348 + MUSHROOM_STATUE = 349 + MARTIAN_CONDUIT_PLATING = 350 + CHIMNEY_SMOKE = 351 + CRIMTANE_THORNS = 352 + VINE_ROPE = 353 + BEWITCHING_TABLE = 354 + ALCHEMY_TABLE = 355 + SUNDIAL = 356 + MARBLE_BLOCK = 357 + GOLD_BIRD_CAGE = 358 + GOLD_BUNNY_CAGE = 359 + GOLD_BUTTERFLY_CAGE = 360 + GOLD_FROG_CAGE = 361 + GOLD_GRASSHOPPER_CAGE = 362 + GOLD_MOUSE_CAGE = 363 + GOLD_WORM_CAGE = 364 + SILK_ROPE = 365 + WEB_ROPE = 366 + MARBLE = 367 + GRANITE = 368 + GRANITE_BLOCK = 369 + METEORITE_BRICK = 370 + PINK_SLIME_BLOCK = 371 + PEACE_CANDLE = 372 + WATER_DRIP = 373 + LAVA_DRIP = 374 + HONEY_DRIP = 375 + FISHING_CRATE = 376 + SHARPENING_STATION = 377 + TARGET_DUMMY = 378 + BUBBLE = 379 + PLANTER_BOX = 380 + LAVA_MOSS = 381 + VINE_FLOWERS = 382 + LIVING_MAHOGANY = 383 + LIVING_MAHOGANY_LEAVES = 384 + CRYSTAL_BLOCK = 385 + TRAPDOOR_OPEN = 386 + TRAPDOOR_CLOSED = 387 + TALL_GATE_CLOSED = 388 + TALL_GATE_OPEN = 389 + LAVA_LAMP = 390 + CAGE_ENCHANTED_NIGHTCRAWLER = 391 + CAGE_BUGGY = 392 + CAGE_GRUBBY = 393 + CAGE_SLUGGY = 394 + ITEM_FRAME = 395 + SANDSTONE = 396 + HARDENED_SAND = 397 + CORRUPT_HARDENED_SAND = 398 + CRIMSON_HARDENED_SAND = 399 + CORRUPT_SANDSTONE = 400 + CRIMSON_SANDSTONE = 401 + HALLOW_HARDENED_SAND = 402 + HALLOW_SANDSTONE = 403 + DESERT_FOSSIL = 404 + FIREPLACE = 405 + CHIMNEY = 406 + FOSSIL_ORE = 407 + LUNAR_ORE = 408 + LUNAR_BRICK = 409 + LUNAR_MONOLITH = 410 + DETONATOR = 411 + LUNAR_CRAFTING_STATION = 412 + SQUIRREL_ORANGE_CAGE = 413 + SQUIRREL_GOLD_CAGE = 414 + LUNAR_BLOCK_SOLAR = 415 + LUNAR_BLOCK_VORTEX = 416 + LUNAR_BLOCK_NEBULA = 417 + LUNAR_BLOCK_STARDUST = 418 + LOGIC_GATE_LAMP = 419 + LOGIC_GATE = 420 + CONVEYOR_BELT_LEFT = 421 + CONVEYOR_BELT_RIGHT = 422 + LOGIC_SENSOR = 423 + WIRE_PIPE = 424 + ANNOUNCEMENT_BOX = 425 + TEAM_BLOCK_RED = 426 + TEAM_BLOCK_RED_PLATFORM = 427 + WEIGHTED_PRESSURE_PLATE = 428 + WIRE_BULB = 429 + TEAM_BLOCK_GREEN = 430 + TEAM_BLOCK_BLUE = 431 + TEAM_BLOCK_YELLOW = 432 + TEAM_BLOCK_PINK = 433 + TEAM_BLOCK_WHITE = 434 + TEAM_BLOCK_GREEN_PLATFORM = 435 + TEAM_BLOCK_BLUE_PLATFORM = 436 + TEAM_BLOCK_YELLOW_PLATFORM = 437 + TEAM_BLOCK_PINK_PLATFORM = 438 + TEAM_BLOCK_WHITE_PLATFORM = 439 + GEM_LOCKS = 440 + FAKE_CONTAINERS = 441 + PROJECTILE_PRESSURE_PAD = 442 + GEYSER_TRAP = 443 + BEE_HIVE = 444 + PIXEL_BOX = 445 + SILLY_BALLOON_PINK = 446 + SILLY_BALLOON_PURPLE = 447 + SILLY_BALLOON_GREEN = 448 + SILLY_STREAMER_BLUE = 449 + SILLY_STREAMER_GREEN = 450 + SILLY_STREAMER_PINK = 451 + SILLY_BALLOON_MACHINE = 452 + SILLY_BALLOON_TILE = 453 + PIGRONATA = 454 + PARTY_MONOLITH = 455 + PARTY_BUNDLE_OF_BALLOON_TILE = 456 + PARTY_PRESENT = 457 + SAND_FALL_BLOCK = 458 + SNOW_FALL_BLOCK = 459 + SNOW_CLOUD = 460 + SAND_DRIP = 461 + DJINN_LAMP = 462 + DEFENDERS_FORGE = 463 + WAR_TABLE = 464 + WAR_TABLE_BANNER = 465 + ELDER_CRYSTAL_STAND = 466 + CONTAINERS2 = 467 + FAKE_CONTAINERS2 = 468 + TABLES2 = 469 + COUNT = 470 + + def __repr__(self): + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/tiles/frameimportantdata.py b/lihzahrd/tiles/frameimportantdata.py new file mode 100644 index 0000000..c9d63c5 --- /dev/null +++ b/lihzahrd/tiles/frameimportantdata.py @@ -0,0 +1,7 @@ +class FrameImportantData: + def __init__(self, frame_x, frame_y): + self.frame_x: int = frame_x + self.frame_y: int = frame_y + + def __repr__(self): + return f"FrameImportantData(frame_x={self.frame_x}, frame_y={self.frame_y})" diff --git a/lihzahrd/tiles/liquid.py b/lihzahrd/tiles/liquid.py index fb7da48..9ff9e9c 100644 --- a/lihzahrd/tiles/liquid.py +++ b/lihzahrd/tiles/liquid.py @@ -1,18 +1,7 @@ -import enum +from .liquidtype import LiquidType -class Liquid(enum.IntEnum): - NO_LIQUID = 0 - WATER = 1 - LAVA = 2 - HONEY = 3 - - @classmethod - def from_flags(cls, flags1): - if flags1[3] and flags1[4]: - return cls.HONEY - if flags1[4]: - return cls.LAVA - if flags1[3]: - return cls.WATER - return cls.NO_LIQUID +class Liquid: + def __init__(self, type_: LiquidType, volume: int): + self.type: LiquidType = type_ + self.volume: int = volume diff --git a/lihzahrd/tiles/liquidtype.py b/lihzahrd/tiles/liquidtype.py new file mode 100644 index 0000000..acf8a2f --- /dev/null +++ b/lihzahrd/tiles/liquidtype.py @@ -0,0 +1,21 @@ +import enum + + +class LiquidType(enum.IntEnum): + NO_LIQUID = 0 + WATER = 1 + LAVA = 2 + HONEY = 3 + + @classmethod + def from_flags(cls, flags1): + if flags1[3] and flags1[4]: + return cls.HONEY + if flags1[4]: + return cls.LAVA + if flags1[3]: + return cls.WATER + return cls.NO_LIQUID + + def __repr__(self): + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/tiles/tile.py b/lihzahrd/tiles/tile.py index c18585e..7eb43d5 100644 --- a/lihzahrd/tiles/tile.py +++ b/lihzahrd/tiles/tile.py @@ -1,18 +1,15 @@ -import enum +import typing +from .block import Block +from .wall import Wall +from .liquid import Liquid -class Liquid(enum.IntEnum): - NO_LIQUID = 0 - WATER = 1 - LAVA = 2 - HONEY = 3 +class Tile: - @classmethod - def from_flags(cls, flags13, flags14): - if flags13 and flags14: - return cls.HONEY - if flags14: - return cls.LAVA - if flags13: - return cls.WATER - return cls.NO_LIQUID + def __init__(self, block: typing.Optional[Block], wall: typing.Optional[Wall], liquid: typing.Optional[Liquid]): + self.block: typing.Optional[Block] = block + self.wall: typing.Optional[Wall] = wall + self.liquid: typing.Optional[Liquid] = liquid + + def __repr__(self): + return f"" diff --git a/lihzahrd/tiles/wall.py b/lihzahrd/tiles/wall.py new file mode 100644 index 0000000..19d0e55 --- /dev/null +++ b/lihzahrd/tiles/wall.py @@ -0,0 +1,8 @@ +import typing +from .walltype import WallType + + +class Wall: + def __init__(self, type_: WallType, paint: typing.Optional[int]): + self.type: WallType = type_ + self.paint: typing.Optional[int] = paint diff --git a/lihzahrd/tiles/walltype.py b/lihzahrd/tiles/walltype.py new file mode 100644 index 0000000..e720c1b --- /dev/null +++ b/lihzahrd/tiles/walltype.py @@ -0,0 +1,237 @@ +import enum + + +class WallType(enum.IntEnum): + STONE = 1 + DIRT_UNSAFE = 2 + EBONSTONE_UNSAFE = 3 + WOOD = 4 + GRAY_BRICK = 5 + RED_BRICK = 6 + BLUE_DUNGEON_UNSAFE = 7 + GREEN_DUNGEON_UNSAFE = 8 + PINK_DUNGEON_UNSAFE = 9 + GOLD_BRICK = 10 + SILVER_BRICK = 11 + COPPER_BRICK = 12 + HELLSTONE_BRICK_UNSAFE = 13 + OBSIDIAN_BRICK_UNSAFE = 14 + MUD_UNSAFE = 15 + DIRT = 16 + BLUE_DUNGEON = 17 + GREEN_DUNGEON = 18 + PINK_DUNGEON = 19 + OBSIDIAN_BRICK = 20 + GLASS = 21 + PEARLSTONE_BRICK = 22 + IRIDESCENT_BRICK = 23 + MUDSTONE_BRICK = 24 + COBALT_BRICK = 25 + MYTHRIL_BRICK = 26 + PLANKED = 27 + PEARLSTONE_BRICK_UNSAFE = 28 + CANDY_CANE = 29 + GREEN_CANDY_CANE = 30 + SNOW_BRICK = 31 + ADAMANTITE_BEAM = 32 + DEMONITE_BRICK = 33 + SANDSTONE_BRICK = 34 + EBONSTONE_BRICK = 35 + RED_STUCCO = 36 + YELLOW_STUCCO = 37 + GREEN_STUCCO = 38 + GRAY = 39 + SNOW_WALL_UNSAFE = 40 + EBONWOOD = 41 + RICH_MAOGANY = 42 + PEARLWOOD = 43 + RAINBOW_BRICK = 44 + TIN_BRICK = 45 + TUNGSTEN_BRICK = 46 + PLATINUM_BRICK = 47 + AMETHYST_UNSAFE = 48 + TOPAZ_UNSAFE = 49 + SAPPHIRE_UNSAFE = 50 + EMERALD_UNSAFE = 51 + RUBY_UNSAFE = 52 + DIAMOND_UNSAFE = 53 + CAVE_UNSAFE = 54 + CAVE2UNSAFE = 55 + CAVE3UNSAFE = 56 + CAVE4UNSAFE = 57 + CAVE5UNSAFE = 58 + CAVE6UNSAFE = 59 + LIVING_LEAF = 60 + CAVE7UNSAFE = 61 + SPIDER_UNSAFE = 62 + GRASS_UNSAFE = 63 + JUNGLE_UNSAFE = 64 + FLOWER_UNSAFE = 65 + GRASS = 66 + JUNGLE = 67 + FLOWER = 68 + CORRUPT_GRASS_UNSAFE = 69 + HALLOWED_GRASS_UNSAFE = 70 + ICE_UNSAFE = 71 + CACTUS = 72 + CLOUD = 73 + MUSHROOM = 74 + BONE = 75 + SLIME = 76 + FLESH = 77 + LIVING_WOOD = 78 + OBSIDIAN_BACK_UNSAFE = 79 + MUSHROOM_UNSAFE = 80 + CRIMSON_GRASS_UNSAFE = 81 + DISC_WALL = 82 + CRIMSTONE_UNSAFE = 83 + ICE_BRICK = 84 + SHADEWOOD = 85 + HIVE_UNSAFE = 86 + LIHZAHRD_BRICK_UNSAFE = 87 + PURPLE_STAINED_GLASS = 88 + YELLOW_STAINED_GLASS = 89 + BLUE_STAINED_GLASS = 90 + GREEN_STAINED_GLASS = 91 + RED_STAINED_GLASS = 92 + RAINBOW_STAINED_GLASS = 93 + BLUE_DUNGEON_SLAB_UNSAFE = 94 + BLUE_DUNGEON_TILE_UNSAFE = 95 + PINK_DUNGEON_SLAB_UNSAFE = 96 + PINK_DUNGEON_TILE_UNSAFE = 97 + GREEN_DUNGEON_SLAB_UNSAFE = 98 + GREEN_DUNGEON_TILE_UNSAFE = 99 + BLUE_DUNGEON_SLAB = 100 + BLUE_DUNGEON_TILE = 101 + PINK_DUNGEON_SLAB = 102 + PINK_DUNGEON_TILE = 103 + GREEN_DUNGEON_SLAB = 104 + GREEN_DUNGEON_TILE = 105 + WOODEN_FENCE = 106 + METAL_FENCE = 107 + HIVE = 108 + PALLADIUM_COLUMN = 109 + BUBBLEGUM_BLOCK = 110 + TITANSTONE_BLOCK = 111 + LIHZAHRD_BRICK = 112 + PUMPKIN = 113 + HAY = 114 + SPOOKY_WOOD = 115 + CHRISTMAS_TREE_WALLPAPER = 116 + ORNAMENT_WALLPAPER = 117 + CANDY_CANE_WALLPAPER = 118 + FESTIVE_WALLPAPER = 119 + STARS_WALLPAPER = 120 + SQUIGGLES_WALLPAPER = 121 + SNOWFLAKE_WALLPAPER = 122 + KRAMPUS_HORN_WALLPAPER = 123 + BLUEGREEN_WALLPAPER = 124 + GRINCH_FINGER_WALLPAPER = 125 + FANCY_GRAY_WALLPAPER = 126 + ICE_FLOE_WALLPAPER = 127 + MUSIC_WALLPAPER = 128 + PURPLE_RAIN_WALLPAPER = 129 + RAINBOW_WALLPAPER = 130 + SPARKLE_STONE_WALLPAPER = 131 + STARLIT_HEAVEN_WALLPAPER = 132 + BUBBLE_WALLPAPER = 133 + COPPER_PIPE_WALLPAPER = 134 + DUCKY_WALLPAPER = 135 + WATERFALL = 136 + LAVAFALL = 137 + EBONWOOD_FENCE = 138 + RICH_MAHOGANY_FENCE = 139 + PEARLWOOD_FENCE = 140 + SHADEWOOD_FENCE = 141 + WHITE_DYNASTY = 142 + BLUE_DYNASTY = 143 + ARCANE_RUNES = 144 + IRON_FENCE = 145 + COPPER_PLATING = 146 + STONE_SLAB = 147 + SAIL = 148 + BOREAL_WOOD = 149 + BOREAL_WOOD_FENCE = 150 + PALM_WOOD = 151 + PALM_WOOD_FENCE = 152 + AMBER_GEMSPARK = 153 + AMETHYST_GEMSPARK = 154 + DIAMOND_GEMSPARK = 155 + EMERALD_GEMSPARK = 156 + AMBER_GEMSPARK_OFF = 157 + AMETHYST_GEMSPARK_OFF = 158 + DIAMOND_GEMSPARK_OFF = 159 + EMERALD_GEMSPARK_OFF = 160 + RUBY_GEMSPARK_OFF = 161 + SAPPHIRE_GEMSPARK_OFF = 162 + TOPAZ_GEMSPARK_OFF = 163 + RUBY_GEMSPARK = 164 + SAPPHIRE_GEMSPARK = 165 + TOPAZ_GEMSPARK = 166 + TIN_PLATING = 167 + CONFETTI = 168 + CONFETTI_BLACK = 169 + CAVE_WALL = 170 + CAVE_WALL2 = 171 + HONEYFALL = 172 + CHLOROPHYTE_BRICK = 173 + CRIMTANE_BRICK = 174 + SHROOMITE_PLATING = 175 + MARTIAN_CONDUIT = 176 + HELLSTONE_BRICK = 177 + MARBLE_UNSAFE = 178 + MARBLE_BLOCK = 179 + GRANITE_UNSAFE = 180 + GRANITE_BLOCK = 181 + METEORITE_BRICK = 182 + MARBLE = 183 + GRANITE = 184 + CAVE8UNSAFE = 185 + CRYSTAL = 186 + SANDSTONE = 187 + CORRUPTION_UNSAFE1 = 188 + CORRUPTION_UNSAFE2 = 189 + CORRUPTION_UNSAFE3 = 190 + CORRUPTION_UNSAFE4 = 191 + CRIMSON_UNSAFE1 = 192 + CRIMSON_UNSAFE2 = 193 + CRIMSON_UNSAFE3 = 194 + CRIMSON_UNSAFE4 = 195 + DIRT_UNSAFE1 = 196 + DIRT_UNSAFE2 = 197 + DIRT_UNSAFE3 = 198 + DIRT_UNSAFE4 = 199 + HALLOW_UNSAFE1 = 200 + HALLOW_UNSAFE2 = 201 + HALLOW_UNSAFE3 = 202 + HALLOW_UNSAFE4 = 203 + JUNGLE_UNSAFE1 = 204 + JUNGLE_UNSAFE2 = 205 + JUNGLE_UNSAFE3 = 206 + JUNGLE_UNSAFE4 = 207 + LAVA_UNSAFE1 = 208 + LAVA_UNSAFE2 = 209 + LAVA_UNSAFE3 = 210 + LAVA_UNSAFE4 = 211 + ROCKS_UNSAFE1 = 212 + ROCKS_UNSAFE2 = 213 + ROCKS_UNSAFE3 = 214 + ROCKS_UNSAFE4 = 215 + HARDENED_SAND = 216 + CORRUPT_HARDENED_SAND = 217 + CRIMSON_HARDENED_SAND = 218 + HALLOW_HARDENED_SAND = 219 + CORRUPT_SANDSTONE = 220 + CRIMSON_SANDSTONE = 221 + HALLOW_SANDSTONE = 222 + DESERT_FOSSIL = 223 + LUNAR_BRICK_WALL = 224 + COG_WALL = 225 + SAND_FALL = 226 + SNOW_FALL = 227 + SILLY_BALLOON_PINK_WALL = 228 + SILLY_BALLOON_PURPLE_WALL = 229 + SILLY_BALLOON_GREEN_WALL = 230 + + def __repr__(self): + return f"{self.__class__.__name__}.{self.name}" diff --git a/lihzahrd/tiles/wires.py b/lihzahrd/tiles/wires.py index ce12924..7586c5c 100644 --- a/lihzahrd/tiles/wires.py +++ b/lihzahrd/tiles/wires.py @@ -10,3 +10,6 @@ class Wires: self.blue: bool = blue self.yellow: bool = yellow self.actuator: bool = actuator + + def __repr__(self): + return f"Wires(red={self.red}, green={self.green}, blue={self.blue}, yellow={self.yellow}, actuator={self.actuator})" \ No newline at end of file diff --git a/lihzahrd/timer.py b/lihzahrd/timer.py new file mode 100644 index 0000000..42843e8 --- /dev/null +++ b/lihzahrd/timer.py @@ -0,0 +1,30 @@ +import time +import typing + + +class Timer: + def __init__(self, name: str, display: bool = False): + self.name: str = name + self.display: bool = display + self._start_time: typing.Optional[float] = None + self._stop_time: typing.Optional[float] = None + + @property + def _result(self) -> float: + return self._stop_time - self._start_time + + def start(self): + self._start_time = time.time() + if self.display: + print(f"Timer {self.name} started.") + + def stop(self): + self._stop_time = time.time() + if self.display: + print(f"Timer {self.name} stopped: {self._result} seconds elapsed.") + + def __enter__(self): + self.start() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() diff --git a/lihzahrd/world.py b/lihzahrd/world.py index 1ea6fe0..f90f085 100644 --- a/lihzahrd/world.py +++ b/lihzahrd/world.py @@ -1,8 +1,10 @@ import uuid import math +import typing from .header import * -from .savedata import filereader +from .fileutils import * from .tiles import * +from .timer import Timer class World: @@ -135,12 +137,13 @@ class World: self.shadow_orbs = value @staticmethod - def _read_tiles(fr: FileReader, tileframeimportant): + def _read_tiles(fr: FileReader, tileframeimportant) -> typing.List: + # Once again, this code is a mess flags1 = fr.bits() - has_tile = flags1[1] + has_block = flags1[1] has_wall = flags1[2] - liquid = Liquid.from_flags(flags1) - extended_block_id = flags1[5] + liquid_type = LiquidType.from_flags(flags1) + has_extended_block_id = flags1[5] rle_compression = RLEEncoding.from_flags(flags1) if flags1[0]: flags2 = fr.bits() @@ -149,278 +152,325 @@ class World: flags3 = fr.bits() is_active = not flags3[2] wires = Wires(red=flags2[1], green=flags2[2], blue=flags2[3], yellow=flags3[5], actuator=flags3[1]) - is_tile_painted = flags3[3] + is_block_painted = flags3[3] is_wall_painted = flags3[4] else: is_active = True wires = Wires(red=flags2[1], green=flags2[2], blue=flags2[3]) - is_tile_painted = False + is_block_painted = False is_wall_painted = False else: shape = Shape.NORMAL is_active = True wires = Wires() - is_tile_painted = False + is_block_painted = False is_wall_painted = False - if has_tile: - if extended_block_id: - block_id = fr.uint2() + if has_block: + if has_extended_block_id: + block_id = BlockType(fr.uint2()) else: - block_id = fr.uint1() + block_id = BlockType(fr.uint1()) + if tileframeimportant[block_id]: + frame_x = fr.uint2() + frame_y = fr.uint2() + else: + frame_x = None + frame_y = None + if is_block_painted: + block_paint = fr.uint1() + else: + block_paint = None + block = Block(type_=block_id, frame=FrameImportantData(frame_x, frame_y), paint=block_paint) else: - block_id = None - if tileframeimportant: - ... - breakpoint() + block = None + if has_wall: + wall_id = WallType(fr.uint1()) + if is_wall_painted: + wall_paint = fr.uint1() + else: + wall_paint = None + wall = Wall(type_=wall_id, paint=wall_paint) + else: + wall = None + if liquid_type != LiquidType.NO_LIQUID: + liquid = Liquid(type_=liquid_type, volume=fr.uint1()) + else: + liquid = None + if rle_compression == RLEEncoding.DOUBLE_BYTE: + multiply_by = fr.uint2() + 1 + elif rle_compression == RLEEncoding.SINGLE_BYTE: + multiply_by = fr.uint1() + 1 + else: + multiply_by = 1 + tile = Tile(block=block, wall=wall, liquid=liquid) + return [tile] * multiply_by @classmethod def create_from_file(cls, file): """Create a World object from a .wld file.""" # This code is a mess. - f = filereader.FileReader(file) + f = FileReader(file) - version = Version(f.int4()) - relogic = f.string(7) - savefile_type = f.uint1() - if version != Version("1.3.5.3") or relogic != "relogic" or savefile_type != 2: - raise NotImplementedError("This parser can only read Terraria 1.3.5.3 save files.") + with Timer("File Format", display=True): + version = Version(f.int4()) + relogic = f.string(7) + savefile_type = f.uint1() + if version != Version("1.3.5.3") or relogic != "relogic" or savefile_type != 2: + raise NotImplementedError("This parser can only read Terraria 1.3.5.3 save files.") - revision = f.uint4() - is_favorite = f.uint8() != 0 + revision = f.uint4() + is_favorite = f.uint8() != 0 - # Pointers and tileframeimportant - _ = [f.int4() for _ in range(f.int2())] - tileframeimportant_size = math.ceil(f.int2() / 8) - tileframeimportant = [] - for _ in range(tileframeimportant_size): - current_bit = f.bits() - tileframeimportant = [*tileframeimportant, *current_bit] + # Pointers and tileframeimportant + pointers = Pointers(*[f.int4() for _ in range(f.int2())]) + tileframeimportant_size = math.ceil(f.int2() / 8) + tileframeimportant = [] + for _ in range(tileframeimportant_size): + current_bit = f.bits() + tileframeimportant = [*tileframeimportant, *current_bit] - name = f.string() + unknown_file_format_data = f.read_until(pointers.world_header) - generator = GeneratorInfo(f.string(), f.int4()) + with Timer("World Header", display=True): + name = f.string() - uuid_ = f.uuid() - id_ = f.int8() - bounds = f.rect() - world_size = Coordinates(y=f.int4(), x=f.int4()) - is_expert = f.bool() - created_on = f.datetime() + generator = GeneratorInfo(f.string(), f.int4()) - world_styles = Styles(moon=MoonStyle(f.uint1()), - trees=FourPartSplit(separators=[f.int4(), f.int4(), f.int4()], - properties=[f.int4(), - f.int4(), - f.int4(), - f.int4()]), - moss=FourPartSplit(separators=[f.int4(), f.int4(), f.int4()], - properties=[f.int4(), - f.int4(), - f.int4(), - f.int4()])) + uuid_ = f.uuid() + id_ = f.int8() + bounds = f.rect() + world_size = Coordinates(y=f.int4(), x=f.int4()) + is_expert = f.bool() + created_on = f.datetime() - bg_underground_snow = f.int4() - bg_underground_jungle = f.int4() - bg_hell = f.int4() + world_styles = Styles(moon=MoonStyle(f.uint1()), + trees=FourPartSplit(separators=[f.int4(), f.int4(), f.int4()], + properties=[f.int4(), + f.int4(), + f.int4(), + f.int4()]), + moss=FourPartSplit(separators=[f.int4(), f.int4(), f.int4()], + properties=[f.int4(), + f.int4(), + f.int4(), + f.int4()])) - spawn_point = Coordinates(f.int4(), f.int4()) - underground_level = f.double() - cavern_level = f.double() + bg_underground_snow = f.int4() + bg_underground_jungle = f.int4() + bg_hell = f.int4() - current_time = f.double() - is_daytime = f.bool() - moon_phase = MoonPhase(f.uint4()) + spawn_point = Coordinates(f.int4(), f.int4()) + underground_level = f.double() + cavern_level = f.double() - blood_moon = f.bool() - eclipse = f.bool() + current_time = f.double() + is_daytime = f.bool() + moon_phase = MoonPhase(f.uint4()) - dungeon_point = Coordinates(f.int4(), f.int4()) - world_evil = WorldEvilType(f.bool()) + blood_moon = f.bool() + eclipse = f.bool() - defeated_eye_of_cthulhu = f.bool() # Possibly. I'm not sure. - defeated_eater_of_worlds = f.bool() # Possibly. I'm not sure. - defeated_skeletron = f.bool() # Possibly. I'm not sure. - defeated_queen_bee = f.bool() - defeated_the_twins = f.bool() - defeated_the_destroyer = f.bool() - defeated_skeletron_prime = f.bool() - defeated_any_mechnical_boss = f.bool() - defeated_plantera = f.bool() - defeated_golem = f.bool() - defeated_king_slime = f.bool() + dungeon_point = Coordinates(f.int4(), f.int4()) + world_evil = WorldEvilType(f.bool()) - saved_goblin_tinkerer = f.bool() - saved_wizard = f.bool() - saved_mechanic = f.bool() + defeated_eye_of_cthulhu = f.bool() # Possibly. I'm not sure. + defeated_eater_of_worlds = f.bool() # Possibly. I'm not sure. + defeated_skeletron = f.bool() # Possibly. I'm not sure. + defeated_queen_bee = f.bool() + defeated_the_twins = f.bool() + defeated_the_destroyer = f.bool() + defeated_skeletron_prime = f.bool() + defeated_any_mechnical_boss = f.bool() + defeated_plantera = f.bool() + defeated_golem = f.bool() + defeated_king_slime = f.bool() - defeated_goblin_army = f.bool() - defeated_clown = f.bool() - defeated_frost_moon = f.bool() - defeated_pirates = f.bool() + saved_goblin_tinkerer = f.bool() + saved_wizard = f.bool() + saved_mechanic = f.bool() - shadow_orbs = ShadowOrbs(smashed_at_least_once=f.bool(), - spawn_meteorite=f.bool(), - evil_boss_counter=f.int4()) + defeated_goblin_army = f.bool() + defeated_clown = f.bool() + defeated_frost_moon = f.bool() + defeated_pirates = f.bool() - smashed_altars_count = f.int4() + shadow_orbs = ShadowOrbs(smashed_at_least_once=f.bool(), + spawn_meteorite=f.bool(), + evil_boss_counter=f.int4()) - is_hardmode = f.bool() + smashed_altars_count = f.int4() - invasion_delay = f.int4() - invasion_size = f.int4() - invasion_type = InvasionType(f.int4()) - invasion_position = f.double() + is_hardmode = f.bool() - time_left_slime_rain = f.double() + invasion_delay = f.int4() + invasion_size = f.int4() + invasion_type = InvasionType(f.int4()) + invasion_position = f.double() - sundial_cooldown = f.uint1() + time_left_slime_rain = f.double() - rain = Rain(is_active=f.bool(), time_left=f.int4(), max_rain=f.single()) + sundial_cooldown = f.uint1() - hardmode_ore_1 = HardmodeTier1Ore(f.int4()) - hardmode_ore_2 = HardmodeTier2Ore(f.int4()) - hardmode_ore_3 = HardmodeTier3Ore(f.int4()) - altars_smashed = AltarsSmashed(count=smashed_altars_count, - ore_tier1=hardmode_ore_1, - ore_tier2=hardmode_ore_2, - ore_tier3=hardmode_ore_3) + rain = Rain(is_active=f.bool(), time_left=f.int4(), max_rain=f.single()) - bg_forest = f.int1() - bg_corruption = f.int1() - bg_jungle = f.int1() - bg_snow = f.int1() - bg_hallow = f.int1() - bg_crimson = f.int1() - bg_desert = f.int1() - bg_ocean = f.int1() + hardmode_ore_1 = HardmodeTier1Ore(f.int4()) + hardmode_ore_2 = HardmodeTier2Ore(f.int4()) + hardmode_ore_3 = HardmodeTier3Ore(f.int4()) + altars_smashed = AltarsSmashed(count=smashed_altars_count, + ore_tier1=hardmode_ore_1, + ore_tier2=hardmode_ore_2, + ore_tier3=hardmode_ore_3) - backgrounds = Backgrounds(bg_underground_snow=bg_underground_snow, - bg_underground_jungle=bg_underground_jungle, - bg_hell=bg_hell, - bg_forest=bg_forest, - bg_corruption=bg_corruption, - bg_jungle=bg_jungle, - bg_snow=bg_snow, - bg_hallow=bg_hallow, - bg_crimson=bg_crimson, - bg_desert=bg_desert, - bg_ocean=bg_ocean) + bg_forest = f.int1() + bg_corruption = f.int1() + bg_jungle = f.int1() + bg_snow = f.int1() + bg_hallow = f.int1() + bg_crimson = f.int1() + bg_desert = f.int1() + bg_ocean = f.int1() - clouds = Clouds(bg_cloud=f.int4(), cloud_number=f.int2(), wind_speed=f.single()) + backgrounds = Backgrounds(bg_underground_snow=bg_underground_snow, + bg_underground_jungle=bg_underground_jungle, + bg_hell=bg_hell, + bg_forest=bg_forest, + bg_corruption=bg_corruption, + bg_jungle=bg_jungle, + bg_snow=bg_snow, + bg_hallow=bg_hallow, + bg_crimson=bg_crimson, + bg_desert=bg_desert, + bg_ocean=bg_ocean) - angler_today_quest_completed_by_count = f.uint1() - angler_today_quest_completed_by = [] - for _ in range(angler_today_quest_completed_by_count): - angler_today_quest_completed_by.append(f.string()) + clouds = Clouds(bg_cloud=f.int4(), cloud_number=f.int2(), wind_speed=f.single()) - saved_angler = f.bool() + angler_today_quest_completed_by_count = f.uint1() + angler_today_quest_completed_by = [] + for _ in range(angler_today_quest_completed_by_count): + angler_today_quest_completed_by.append(f.string()) - angler_today_quest_target = AnglerQuestFish(f.int4()) - anglers_quest = AnglerQuest(current_goal=angler_today_quest_target, - completed_by=angler_today_quest_completed_by) + saved_angler = f.bool() - saved_stylist = f.bool() - saved_tax_collector = f.bool() + angler_today_quest_target = AnglerQuestFish(f.int4()) + anglers_quest = AnglerQuest(current_goal=angler_today_quest_target, + completed_by=angler_today_quest_completed_by) - invasion_size_start = f.int4() # ??? - invasion = Invasion(delay=invasion_delay, - size=invasion_size, - type_=invasion_type, - position=invasion_position, - size_start=invasion_size_start) + saved_stylist = f.bool() + saved_tax_collector = f.bool() - cultist_delay = f.int4() # ??? - mob_types_count = f.int2() - mob_kills = {} - for mob_id in range(mob_types_count): - mob_kills[mob_id] = f.int4() + invasion_size_start = f.int4() # ??? + invasion = Invasion(delay=invasion_delay, + size=invasion_size, + type_=invasion_type, + position=invasion_position, + size_start=invasion_size_start) - fast_forward_time = f.bool() - time = Time(current=current_time, - is_daytime=is_daytime, - moon_phase=moon_phase, - sundial_cooldown=sundial_cooldown, - fast_forward_time=fast_forward_time) + cultist_delay = f.int4() # ??? + mob_types_count = f.int2() + mob_kills = {} + for mob_id in range(mob_types_count): + mob_kills[mob_id] = f.int4() - defeated_duke_fishron = f.bool() - defeated_moon_lord = f.bool() - defeated_pumpking = f.bool() - defeated_mourning_wood = f.bool() - defeated_ice_queen = f.bool() - defeated_santa_nk1 = f.bool() - defeated_everscream = f.bool() - defeated_pillars = PillarsInfo(solar=f.bool(), vortex=f.bool(), nebula=f.bool(), stardust=f.bool()) + fast_forward_time = f.bool() + time = Time(current=current_time, + is_daytime=is_daytime, + moon_phase=moon_phase, + sundial_cooldown=sundial_cooldown, + fast_forward_time=fast_forward_time) - lunar_events = LunarEvents(pillars_present=PillarsInfo(solar=f.bool(), - vortex=f.bool(), - nebula=f.bool(), - stardust=f.bool()), - are_active=f.bool()) + defeated_duke_fishron = f.bool() + defeated_moon_lord = f.bool() + defeated_pumpking = f.bool() + defeated_mourning_wood = f.bool() + defeated_ice_queen = f.bool() + defeated_santa_nk1 = f.bool() + defeated_everscream = f.bool() + defeated_pillars = PillarsInfo(solar=f.bool(), vortex=f.bool(), nebula=f.bool(), stardust=f.bool()) - party_center_active = f.bool() - party_natural_active = f.bool() - party_cooldown = f.int4() - partying_npcs_count = f.int4() - partying_npcs = [] - for _ in range(partying_npcs_count): - partying_npcs.append(f.int4()) - party = Party(thrown_by_party_center=party_center_active, - thrown_by_npcs=party_natural_active, - cooldown=party_cooldown, - partying_npcs=partying_npcs) + lunar_events = LunarEvents(pillars_present=PillarsInfo(solar=f.bool(), + vortex=f.bool(), + nebula=f.bool(), + stardust=f.bool()), + are_active=f.bool()) - sandstorm = Sandstorm(is_active=f.bool(), - time_left=f.int4(), - severity=f.single(), - intended_severity=f.single()) + party_center_active = f.bool() + party_natural_active = f.bool() + party_cooldown = f.int4() + partying_npcs_count = f.int4() + partying_npcs = [] + for _ in range(partying_npcs_count): + partying_npcs.append(f.int4()) + party = Party(thrown_by_party_center=party_center_active, + thrown_by_npcs=party_natural_active, + cooldown=party_cooldown, + partying_npcs=partying_npcs) - events = Events(blood_moon=blood_moon, - solar_eclipse=eclipse, - invasion=invasion, - slime_rain=time_left_slime_rain, - rain=rain, - party=party, - sandstorm=sandstorm, - lunar_events=lunar_events) + sandstorm = Sandstorm(is_active=f.bool(), + time_left=f.int4(), + severity=f.single(), + intended_severity=f.single()) - saved_bartender = f.bool() - saved_npcs = SavedNPCs(goblin_tinkerer=saved_goblin_tinkerer, - wizard=saved_wizard, - mechanic=saved_mechanic, - angler=saved_angler, - stylist=saved_stylist, - tax_collector=saved_tax_collector, - bartender=saved_bartender) + events = Events(blood_moon=blood_moon, + solar_eclipse=eclipse, + invasion=invasion, + slime_rain=time_left_slime_rain, + rain=rain, + party=party, + sandstorm=sandstorm, + lunar_events=lunar_events) - old_ones_army = OldOnesArmyTiers(f.bool(), f.bool(), f.bool()) + saved_bartender = f.bool() + saved_npcs = SavedNPCs(goblin_tinkerer=saved_goblin_tinkerer, + wizard=saved_wizard, + mechanic=saved_mechanic, + angler=saved_angler, + stylist=saved_stylist, + tax_collector=saved_tax_collector, + bartender=saved_bartender) - bosses_defeated = BossesDefeated(eye_of_cthulhu=defeated_eye_of_cthulhu, - eater_of_worlds=defeated_eater_of_worlds, - skeletron=defeated_skeletron, - queen_bee=defeated_queen_bee, - the_twins=defeated_the_twins, - the_destroyer=defeated_the_destroyer, - skeletron_prime=defeated_skeletron_prime, - any_mechnical_boss=defeated_any_mechnical_boss, - plantera=defeated_plantera, - golem=defeated_golem, - king_slime=defeated_king_slime, - goblin_army=defeated_goblin_army, - clown=defeated_clown, - frost_moon=defeated_frost_moon, - pirates=defeated_pirates, - duke_fishron=defeated_duke_fishron, - moon_lord=defeated_moon_lord, - pumpking=defeated_pumpking, - mourning_wood=defeated_mourning_wood, - ice_queen=defeated_ice_queen, - santa_nk1=defeated_santa_nk1, - everscream=defeated_everscream, - lunar_pillars=defeated_pillars, - old_ones_army=old_ones_army) - # Tile data starts here - first_tile = cls._read_tiles(f) + old_ones_army = OldOnesArmyTiers(f.bool(), f.bool(), f.bool()) + + bosses_defeated = BossesDefeated(eye_of_cthulhu=defeated_eye_of_cthulhu, + eater_of_worlds=defeated_eater_of_worlds, + skeletron=defeated_skeletron, + queen_bee=defeated_queen_bee, + the_twins=defeated_the_twins, + the_destroyer=defeated_the_destroyer, + skeletron_prime=defeated_skeletron_prime, + any_mechnical_boss=defeated_any_mechnical_boss, + plantera=defeated_plantera, + golem=defeated_golem, + king_slime=defeated_king_slime, + goblin_army=defeated_goblin_army, + clown=defeated_clown, + frost_moon=defeated_frost_moon, + pirates=defeated_pirates, + duke_fishron=defeated_duke_fishron, + moon_lord=defeated_moon_lord, + pumpking=defeated_pumpking, + mourning_wood=defeated_mourning_wood, + ice_queen=defeated_ice_queen, + santa_nk1=defeated_santa_nk1, + everscream=defeated_everscream, + lunar_pillars=defeated_pillars, + old_ones_army=old_ones_army) + + unknown_world_header_data = f.read_until(pointers.world_tiles) + + with Timer("World Tiles", display=True): + tiledata = [] + while len(tiledata) < world_size.x: + # Read a column + column = [] + while len(column) < world_size.y: + tiles = cls._read_tiles(f, tileframeimportant) + column = [*column, *tiles] + tiledata.append(column) + + unknown_world_tiles_data = f.read_until(pointers.chests) + + breakpoint() 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, @@ -430,5 +480,4 @@ class World: 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) - breakpoint() return world