From 6b50c8a4472461683a98605d6388f34e368c9f58 Mon Sep 17 00:00:00 2001 From: xeon Date: Sat, 7 Feb 2026 19:29:41 +0300 Subject: [PATCH] feat(scene): implement CS_SCENE_REPATRIATE handler Now the player shouldn't get stuck after going to forbidden areas (e.g. water) --- gamesv/src/Assets.zig | 21 +++++++++++++++++++++ gamesv/src/logic/messaging/scene.zig | 28 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/gamesv/src/Assets.zig b/gamesv/src/Assets.zig index 7b1595f..c73e436 100644 --- a/gamesv/src/Assets.zig +++ b/gamesv/src/Assets.zig @@ -7,6 +7,7 @@ pub const CharacterSkillMap = @import("Assets/CharacterSkillMap.zig"); const Io = std.Io; const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; +const HashMap = std.AutoArrayHashMapUnmanaged; const StringHashMap = std.StringArrayHashMapUnmanaged; const meta = std.meta; @@ -19,6 +20,7 @@ str_to_num_dicts: IndexDictionaries.StrToNum, num_to_str_dicts: IndexDictionaries.NumToStr, common_skill_config: configs.CommonSkillConfig, level_config_table: StringHashMap(configs.LevelConfig), +level_config_table_by_num_id: HashMap(i32, *const configs.LevelConfig), // Map mark groups as they're stored in LevelMapMark.json level_map_mark_groups: StringHashMap([]const configs.ClientSingleMapMarkData), // instId-to-data mapping @@ -76,6 +78,11 @@ pub fn load(io: Io, gpa: Allocator) !Assets { "LevelConfigTable.json", )).map; + const level_config_table_by_num_id = try buildLevelConfigByNumIdTable( + &level_config_table, + arena.allocator(), + ); + const level_map_mark_groups = (try configs.loadJsonConfig( std.json.ArrayHashMap([]const configs.ClientSingleMapMarkData), io, @@ -100,6 +107,7 @@ pub fn load(io: Io, gpa: Allocator) !Assets { .num_to_str_dicts = num_to_str_dicts, .common_skill_config = common_skill_config, .level_config_table = level_config_table, + .level_config_table_by_num_id = level_config_table_by_num_id, .level_map_mark_groups = level_map_mark_groups, .map_mark_table = map_mark_table, .teleport_validation_table = teleport_validation_table, @@ -124,6 +132,19 @@ fn buildMapMarkTable( return map; } +fn buildLevelConfigByNumIdTable( + str_table: *const StringHashMap(configs.LevelConfig), + arena: Allocator, +) Allocator.Error!HashMap(i32, *const configs.LevelConfig) { + var map: HashMap(i32, *const configs.LevelConfig) = .empty; + + for (str_table.values()) |*config| { + try map.put(arena, config.idNum, config); + } + + return map; +} + pub fn deinit(assets: *Assets) void { assets.owned_tables.deinit(); assets.arena.deinit(); diff --git a/gamesv/src/logic/messaging/scene.zig b/gamesv/src/logic/messaging/scene.zig index 06fd56d..e2e3859 100644 --- a/gamesv/src/logic/messaging/scene.zig +++ b/gamesv/src/logic/messaging/scene.zig @@ -1,5 +1,6 @@ const pb = @import("proto").pb; const logic = @import("../../logic.zig"); +const Assets = @import("../../Assets.zig"); const messaging = logic.messaging; const Level = logic.Level; @@ -59,3 +60,30 @@ pub fn onMoveObjectMove( } } } + +pub fn onSceneRepatriate( + request: messaging.Request(pb.CS_SCENE_REPATRIATE), + assets: *const Assets, + scene: Player.Component(.scene), + change_scene_tx: logic.event.Sender(.change_scene_begin), + cur_scene_modified_tx: logic.event.Sender(.current_scene_modified), +) !void { + if (scene.data.current.level_id != request.message.scene_num_id) + return; + + const level_config = assets.level_config_table_by_num_id.get(scene.data.current.level_id).?; + scene.data.current.position = .{ + level_config.playerInitPos.x, + level_config.playerInitPos.y, + level_config.playerInitPos.z, + }; + + scene.data.current.rotation = .{ + level_config.playerInitRot.x, + level_config.playerInitRot.y, + level_config.playerInitRot.z, + }; + + try cur_scene_modified_tx.send(.{}); + try change_scene_tx.send(.{}); +}