Skip to content
Back to top
View this page

# Common operations

This page lists some common operations you’ll find yourself doing while using `lihzahrd`.

Tip

What else would you like to see here? Don’t be afraid to ask, it helps us build a better package!

## Loading a world file

To load an existing Terraria world save file, first you’ll need to `open()` a binary file object:

    1with open("World.wld", "rb") as file:
    2    pass

Then, you’ll need to load the file object in a `FileProcessor`:

    1from lihzahrd.terraria.utils.file_processor import FileProcessor
    2
    3with open("World.wld", "rb") as file:
    4    fp = FileProcessor(file)

Then, with the file object still open, call the `read()` class method of `PackWorld` to get a `PackRead` containing the results of the read:

    1from lihzahrd.terraria.utils.file_processor import FileProcessor
    2from lihzahrd.terraria.world.world import PackWorld
    3
    4with open("World.wld", "rb") as file:
    5    fp = FileProcessor(file)
    6    result = PackWorld.read(fp, strict=False)  # Note: can be very slow!

You can now close the file; if the read completed without any issues, your results will be `valid`, but even if an issue occurred, you’ll still be able to access the read data at `instance`:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3
     4with open("World.wld", "rb") as file:
     5    fp = FileProcessor(file)
     6    result = PackWorld.read(fp, strict=False)
     7
     8if not result.valid:
     9    exit(1)
    10
    11world = result.instance

## Accessing a world’s properties

Properties are contained inside `PackWorld` objects, and are grouped by the section of the save file they appear in.

Most data about a world appears in the `header`, and all of the properties appearing there can have their values accessed directly as a Python object via their `value` attribute:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3
     4with open("World.wld", "rb") as file:
     5    fp = FileProcessor(file)
     6    result = PackWorld.read(fp, strict=False)
     7
     8if not result.valid:
     9    exit(1)
    10
    11world = result.instance
    12
    13world_name: str = world.header.name.value
    14print(f"Welcome to {world_name}!")

Values can also be set to change them:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3
     4with open("World.wld", "rb") as file:
     5    fp = FileProcessor(file)
     6    result = PackWorld.read(fp, strict=False)
     7
     8if not result.valid:
     9    exit(1)
    10
    11world = result.instance
    12
    13world_name: str = world.header.name.value
    14print(f"Welcome to {world_name}!")
    15
    16world.header.name.value = f"{world_name} but for the Worthy"
    17world.header.special_fortheworthy.value = True

Some properties may offer utility methods which might be clearer or safer to use than directly accessing `value`; those are usually called `is_*`, `set_to_*`, `get_*`, or `set_from_*`:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3from lihzahrd.terraria.data.classmembers.block_base import BlockBase
     4from lihzahrd.terraria.data.classmembers.blocks import PalladiumOre
     5
     6with open("World.wld", "rb") as file:
     7    fp = FileProcessor(file)
     8    result = PackWorld.read(fp, strict=False)
     9
    10if not result.valid:
    11    exit(1)
    12
    13world = result.instance
    14
    15world_name: str = world.header.name.value
    16world_ore_1: type[BlockBase] = world.header.ore_copper_tier.get_block()
    17
    18print(f"Welcome to {world_name}, land of {world_ore_1.NAME}!")
    19if world.header.difficulty.is_master():
    20    print("You are already a legendary hero!")
    21if world.header.mode.is_hardmode():
    22    print("Your foes are already worthy of the challenge!")
    23
    24world.header.name.value = f"{world_name} but for Legendary Heroes"
    25world.header.difficulty.set_master()
    26world.header.special_fortheworthy.value = True
    27world.header.mode.set_to_hardmode()
    28world.header.ore_cobalt_tier.set_from_block(PalladiumOre)

## Saving a world file

Once you’ve completed your edits, you can save back the world to a file.

