On this page
Project-scoped level-editor tilemap mutations for tile, entity, and collision placement plus map-layer management, with apply-or-reject semantics and undo records.
#server.src.pixelweaver.level_ops
#server.src.pixelweaver.level_ops
Project-scoped level-editor (tilemap) mutations -- the nine level commands.
A faithful, MCP-agnostic mirror of the client map-state.svelte.ts singleton (plain ProjectState + params in, meta_snapshot record out -- exactly like character_ops / frame_tag_ops). Each function does a read-modify-write on project.level_map (the client-canonical SerializedMapState dict) against a deep copy and returns a meta_snapshot undo record for the level_map project attribute (before/after the whole document), applied by undo_history.
Design rules honored: - Self-contained forwarded params: the three object-placing commands (place_tile / place_entity / add_collision_shape) carry the target layer's id AND name, and MATERIALIZE the layer if the server has not seen it yet. Map layers have no lifecycle command of their own, so a placement is defined to be self-contained -- it creates the layer it targets. Layer TYPE is implied by the command (tile / entity / collision). - Client-generated ids: place_entity / add_collision_shape replay the id the client minted (stabilize-in-execute), so both sides agree on object identity. - Apply-or-reject: the mutating (non-creating) commands hard-error when their target layer / entity / shape is missing, rather than silently no-op.
#_tile_key
def _tile_key(col: int, row: int) -> strMirror of map-state's internal tileKey ("col,row").
#_require_layer
def _require_layer(level_map: dict[str, Any], layer_id: str, layer_type: str) -> dict[str, Any]Resolve an EXISTING layer of layer_type (hard error if missing/wrong).
#_new_layer_dict
def _new_layer_dict(layer_id: str, layer_type: str, name: str) -> dict[str, Any]Build an empty map-layer dict (mirror of the client addLayer shape).
#_get_or_create_layer
def _get_or_create_layer(level_map: dict[str, Any], layer_id: str, layer_type: str, layer_name: str | None) -> dict[str, Any]Resolve an existing layer or MATERIALIZE it (self-contained placement).
A placement referencing an unknown layer id creates that layer with the embedded name (falling back to the client's type-default name). This coexists with the explicit add_map_layer lifecycle command: an explicit add creates the layer up front, while a placement into a not-yet-synced layer still materializes it, so a fresh reload never loses the placement.
#place_tile
def place_tile(project: ProjectState, *, layer_id: str, col: int, row: int, tile: dict[str, Any], layer_name: str | None=None) -> dict[str, Any]Paint tile at (col, row) on a tile layer (materialize it if absent).
#remove_tile
def remove_tile(project: ProjectState, *, layer_id: str, col: int, row: int) -> dict[str, Any]Erase the tile at (col, row) on an existing tile layer (empty cell = no-op).
#place_entity
def place_entity(project: ProjectState, *, layer_id: str, entity_id: str, project_ref: str, canvas_ref: str, x: float, y: float, height: float, properties: dict[str, str], layer_name: str | None=None) -> dict[str, Any]Add a client-minted entity to an entity layer (materialize it if absent).
#move_entity
def move_entity(project: ProjectState, *, layer_id: str, entity_id: str, x: float, y: float) -> dict[str, Any]Set an existing entity's screen position.
#remove_entity
def remove_entity(project: ProjectState, *, layer_id: str, entity_id: str) -> dict[str, Any]Remove an existing entity by id.
#update_entity_properties
def update_entity_properties(project: ProjectState, *, layer_id: str, entity_id: str, properties: dict[str, str]) -> dict[str, Any]Merge properties into an existing entity (mirror of the client merge).
#add_collision_shape
def add_collision_shape(project: ProjectState, *, layer_id: str, shape_id: str, type: str, points: list[dict[str, Any]], layer_name: str | None=None) -> dict[str, Any]Add a client-minted collision shape to a collision layer (materialize it if absent).
#remove_collision_shape
def remove_collision_shape(project: ProjectState, *, layer_id: str, shape_id: str) -> dict[str, Any]Remove an existing collision shape by id.
#add_map_layer
def add_map_layer(project: ProjectState, *, layer_id: str, name: str, type: str) -> dict[str, Any]Create an EMPTY map layer (mirror of map-state addLayer).
The client mints the id (stabilize-in-execute) and embeds it. Hard error if the id already exists -- this is a creation command, not an upsert. Sets activeLayerId to the new layer, exactly like the client.
#remove_map_layer
def remove_map_layer(project: ProjectState, *, layer_id: str) -> dict[str, Any]Remove a map layer by id (mirror of map-state removeLayer).
Reassigns activeLayerId to the first remaining layer (or "") when the removed layer was the active one. Hard error if the layer is missing.
#set_map_layer_visibility
def set_map_layer_visibility(project: ProjectState, *, layer_id: str, visible: bool) -> dict[str, Any]Set a map layer's visibility (mirror of the client visibility toggle).
#set_map_grid
def set_map_grid(project: ProjectState, *, cols: int, rows: int, tile_width: int, tile_height: int, grid_mode: str) -> dict[str, Any]Set the grid dimensions, tile size, and projection mode (all at once).
Mirror of the MapPropertiesPanel controls. Validation mirrors the client's clamps (grid dims >= 1, tile dims >= 4) and the gridMode enum -- present but invalid values are a hard error, never silently defaulted.
#move_map_layer
def move_map_layer(project: ProjectState, *, from_index: int, to_index: int) -> dict[str, Any]Reorder a map layer (mirror of map-state moveLayer splice).