1
Fork 0
mirror of https://github.com/Steffo99/lihzahrd.git synced 2024-11-21 15:44:24 +00:00

First pass at 1.4.0.4 world header parsing.

This commit is contained in:
Dale Floer 2020-05-29 23:37:53 -07:00
parent 4fbc952d4e
commit 304b279c6a
12 changed files with 213 additions and 39 deletions

View file

@ -1,5 +1,5 @@
import lihzahrd
world = lihzahrd.World.create_from_file("Casarao.wld")
world = lihzahrd.World.create_from_file("test-1404.wld")
breakpoint()

View file

@ -10,18 +10,22 @@ from .generatorinfo import GeneratorInfo
from .hardmodeore import HardmodeTier1Ore, HardmodeTier2Ore, HardmodeTier3Ore
from .invasion import Invasion
from .invasiontype import InvasionType
from .lanternevent import LanternEvent
from .lunarevents import LunarEvents
from .moonphase import MoonPhase
from .moonstyle import MoonStyle
from .oldonesarmytiers import OldOnesArmyTiers
from .party import Party
from .pets import Pets
from .pillarsinfo import PillarsInfo
from .rain import Rain
from .sandstorm import Sandstorm
from .savednpcs import SavedNPCs
from .savedoretiers import SavedOreTiers
from .shadoworbs import ShadowOrbs
from .styles import Styles
from .time import Time
from .treetopvariants import TreetopVariants
from .version import Version
from .worldeviltype import WorldEvilType
@ -40,18 +44,22 @@ __all__ = [
"HardmodeTier3Ore",
"Invasion",
"InvasionType",
"LanternEvent",
"LunarEvents",
"MoonPhase",
"MoonStyle",
"OldOnesArmyTiers",
"Party",
"Pets",
"PillarsInfo",
"Rain",
"Sandstorm",
"SavedNPCs",
"SavedOreTiers",
"ShadowOrbs",
"Styles",
"Time",
"TreetopVariants",
"Version",
"WorldEvilType"
]

View file

@ -11,7 +11,12 @@ class Backgrounds:
bg_hallow: int,
bg_crimson: int,
bg_desert: int,
bg_ocean: int):
bg_ocean: int,
new_bg_1: int,
new_bg_2: int,
new_bg_3: int,
new_bg_4: int,
new_bg_5: int,):
self.bg_underground_snow: int = bg_underground_snow
self.bg_underground_jungle: int = bg_underground_jungle
self.bg_hell: int = bg_hell
@ -23,8 +28,14 @@ class Backgrounds:
self.bg_crimson: int = bg_crimson
self.bg_desert: int = bg_desert
self.bg_ocean: int = bg_ocean
self.new_bg_1: int = new_bg_1
self.new_bg_2: int = new_bg_2
self.new_bg_3: int = new_bg_3
self.new_bg_4: int = new_bg_4
self.new_bg_5: int = new_bg_5
def __repr__(self):
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})"
f" {self.bg_crimson}, {self.bg_desert}, {self.bg_ocean}," \
f" {self.new_bg_1}, {self.new_bg_2}, {self.new_bg_3}, {self.new_bg_4}, {self.new_bg_5})"

View file

@ -29,7 +29,9 @@ class BossesDefeated:
martian_madness: bool,
lunatic_cultist: bool,
lunar_pillars: PillarsInfo,
old_ones_army: OldOnesArmyTiers):
old_ones_army: OldOnesArmyTiers,
empress_of_light: bool,
queen_slime: bool):
self.eye_of_cthulhu: bool = eye_of_cthulhu
self.eater_of_worlds: bool = eater_of_worlds
self.skeletron: bool = skeletron
@ -59,6 +61,8 @@ class BossesDefeated:
self.lunatic_cultist: bool = lunatic_cultist
self.lunar_pillars: PillarsInfo = lunar_pillars
self.old_ones_army: OldOnesArmyTiers = old_ones_army
self.empress_of_light: bool = empress_of_light
self.queen_slime: bool = queen_slime
def __repr__(self):
return f"<BossesDefeated>"