Again, you’ll need to `open()` a binary file object, but this time in write mode, and make a `FileProcessor` like before:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3from lihzahrd.terraria.data.classmembers.block_base import BlockBase
     4from lihzahrd.terraria.data.classmembers.blocks import PalladiumOre
     5
     6with open("World.wld", "rb") as file:
     7    fp = FileProcessor(file)
     8    result = PackWorld.read(fp, strict=False)
     9
    10if not result.valid:
    11    exit(1)
    12
    13world = result.instance
    14
    15world_name: str = world.header.name.value
    16world_ore_1: type[BlockBase] = world.header.ore_copper_tier.get_block()
    17
    18print(f"Welcome to {world_name}, land of {world_ore_1.NAME}!")
    19if world.header.difficulty.is_master():
    20    print("You are already a legendary hero!")
    21if world.header.mode.is_hardmode():
    22    print("Your foes are already worthy of the challenge!")
    23
    24world.header.name.value = f"{world_name} but for Legendary Heroes"
    25world.header.difficulty.set_master()
    26world.header.special_fortheworthy.value = True
    27world.header.mode.set_to_hardmode()
    28world.header.ore_cobalt_tier.set_from_block(PalladiumOre)
    29
    30with open("WorldLegendary.wld", "wb") as file:
    31    fp = FileProcessor(file)

Then, you can `write()` the `PackWorld` instance to it, getting a `PackWrite` result object, through which you can check if the written world is `valid`:

     1from lihzahrd.terraria.utils.file_processor import FileProcessor
     2from lihzahrd.terraria.world.world import PackWorld
     3from lihzahrd.terraria.data.classmembers.block_base import BlockBase
     4from lihzahrd.terraria.data.classmembers.blocks import PalladiumOre
     5
     6with open("World.wld", "rb") as file:
     7    fp = FileProcessor(file)
     8    result = PackWorld.read(fp, strict=False)
     9
    10if not result.valid:
    11    exit(1)
    12
    13world = result.instance
    14
    15world_name: str = world.header.name.value
    16world_ore_1: type[BlockBase] = world.header.ore_copper_tier.get_block()
    17
    18print(f"Welcome to {world_name}, land of {world_ore_1.NAME}!")
    19if world.header.difficulty.is_master():
    20    print("You are already a legendary hero!")
    21if world.header.mode.is_hardmode():
    22    print("Your foes are already worthy of the challenge!")
    23
    24world.header.name.value = f"{world_name} but for Legendary Heroes"
    25world.header.difficulty.set_master()
    26world.header.special_fortheworthy.value = True
    27world.header.mode.set_to_hardmode()
    28world.header.ore_cobalt_tier.set_from_block(PalladiumOre)
    29
    30with open("WorldLegendary.wld", "wb") as file:
    31    fp = FileProcessor(file)
    32    result = world.write(fp, strict=False)
    33
    34if not result.valid:
    35    exit(2)

## Editing tiles

Tiles are represented internally as a `numpy` matrix, which you can edit in the same ways you’d edit such an object, except that you can assign `Tile` objects to their values:

     1from lihzahrd.terraria.data.classmembers.blocks import Grass, Dirt
     2from lihzahrd.terraria.data.classmembers.walls import DirtWall
     3
     4...
     5
     6# Turn all tiles in the world into air
     7world.tiles[:, :] = Tile()
     8
     9# Create a line of grass blocks at world height 300
    10world.tiles[:, 300:301] = Tile(block=Grass())
    11
    12# Fill everything below height 300 with dirt blocks and dirt walls
    13world.tiles[:, 301:] = Tile(block=Dirt(), wall=DirtWall())

Alternatively, you can manually access the properties as you would for a structured array, but you’ll need to manually set their values as described by `TILE_DTYPE`:

     1...
     2
     3# In the left half of the world, draw a red wire column every 10 tiles
     4world.tiles["wire_red"][0:2100:10, :] = True
     5
     6# In the right half of the world, draw a blue wire column every 10 tiles
     7world.tiles["wire_blue"][2101:4200:10, :] = True
     8
     9# Remove one block every 3x3 square
    10world.tiles["block_id"][::3, ::3] = 0