extends Node # Updated each frame from ObserverSnapshot data (Protocol format: {tick, entities, tiles}). # Entities use Protocol decoded format: {entity_id, x, y, z, kind: {variant, data}}. # Tiles use format: [{x, y, z, type}]. var current_snapshot: Dictionary = {} var current_tick: int = 0 var player_position: Vector2 = Vector2.ZERO var visible_entities: Array = [] var visible_tiles: Array = [] var visible_positions: Dictionary = {} # Vector2i -> true, for fast fog lookups # v2 fields (D-015, D-031) var game_time: Dictionary = {} # {day, time_of_day, day_phase, paused} or empty var player_facing: String = "North" # 8-directional facing direction var visibility_sectors: Dictionary = {} # Vector2i -> "Forward"/"Peripheral" # Player entity ID — the first entity is assumed to be the player (will be # refined when the server assigns explicit player entity IDs). var player_entity_id: int = 1 func apply_snapshot(snapshot: Dictionary) -> void: current_snapshot = snapshot if snapshot.has("tick"): current_tick = snapshot.tick if snapshot.has("entities"): visible_entities = snapshot.entities # Derive player position from the player entity var found_player := false for entity in visible_entities: if entity.has("entity_id") and entity.entity_id == player_entity_id: player_position = Vector2(entity.x, entity.y) found_player = true break if not found_player and visible_entities.size() > 0: push_warning("GameState: player entity_id %d not found in %d entities" % [ player_entity_id, visible_entities.size()]) if snapshot.has("tiles"): visible_tiles = snapshot.tiles if snapshot.has("visible_positions"): visible_positions.clear() for pos in snapshot.visible_positions: visible_positions[Vector2i(pos.x, pos.y)] = true # v2: game_time (D-031) if snapshot.has("game_time") and snapshot.game_time is Dictionary: game_time = snapshot.game_time # v2: player_facing (D-015) if snapshot.has("player_facing") and snapshot.player_facing is String: player_facing = snapshot.player_facing # v2: visible_tiles with visibility sectors # Derives visible_positions when not explicitly provided (real server mode) if snapshot.has("visible_tiles") and snapshot.visible_tiles is Array and snapshot.visible_tiles.size() > 0: visibility_sectors.clear() var has_explicit_positions := snapshot.has("visible_positions") if not has_explicit_positions: visible_positions.clear() for vtile in snapshot.visible_tiles: if not vtile is Dictionary or not vtile.has("x") or not vtile.has("y"): continue var pos := Vector2i(vtile.x, vtile.y) if vtile.has("visibility"): visibility_sectors[pos] = vtile.visibility if not has_explicit_positions: visible_positions[pos] = true