feat(scene): implement enemy spawn

This commit is contained in:
xeon
2026-02-08 18:42:48 +03:00
parent 1d25ab84af
commit e8e7fd9dd9
4 changed files with 104 additions and 0 deletions

View File

@@ -9,4 +9,27 @@ pub const WorldEntityBriefInfo = struct {
detailId: ?[]const u8, detailId: ?[]const u8,
position: logic.Level.Object.Vector, position: logic.Level.Object.Vector,
rotation: logic.Level.Object.Vector, rotation: logic.Level.Object.Vector,
pub fn objectType(info: WorldEntityBriefInfo) ObjectType {
return std.enums.fromInt(ObjectType, info.entityType) orelse .invalid;
}
};
pub const ObjectType = enum(u32) {
all = 4294967295,
invalid = 1,
character = 8,
enemy = 16,
interactive = 32,
projectile = 64,
factory_region = 128,
npc = 256,
ability_entity = 512,
cinematic_entity = 1024,
remote_factory_entity = 2048,
creature = 4096,
god_entity = 8192,
enemy_part = 16384,
social_building = 32768,
enemy_all = 16400,
}; };

View File

@@ -18,3 +18,5 @@ pub const SyncSelfScene = struct {
team_modified, team_modified,
}, },
}; };
pub const RefreshVisibleObjects = struct {};

View File

@@ -9,8 +9,10 @@ const Player = logic.Player;
pub fn onSceneLoadFinish( pub fn onSceneLoadFinish(
_: messaging.Request(pb.CS_SCENE_LOAD_FINISH), _: messaging.Request(pb.CS_SCENE_LOAD_FINISH),
sync_self_scene_tx: logic.event.Sender(.sync_self_scene), sync_self_scene_tx: logic.event.Sender(.sync_self_scene),
refresh_visible_objects_tx: logic.event.Sender(.refresh_visible_objects),
) !void { ) !void {
try sync_self_scene_tx.send(.{ .reason = .entrance }); try sync_self_scene_tx.send(.{ .reason = .entrance });
try refresh_visible_objects_tx.send(.{});
} }
pub fn onMoveObjectMove( pub fn onMoveObjectMove(

View File

@@ -202,6 +202,83 @@ pub fn syncSelfScene(
try session.send(self_scene_info); try session.send(self_scene_info);
} }
pub fn refreshVisibleObjects(
rx: logic.event.Receiver(.refresh_visible_objects),
session: *Session,
arena: logic.Resource.Allocator(.arena),
scene: Player.Component(.scene),
assets: *const Assets,
) !void {
const objects_per_message: usize = 128; // TODO(Session): message fragmentation.
_ = rx;
const level_id = scene.data.current.level_id;
var container: pb.SCENE_OBJECT_DETAIL_CONTAINER = .init;
const brief_map = &assets.world_entity_registry.worldEntityBriefInfos;
for (brief_map.map.keys(), brief_map.map.values()) |id, info| {
if (@divFloor(id, 100_000_000) != level_id)
continue;
if (info.objectType() != .enemy) continue;
const template_id = info.detailId orelse continue;
const enemy_attrs = assets.table(.enemy_attribute_template).getPtr(template_id) orelse continue;
const common_info: pb.SCENE_OBJECT_COMMON_INFO = .{
.id = id,
.type = 3,
.templateid = template_id,
.position = .{ .X = info.position.x, .Y = info.position.y, .Z = info.position.z },
.rotation = .{ .X = info.rotation.x, .Y = info.rotation.y, .Z = info.rotation.z },
.scene_num_id = level_id,
.hp = 100,
};
var monster: pb.SCENE_MONSTER = .{
.common_info = common_info,
.level = 1,
.battle_info = .{
.msg_generation = @truncate(id),
.battle_inst_id = @truncate(id),
.part_inst_info = .init,
},
};
for (enemy_attrs.levelDependentAttributes[0].attrs) |attr| {
try monster.attrs.append(arena.interface, .{
.attr_type = @intFromEnum(attr.attrType),
.basic_value = attr.attrValue,
.value = attr.attrValue,
});
}
for (enemy_attrs.levelIndependentAttributes.attrs) |attr| {
try monster.attrs.append(arena.interface, .{
.attr_type = @intFromEnum(attr.attrType),
.basic_value = attr.attrValue,
.value = attr.attrValue,
});
}
try container.monster_list.append(arena.interface, monster);
if (container.monster_list.items.len == objects_per_message) {
try session.send(pb.SC_OBJECT_ENTER_VIEW{
.detail = container,
});
container = .init;
}
}
if (container.monster_list.items.len != 0) {
try session.send(pb.SC_OBJECT_ENTER_VIEW{
.detail = container,
});
}
}
fn packCharacterSkills( fn packCharacterSkills(
arena: Allocator, arena: Allocator,
assets: *const Assets, assets: *const Assets,