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

Use a tilematrix instead of a list of lists

This commit is contained in:
Steffo 2019-08-12 21:57:08 +02:00
parent 317d5d5190
commit 86ebd39c4e
6 changed files with 78 additions and 12 deletions

2
lihzahrd/errors.py Normal file
View file

@ -0,0 +1,2 @@
class InvalidFooterError(Exception):
"""This exception is raised if the footer contents do not match the expected data."""

View file

@ -9,6 +9,7 @@ from .block import Block
from .wall import Wall
from .liquid import Liquid
from .tile import Tile
from .tilematrix import TileMatrix
__all__ = ["LiquidType", "RLEEncoding", "Shape", "Wiring", "BlockType", "FrameImportantData", "WallType", "Block",
"Wall", "Liquid", "Tile"]
"Wall", "Liquid", "Tile", "TileMatrix"]

View file

@ -0,0 +1,61 @@
import typing
from .tile import Tile
from ..fileutils import FileReader, Coordinates
class TileMatrix:
"""A huge matrix containing the tiles of a whole world."""
def __init__(self):
self._tiles: typing.List[typing.List[Tile]] = []
def __repr__(self):
if len(self._tiles) > 0:
return f"<TileMatrix {len(self._tiles)}x{len(self._tiles[0])}>"
return f"<TileMatrix 0x0>"
def __getitem__(self, item: typing.Union[typing.Tuple, Coordinates]):
"""Get a tile at specific coordinates.
(x=0, y=0) returns the top-left tile in the map.
You can specify a negative coordinate to count tiles respectively from the right or from the bottom:
(x=-1, y=-1) returns the bottom-right tile in the map."""
if isinstance(item, Coordinates):
return self._tiles[item.x][item.y]
elif isinstance(item, tuple):
return self._tiles[item[0]][item[1]]
else:
raise TypeError(f"Unsupported type: {item.__class__.__name__}")
def __setitem__(self, key: typing.Union[typing.Tuple, Coordinates], value: Tile):
"""Change a tile at specific coordinates.
The same properties that apply to __getitem__ are valid for __setitem__."""
if not isinstance(value, Tile):
raise TypeError(f"Invalid type: {value.__class__.__name__} instead of Tile")
if isinstance(key, Coordinates):
self._tiles[key.x][key.y] = value
elif isinstance(key, tuple):
self._tiles[key[0]][key[1]] = value
else:
raise TypeError(f"Invalid type: {key.__class__.__name__} instead of tuple or Coordinates")
def __len__(self):
"""Return the amount of tiles present in the matrix."""
if len(self._tiles) > 0:
return len(self._tiles) * len(self._tiles[0])
return 0
def add_column(self, column: typing.List[Tile]):
"""Add a new column to the matrix."""
if len(self._tiles) > 0 and len(column) != len(self._tiles[0]):
raise ValueError("column has a different length than the others in the matrix")
self._tiles.append(column)
@property
def size(self) -> Coordinates:
"""Return the size of the matrix as a pair of coordinates."""
if len(self._tiles) > 0:
return Coordinates(len(self._tiles), len(self._tiles[0]))
return Coordinates(0, 0)

View file

@ -37,4 +37,4 @@ class Wiring:
if flags3 is not None:
return cls(red=flags2[1], green=flags2[2], blue=flags2[3], yellow=flags3[5], actuator=flags3[1])
return cls(red=flags2[1], green=flags2[2], blue=flags2[3])
return None
return cls()

View file

@ -3,7 +3,8 @@ import typing
class Timer:
def __init__(self, name: str, display: bool = False):
"""An object to track and print the time required to perform a section of code."""
def __init__(self, name: str, display: bool = True):
self.name: str = name
self.display: bool = display
self._start_time: typing.Optional[float] = None

View file

@ -11,6 +11,7 @@ from .tileentities import *
from .pressureplates import *
from .townmanager import *
from .timer import Timer
from .errors import InvalidFooterError
class World:
@ -46,7 +47,7 @@ class World:
anglers_quest: AnglerQuest,
clouds: Clouds,
cultist_delay: int,
tiles: typing.List[typing.List[Tile]],
tiles: TileMatrix,
chests: typing.List[Chest],
signs: typing.List[Sign],
npcs: typing.List[NPC],
@ -145,7 +146,7 @@ class World:
self.anglers_quest: AnglerQuest = anglers_quest
"""Information about today's Angler's Quest."""
self.tiles: typing.List[typing.List[Tile]] = tiles
self.tiles: TileMatrix = tiles
"""A matrix of all the tiles present in the world."""
self.chests: typing.List[Chest] = chests
@ -515,13 +516,13 @@ class World:
unknown_world_header_data = f.read_until(pointers.world_tiles)
with Timer("World Tiles", display=True):
tiles = []
while len(tiles) < world_size.x:
tm = TileMatrix()
while tm.size.x < world_size.x:
column = []
while len(column) < world_size.y:
readtiles = cls._read_tile_block(f, tileframeimportant)
column = [*column, *readtiles]
tiles.append(column)
tm.add_column(column)
unknown_world_tiles_data = f.read_until(pointers.chests)
@ -642,7 +643,7 @@ 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, signs=signs,
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,
unknown_file_format_data=unknown_file_format_data,
@ -657,10 +658,10 @@ class World:
with Timer("Footer", display=True):
if not f.bool():
raise Exception("Invalid footer")
raise InvalidFooterError("Invalid footer")
if not f.string() == world.name:
raise Exception("Invalid footer")
raise InvalidFooterError("Invalid footer")
if not f.int4() == world.id:
raise Exception("Invalid footer")
raise InvalidFooterError("Invalid footer")
return world