From 4d182852e530b9205bdd722efb2815fa70093d51 Mon Sep 17 00:00:00 2001 From: xeon Date: Thu, 25 Jan 2024 14:31:32 +0300 Subject: [PATCH] NPC spawn --- RPG.GameCore/Level/Group/LevelGroupInfo.cs | 2 +- RPG.GameCore/Level/Objects/LevelNPCInfo.cs | 23 ++++++++++++++ .../Game/Entity/Factory/EntityFactory.cs | 5 ++++ .../Game/Entity/NpcEntity.cs | 30 +++++++++++++++++++ .../Game/Maze/MazeManager.cs | 10 +++++++ .../Modules/AdventureModule.cs | 18 ++++++++++- 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 RPG.GameCore/Level/Objects/LevelNPCInfo.cs create mode 100644 RPG.Services.Gameserver/Game/Entity/NpcEntity.cs diff --git a/RPG.GameCore/Level/Group/LevelGroupInfo.cs b/RPG.GameCore/Level/Group/LevelGroupInfo.cs index a7f62c9..d68de2c 100644 --- a/RPG.GameCore/Level/Group/LevelGroupInfo.cs +++ b/RPG.GameCore/Level/Group/LevelGroupInfo.cs @@ -23,7 +23,7 @@ public class LevelGroupInfo // TODO: public LevelWaypointInfo[] WaypointList { get; set; } // 0x70 // TODO: public LevelPathwayInfo[] PathwayList { get; set; } // 0x78 // TODO: public LevelBattleAreaInfo[] BattleAreaList { get; set; } // 0x80 - // TODO: public LevelNPCInfo[] NPCList { get; set; } // 0x88 + public LevelNPCInfo[] NPCList { get; set; } = []; // 0x88 public uint GroupRefreshID { get; set; } // 0x90 // TODO: public RandomNPCMonsterInfo[] RandomNPCMonsterList { get; set; } // 0x98 public uint[] InitialRandomNPCMonsterIDList { get; set; } = []; // 0xA0 diff --git a/RPG.GameCore/Level/Objects/LevelNPCInfo.cs b/RPG.GameCore/Level/Objects/LevelNPCInfo.cs new file mode 100644 index 0000000..7b35ea5 --- /dev/null +++ b/RPG.GameCore/Level/Objects/LevelNPCInfo.cs @@ -0,0 +1,23 @@ +using RPG.GameCore.Level.AI; +using RPG.GameCore.Level.Graph; +using RPG.GameCore.Level.Trigger; + +namespace RPG.GameCore.Level.Objects; + +public class LevelNPCInfo : NamedLevelObjectInfo +{ + public uint NPCID { get; set; } // 0x40 + public string LevelGraph { get; set; } = string.Empty; // 0x48 + public bool CreateOnInitial { get; set; } // 0x50 + public LevelGraphValueSource? ValueSource { get; set; } // 0x58 + public uint CampID { get; set; } // 0x60 + public LevelTriggerInfo? Trigger { get; set; } // 0x68 + public AIConfigInfo? AIConfig { get; set; } // 0x70 + public uint RecordID { get; set; } // 0x78 + public uint EventID { get; set; } // 0x7C + public bool Stable { get; set; } // 0x80 + public uint DialogueTriggerAngle { get; set; } // 0x84 + public uint[] DialogueGroups { get; set; } = []; // 0x88 + public uint[] ServerInteractVerificationIDList { get; set; } = []; // 0x90 + public string DefaultIdleStateName { get; set; } = string.Empty; // 0x98 +} diff --git a/RPG.Services.Gameserver/Game/Entity/Factory/EntityFactory.cs b/RPG.Services.Gameserver/Game/Entity/Factory/EntityFactory.cs index c627a66..0ab5c33 100644 --- a/RPG.Services.Gameserver/Game/Entity/Factory/EntityFactory.cs +++ b/RPG.Services.Gameserver/Game/Entity/Factory/EntityFactory.cs @@ -22,6 +22,11 @@ internal class EntityFactory return new(NextEntityId(), groupId, levelProp.ID, levelProp); } + public NpcEntity CreateNpcEntity(LevelNPCInfo levelNPC, uint groupId) + { + return new(NextEntityId(), groupId, levelNPC.ID, levelNPC); + } + public void Reset() { _entityIdSeed = 0; diff --git a/RPG.Services.Gameserver/Game/Entity/NpcEntity.cs b/RPG.Services.Gameserver/Game/Entity/NpcEntity.cs new file mode 100644 index 0000000..c3a34eb --- /dev/null +++ b/RPG.Services.Gameserver/Game/Entity/NpcEntity.cs @@ -0,0 +1,30 @@ +using RPG.GameCore.Level.Objects; +using RPG.Network.Proto; + +namespace RPG.Services.Gameserver.Game.Entity; + +internal class NpcEntity : EntityBase +{ + public uint NpcId { get; } + + public NpcEntity(uint id, uint groupId, uint instanceId, LevelNPCInfo info) : base(id, groupId, instanceId) + { + NpcId = info.NPCID; + } + + public override EntityType Type => EntityType.EntityNpc; + + public override SceneEntityInfo SceneEntityInfo + { + get + { + SceneEntityInfo info = base.SceneEntityInfo; + info.Npc = new() + { + NpcId = NpcId + }; + + return info; + } + } +} diff --git a/RPG.Services.Gameserver/Game/Maze/MazeManager.cs b/RPG.Services.Gameserver/Game/Maze/MazeManager.cs index 739f253..2b95825 100644 --- a/RPG.Services.Gameserver/Game/Maze/MazeManager.cs +++ b/RPG.Services.Gameserver/Game/Maze/MazeManager.cs @@ -143,6 +143,16 @@ internal class MazeManager EntityManager.AddEntity(propEntity); } + + foreach (LevelNPCInfo levelNPC in levelGroup.NPCList) + { + if (!levelNPC.CreateOnInitial) continue; + + NpcEntity npcEntity = _entityFactory.CreateNpcEntity(levelNPC, groupInstanceInfo.ID); + npcEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelNPC)); + + EntityManager.AddEntity(npcEntity); + } } } diff --git a/RPG.Services.Gameserver/Modules/AdventureModule.cs b/RPG.Services.Gameserver/Modules/AdventureModule.cs index eb0bd49..386efe2 100644 --- a/RPG.Services.Gameserver/Modules/AdventureModule.cs +++ b/RPG.Services.Gameserver/Modules/AdventureModule.cs @@ -1,4 +1,5 @@ -using RPG.GameCore.Excel; +using RPG.GameCore.Enums; +using RPG.GameCore.Excel; using RPG.Network.Proto; using RPG.Services.Gameserver.Game.Entity; using RPG.Services.Gameserver.Game.Maze; @@ -59,6 +60,21 @@ internal class AdventureModule : BaseModule _mazeManager.ResetAvatarPosition(); } + [OnCommand(CmdType.CmdInteractPropCsReq)] + public Task OnCmdInteractPropCsReq(PlayerSession session, ReadOnlyMemory body) + { + InteractPropCsReq req = InteractPropCsReq.Parser.ParseFrom(body.Span); + // TODO: interact logic + + Send(session, CmdType.CmdInteractPropScRsp, new InteractPropScRsp + { + PropEntityId = req.PropEntityId, + Retcode = 0 + }); + + return Task.CompletedTask; + } + [OnCommand(CmdType.CmdSceneCastSkillCsReq)] public Task OnCmdSceneCastSkillCsReq(PlayerSession session, ReadOnlyMemory body) {