View file

@ -3,7 +3,7 @@ from .rain import Rain
from .party import Party
from .sandstorm import Sandstorm
from .lunarevents import LunarEvents
from .lanternevent import LanternEvent
class Events:
"""Information about the ongoing world events."""
@ -15,7 +15,8 @@ class Events:
rain: Rain,
party: Party,
sandstorm: Sandstorm,
lunar_events: LunarEvents):
lunar_events: LunarEvents,
lantern_night: LanternEvent):
self.blood_moon: bool = blood_moon
"""If the current moon is a Blood Moon."""
@ -40,5 +41,8 @@ class Events:
self.lunar_events: LunarEvents = lunar_events
"""Information about the currently ongoing Lunar Events."""
self.lantern_night: LanternEvent = lantern_night
"""Information about the currently ongoing lantern night."""
def __repr__(self):
return f"<WorldEvents>"

29
lihzahrd/header/lanternevent.py Executable file
View file

@ -0,0 +1,29 @@
import typing
class LanternEvent:
"""Lantern Night event related information."""
def __init__(self,
nights_on_cooldown: int,
genuine: bool,
manual: bool,
next_night_is_lantern_night: bool):
self.nights_on_cooldown: int = nights_on_cooldown
"""How many nights before the next lantern night can happen."""
self.genuine: bool = genuine
"""Was this night started by the game spontaneously?"""
self.manual: bool = manual
"""Was this night started by the player?"""
self.next_night_is_lantern_night:bool = next_night_is_lantern_night
"""Is the next night a lantern night?"""
def __repr__(self):
return f"WorldLanternNight(nights_on_cooldown={self.nights_on_cooldown}," \
f" genuine={self.genuine}, manual={self.manual}, nights_on_cooldown={self.nights_on_cooldown})"
@property
def is_active(self):
return self.genuine or self.manual # ToDo: Test this!

View file

@ -6,6 +6,13 @@ class MoonStyle(enum.IntEnum):
WHITE = 0
ORANGE = 1
RINGED_GREEN = 2
BLUE = 3
ICE = 4
GREEN = 5
PINK = 6
PINK_ORANGE = 7
TRIPLE_PURPLE = 8
def __repr__(self):
return f"{self.__class__.__name__}.{self.name}"

19
lihzahrd/header/pets.py Executable file
View file

@ -0,0 +1,19 @@
import typing
class Pets:
"""Pet related information"""
def __init__(self,
cat: bool,
dog: bool,
bunny: bool):
self.cat: bool = cat
"""Has the cat been bought."""
self.dog: int = dog
"""Has the cat been bought."""
self.bunny: float = bunny
"""Has the bunny been bought."""
def __repr__(self):
return f"WorldPets(cat={self.cat}, dog={self.dog}, bunny={self.bunny})"

View file

@ -6,7 +6,9 @@ class SavedNPCs:
angler: bool,
stylist: bool,
tax_collector: bool,
bartender: bool):
bartender: bool,
golfer: bool,
advanced_combat: bool):
self.goblin_tinkerer: bool = goblin_tinkerer
self.wizard: bool = wizard
self.mechanic: bool = mechanic
@ -14,8 +16,11 @@ class SavedNPCs:
self.stylist: bool = stylist
self.tax_collector: bool = tax_collector
self.bartender: bool = bartender
self.golfer: bool = golfer
self.advanced_combat: bool = advanced_combat
"""Was the Advanced Combat Technique Book used."""
def __repr__(self):
return f"SavedNPCs(goblin_tinkerer={self.goblin_tinkerer}, wizard={self.wizard}, mechanic={self.mechanic}," \
f" angler={self.angler}, stylist={self.stylist}, tax_collector={self.tax_collector}," \
f" bartender={self.bartender})"
f" bartender={self.bartender}, golfer={self.golfer}, advanced_combat={self.advanced_combat}"

View file

