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