mirror of
https://git.xeondev.com/LR/S.git
synced 2026-03-21 23:22:21 +01:00
250 lines
8.0 KiB
Zig
250 lines
8.0 KiB
Zig
const std = @import("std");
|
|
const pb = @import("proto").pb;
|
|
const logic = @import("../../logic.zig");
|
|
const Session = @import("../../Session.zig");
|
|
const Assets = @import("../../Assets.zig");
|
|
|
|
const Level = logic.Level;
|
|
const Player = logic.Player;
|
|
const ArrayList = std.ArrayList;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
pub fn enterSceneOnLogin(
|
|
rx: logic.event.Receiver(.login),
|
|
tx: logic.event.Sender(.change_scene_begin),
|
|
) !void {
|
|
_ = rx;
|
|
|
|
try tx.send(.{});
|
|
}
|
|
|
|
fn respawnCharTeam(
|
|
gpa: Allocator,
|
|
char_bag: *const Player.CharBag,
|
|
cur_scene: *const Player.Scene.Current,
|
|
level: *Level,
|
|
) Level.SpawnError!void {
|
|
// Despawn previous team
|
|
var team = level.team();
|
|
var char_net_id = team.next();
|
|
while (char_net_id != .none) : (char_net_id = team.next()) {
|
|
const handle = level.getObjectByNetId(char_net_id).?;
|
|
level.despawn(handle);
|
|
}
|
|
|
|
// Spawn new team
|
|
const position: Level.Object.Vector = .{
|
|
.x = cur_scene.position[0],
|
|
.y = cur_scene.position[1],
|
|
.z = cur_scene.position[2],
|
|
};
|
|
|
|
const rotation: Level.Object.Vector = .{
|
|
.x = cur_scene.rotation[0],
|
|
.y = cur_scene.rotation[1],
|
|
.z = cur_scene.rotation[2],
|
|
};
|
|
|
|
const team_index = char_bag.meta.curr_team_index;
|
|
const chars = char_bag.chars.slice();
|
|
|
|
for (char_bag.teams.items(.char_team)[team_index]) |slot| {
|
|
const char_index = slot.charIndex() orelse continue;
|
|
const i = @intFromEnum(char_index);
|
|
|
|
const char_template_id_num = chars.items(.template_id)[i];
|
|
|
|
_ = try level.spawn(
|
|
gpa,
|
|
.{
|
|
.template_id = char_template_id_num,
|
|
.position = position,
|
|
.rotation = rotation,
|
|
.hp = chars.items(.hp)[i],
|
|
},
|
|
.{ .character = .{
|
|
.level = chars.items(.level)[i],
|
|
.char_index = char_index,
|
|
} },
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn beginChangingScene(
|
|
rx: logic.event.Receiver(.change_scene_begin),
|
|
gpa: logic.Resource.Allocator(.gpa),
|
|
session: *Session,
|
|
base: Player.Component(.base),
|
|
scene: Player.Component(.scene),
|
|
char_bag: Player.Component(.char_bag),
|
|
level: *Level,
|
|
) !void {
|
|
_ = rx;
|
|
|
|
level.reset();
|
|
try respawnCharTeam(gpa.interface, char_bag.data, &scene.data.current, level);
|
|
|
|
const position: pb.VECTOR = .{
|
|
.X = scene.data.current.position[0],
|
|
.Y = scene.data.current.position[1],
|
|
.Z = scene.data.current.position[2],
|
|
};
|
|
|
|
try session.send(pb.SC_CHANGE_SCENE_BEGIN_NOTIFY{
|
|
.scene_num_id = scene.data.current.level_id,
|
|
.position = position,
|
|
.pass_through_data = .init,
|
|
});
|
|
|
|
try session.send(pb.SC_ENTER_SCENE_NOTIFY{
|
|
.role_id = base.data.role_id,
|
|
.scene_num_id = scene.data.current.level_id,
|
|
.position = position,
|
|
.pass_through_data = .init,
|
|
});
|
|
}
|
|
|
|
pub fn refreshCharTeam(
|
|
rx: logic.event.Receiver(.char_bag_team_modified),
|
|
gpa: logic.Resource.Allocator(.gpa),
|
|
char_bag: Player.Component(.char_bag),
|
|
scene: Player.Component(.scene),
|
|
level: *Level,
|
|
sync_tx: logic.event.Sender(.sync_self_scene),
|
|
) !void {
|
|
switch (rx.payload.modification) {
|
|
.set_leader => return, // Doesn't require any action from server.
|
|
.set_char_team => if (rx.payload.team_index == char_bag.data.meta.curr_team_index) {
|
|
// If the current active team has been modified, it has to be re-spawned.
|
|
try respawnCharTeam(gpa.interface, char_bag.data, &scene.data.current, level);
|
|
try sync_tx.send(.{ .reason = .team_modified });
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn syncSelfScene(
|
|
rx: logic.event.Receiver(.sync_self_scene),
|
|
session: *Session,
|
|
arena: logic.Resource.Allocator(.arena),
|
|
char_bag: Player.Component(.char_bag),
|
|
scene: Player.Component(.scene),
|
|
level: *Level,
|
|
assets: *const Assets,
|
|
) !void {
|
|
const reason: pb.SELF_INFO_REASON_TYPE = switch (rx.payload.reason) {
|
|
.entrance => .SLR_ENTER_SCENE,
|
|
.team_modified => .SLR_CHANGE_TEAM,
|
|
};
|
|
|
|
const team_index = char_bag.data.meta.curr_team_index;
|
|
const leader_index = char_bag.data.teams.items(.leader_index)[team_index];
|
|
|
|
var self_scene_info: pb.SC_SELF_SCENE_INFO = .{
|
|
.scene_num_id = scene.data.current.level_id,
|
|
.self_info_reason = @intFromEnum(reason),
|
|
.teamInfo = .{
|
|
.team_type = .CHAR_BAG_TEAM_TYPE_MAIN,
|
|
.team_index = @intCast(team_index),
|
|
.cur_leader_id = leader_index.objectId(),
|
|
.team_change_token = 0,
|
|
},
|
|
.scene_impl = .{ .empty = .{} },
|
|
.detail = .{},
|
|
};
|
|
|
|
const objects = level.objects.slice();
|
|
for (0..objects.len) |i| {
|
|
const position = objects.items(.position)[i];
|
|
const rotation = objects.items(.rotation)[i];
|
|
const net_id = @intFromEnum(objects.items(.net_id)[i]);
|
|
|
|
var common_info: pb.SCENE_OBJECT_COMMON_INFO = .{
|
|
.id = net_id,
|
|
.position = .{ .X = position.x, .Y = position.y, .Z = position.z },
|
|
.rotation = .{ .X = rotation.x, .Y = rotation.y, .Z = rotation.z },
|
|
.scene_num_id = scene.data.current.level_id,
|
|
.hp = objects.items(.hp)[i],
|
|
};
|
|
|
|
switch (objects.items(.extra)[i]) {
|
|
.character => |extra| {
|
|
const template_id_num = objects.items(.template_id)[i];
|
|
const template_id = assets.numToStr(.char_id, template_id_num).?;
|
|
|
|
common_info.type = 0;
|
|
common_info.templateid = template_id;
|
|
|
|
var scene_char: pb.SCENE_CHARACTER = .{
|
|
.level = extra.level,
|
|
.common_info = common_info,
|
|
.battle_info = .{
|
|
.msg_generation = @intCast(net_id),
|
|
.battle_inst_id = @intCast(net_id),
|
|
.part_inst_info = .init,
|
|
.skill_list = try packCharacterSkills(arena.interface, assets, template_id),
|
|
},
|
|
};
|
|
|
|
const char_data = assets.table(.character).getPtr(template_id).?;
|
|
for (char_data.attributes[0].Attribute.attrs) |attr| {
|
|
try scene_char.attrs.append(arena.interface, .{
|
|
.attr_type = @intFromEnum(attr.attrType),
|
|
.basic_value = attr.attrValue,
|
|
.value = attr.attrValue,
|
|
});
|
|
}
|
|
|
|
try self_scene_info.detail.?.char_list.append(arena.interface, scene_char);
|
|
},
|
|
}
|
|
}
|
|
|
|
try session.send(self_scene_info);
|
|
}
|
|
|
|
fn packCharacterSkills(
|
|
arena: Allocator,
|
|
assets: *const Assets,
|
|
template_id: []const u8,
|
|
) Allocator.Error!ArrayList(pb.SERVER_SKILL) {
|
|
const char_skills = assets.char_skill_map.map.getPtr(template_id).?.all_skills;
|
|
var list: ArrayList(pb.SERVER_SKILL) = try .initCapacity(
|
|
arena,
|
|
char_skills.len + assets.common_skill_config.config.Character.skillConfigs.len,
|
|
);
|
|
|
|
errdefer comptime unreachable;
|
|
|
|
for (char_skills, 1..) |name, i| {
|
|
list.appendAssumeCapacity(.{
|
|
.skill_id = .{
|
|
.id_impl = .{ .str_id = name },
|
|
.type = .BATTLE_ACTION_OWNER_TYPE_SKILL,
|
|
},
|
|
.blackboard = .{},
|
|
.inst_id = (100 + i),
|
|
.level = 1,
|
|
.source = .BATTLE_SKILL_SOURCE_DEFAULT,
|
|
.potential_lv = 1,
|
|
.is_enable = true,
|
|
});
|
|
}
|
|
|
|
for (assets.common_skill_config.config.Character.skillConfigs, char_skills.len + 1..) |config, i| {
|
|
list.appendAssumeCapacity(.{
|
|
.skill_id = .{
|
|
.id_impl = .{ .str_id = config.skillId },
|
|
.type = .BATTLE_ACTION_OWNER_TYPE_SKILL,
|
|
},
|
|
.blackboard = .{},
|
|
.inst_id = (100 + i),
|
|
.level = 1,
|
|
.source = .BATTLE_SKILL_SOURCE_DEFAULT,
|
|
.potential_lv = 1,
|
|
.is_enable = true,
|
|
});
|
|
}
|
|
|
|
return list;
|
|
}
|