@ -0,0 +1,17 @@
import typing
class SavedOreTiers:
"""Information about the treetop variants in the worls"""
def __init__(self,
saved_ore_tier_copper: int,
saved_ore_tier_iron: int,
saved_ore_tier_silver: int,
saved_ore_tier_gold: int,
):
self.copper: int = saved_ore_tier_copper
self.iron: int = saved_ore_tier_iron
self.silver: int = saved_ore_tier_copper
self.gold: int = saved_ore_tier_gold
def __repr__(self):
return f"WorldSavedOreTier(copper={self.copper}, iron={self.iron}, silver={self.silver}, gold={self.gold})"

View file

@ -0,0 +1,10 @@
import typing
class TreetopVariants:
"""Information about the treetop variants in the worls"""
def __init__(self,
treetop_variants: typing.List[str]):
self.treetop_variants: typing.List[str] = treetop_variants
def __repr__(self):
return f"WorldTreetopVariants({self.treetop_variants})"

View file

@ -27,7 +27,9 @@ class World:
id_: int,
bounds: Rect,
size: Coordinates,
is_expert: bool,
game_mode: int,
drunk_world: bool,
get_good_world: bool,
created_on,
styles: Styles,
backgrounds: Backgrounds,
@ -54,6 +56,9 @@ class World:
tile_entities: typing.List[TileEntity],
weighed_pressure_plates: typing.List[WeighedPressurePlate],
rooms: typing.List[Room],
pets: Pets,
treetop_variants: TreetopVariants,
saved_ore_tiers: SavedNPCs,
unknown_file_format_data: bytes = b"",
unknown_world_header_data: bytes = b"",
unknown_world_tiles_data: bytes = b"",
@ -94,8 +99,17 @@ class World:
self.size: Coordinates = size
"""The world size in tiles."""
self.is_expert: bool = is_expert
"""If the world is in expert mode or not."""
self.game_mode: int = game_mode
"""Which mode the game is in. 0=classic, 1=expert, 2=master, 3=journey"""
self.is_expert: bool = True if self.game_mode==1 else False
"""If the world is in expert mode or not, no longer stored in worldfile."""
self.drunk_world: bool = drunk_world
"""Was this world created with the drunk worldgen seed."""
self.get_good_world: bool = get_good_world
"""Was this world created with the get good worldgen seed."""
self.created_on = created_on
"""The date and time this world was created in."""
@ -166,6 +180,15 @@ class World:
self.weighed_pressure_plates: typing.List[WeighedPressurePlate] = weighed_pressure_plates
"""A list of all Weighed Pressure Plates in the world."""
self.pets: Pets = pets
"""Which pets have bene purchased."""
self.treetop_variants: TreetopVariants = treetop_variants
"""Treetops variants that can exist in the world."""
self.saved_ore_tiers: SavedOreTiers = saved_ore_tiers
"""Probably related to drunk wordgen having both types of ores."""
self.rooms: typing.List[Room] = rooms
self.clouds: Clouds = clouds
self.cultist_delay: int = cultist_delay
@ -292,8 +315,8 @@ class World:
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.")
if version != Version("1.4.0.4") or relogic != "relogic" or savefile_type != 2:
raise NotImplementedError("This parser can only read Terraria 1.4.0.4 save files.")
revision = f.uint4()
is_favorite = f.uint8() != 0
@ -309,14 +332,15 @@ class World:
unknown_file_format_data = f.read_until(pointers.world_header)
name = f.string()
generator = GeneratorInfo(f.string(), f.uint8())
uuid_ = f.uuid()
id_ = f.int4()
bounds = f.rect()
world_size = Coordinates(y=f.int4(), x=f.int4())
is_expert = f.bool()
game_mode = f.int4()
drunk_world = f.bool()
get_good_world = f.bool()
created_on = f.datetime()
world_styles = Styles(moon=MoonStyle(f.uint1()),
@ -415,18 +439,6 @@ class World:
bg_desert = f.int1()
bg_ocean = f.int1()
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)
clouds = Clouds(bg_cloud=f.int4(), cloud_number=f.int2(), wind_speed=f.single())
angler_today_quest_completed_by_count = f.uint1()
@ -442,6 +454,7 @@ class World:
saved_stylist = f.bool()
saved_tax_collector = f.bool()
saved_golfer = f.bool()
invasion_size_start = f.int4() # ???
invasion = Invasion(delay=invasion_delay,
@ -497,6 +510,49 @@ class World:
severity=f.single(),
intended_severity=f.single())
saved_bartender = f.bool()
old_ones_army = OldOnesArmyTiers(f.bool(), f.bool(), f.bool())
# ToDo: Figure out which biomes got new BGs.
# Oasis and Graveyard probably got new backgrounds.
new_bg_1 = f.int1()
new_bg_2 = f.int1()
new_bg_3 = f.int1() # Maybe oasis.
new_bg_4 = f.int1()
new_bg_5 = f.int1()
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,
new_bg_1=new_bg_1,
new_bg_2=new_bg_2,
new_bg_3=new_bg_3,
new_bg_4=new_bg_4,
new_bg_5=new_bg_5,)
combat_book_used = 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,
golfer=saved_golfer,
advanced_combat=combat_book_used)
lantern_night = LanternEvent(f.int4(), f.bool(), f.bool(), f.bool())
events = Events(blood_moon=blood_moon,
solar_eclipse=eclipse,
invasion=invasion,
@ -504,18 +560,18 @@ class World:
rain=rain,
party=party,
sandstorm=sandstorm,
lunar_events=lunar_events)
lunar_events=lunar_events,
lantern_night=lantern_night)
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)
treetop_variant_count = f.int4()
treetop_variants = TreetopVariants([f.int4() for _ in range(treetop_variant_count)])
old_ones_army = OldOnesArmyTiers(f.bool(), f.bool(), f.bool())
saved_ore_tiers = SavedOreTiers(f.int4(), f.int4(), f.int4(), f.int4())
pets = Pets(f.bool(), f.bool(), f.bool())
defeated_empress_of_light = f.bool()
defeated_queen_slime = f.bool()
bosses_defeated = BossesDefeated(eye_of_cthulhu=defeated_eye_of_cthulhu,
eater_of_worlds=defeated_eater_of_worlds,
@ -542,7 +598,9 @@ class World:
lunar_pillars=defeated_pillars,
old_ones_army=old_ones_army,
martian_madness=defeated_martian_madness,
lunatic_cultist=defeated_lunatic_cultist)
lunatic_cultist=defeated_lunatic_cultist,
empress_of_light=defeated_empress_of_light,
queen_slime=defeated_queen_slime)
unknown_world_header_data = f.read_until(pointers.world_tiles)
@ -671,7 +729,8 @@ class World:
# Object creation
world = cls(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,
is_expert=is_expert, created_on=created_on, styles=world_styles, backgrounds=backgrounds,
game_mode=game_mode, drunk_world=drunk_world, get_good_world=get_good_world,
created_on=created_on, styles=world_styles, backgrounds=backgrounds,
spawn_point=spawn_point, underground_level=underground_level, cavern_level=cavern_level,
time=time, events=events, dungeon_point=dungeon_point, world_evil=world_evil,
saved_npcs=saved_npcs, altars_smashed=altars_smashed, is_hardmode=is_hardmode,
@ -679,6 +738,7 @@ class World:
clouds=clouds, cultist_delay=cultist_delay, tiles=tm, chests=chests, signs=signs,
npcs=npcs, mobs=mobs, tile_entities=tile_entities,
weighed_pressure_plates=weighed_pressure_plates, rooms=rooms,
treetop_variants=treetop_variants, saved_ore_tiers=saved_ore_tiers, pets=pets,
unknown_file_format_data=unknown_file_format_data,
unknown_world_header_data=unknown_world_header_data,
unknown_world_tiles_data=unknown_world_tiles_data,