Implement PropEntity spawn

This commit is contained in:
xeon 2024-01-25 13:55:10 +03:00
parent b093824270
commit 158e81be6b
10 changed files with 137 additions and 41 deletions

View file

@ -0,0 +1,7 @@
namespace RPG.GameCore.Level.Capture;
public class StageObjectCapture
{
public string BlockAlias { get; set; } = string.Empty; // 0x10
public string PrefabAlias { get; set; } = string.Empty; // 0x18
}

View file

@ -19,7 +19,7 @@ public class LevelGroupInfo
public LevelAnchorInfo[] AnchorList { get; set; } = []; // 0x50 public LevelAnchorInfo[] AnchorList { get; set; } = []; // 0x50
// TODO: public LevelModelInfo[] ModelList { get; set; } // 0x58 // TODO: public LevelModelInfo[] ModelList { get; set; } // 0x58
public LevelMonsterInfo[] MonsterList { get; set; } = []; // 0x60 public LevelMonsterInfo[] MonsterList { get; set; } = []; // 0x60
// TODO: public LevelPropInfo[] PropList { get; set; } // 0x68 public LevelPropInfo[] PropList { get; set; } = []; // 0x68
// TODO: public LevelWaypointInfo[] WaypointList { get; set; } // 0x70 // TODO: public LevelWaypointInfo[] WaypointList { get; set; } // 0x70
// TODO: public LevelPathwayInfo[] PathwayList { get; set; } // 0x78 // TODO: public LevelPathwayInfo[] PathwayList { get; set; } // 0x78
// TODO: public LevelBattleAreaInfo[] BattleAreaList { get; set; } // 0x80 // TODO: public LevelBattleAreaInfo[] BattleAreaList { get; set; } // 0x80

View file

@ -0,0 +1,35 @@
using RPG.GameCore.Enums;
using RPG.GameCore.Level.Capture;
using RPG.GameCore.Level.Graph;
using RPG.GameCore.Level.Trigger;
using System.Text.Json.Serialization;
namespace RPG.GameCore.Level.Objects;
public class LevelPropInfo : NamedLevelObjectInfo
{
public float RotX { get; set; } // 0x40
public float RotZ { get; set; } // 0x44
public uint PropID { get; set; } // 0x48
public bool IsLimitedLife { get; set; } // 0x4C
public float LifeTime { get; set; } // 0x50
public string InitLevelGraph { get; set; } = string.Empty; // 0x58
public LevelTriggerInfo? Trigger { get; set; } // 0x60
public bool CreateOnInitial { get; set; } // 0x68
public LevelGraphValueSource? ValueSource { get; set; } // 0x70
public uint CampID { get; set; } // 0x78
[JsonConverter(typeof(JsonStringEnumConverter))]
public PropState State { get; set; } // 0x7C
public uint RecordID { get; set; } // 0x80
public uint EventID { get; set; } // 0x84
public uint AnchorGroupID { get; set; } // 0x88
public uint AnchorID { get; set; } // 0x8C
public uint MapTeleportID { get; set; } // 0x90
public uint ChestID { get; set; } // 0x94
public uint DialogueTriggerAngle { get; set; } // 0x98
public uint[] DialogueGroups { get; set; } = []; // 0xA0
public bool OverrideTriggerHint { get; set; } // 0xA8
public float HintRange { get; set; } // 0xAC
public uint[] ServerInteractVerificationIDList { get; set; } = []; // 0xB0
public StageObjectCapture? StageObjectCapture { get; set; } // 0xB8
}

View file

@ -8,7 +8,7 @@ internal class AvatarEntity : EntityBase
public AvatarType AvatarType { get; } public AvatarType AvatarType { get; }
public uint Uid { get; } public uint Uid { get; }
public AvatarEntity(uint id, uint groupId, uint instanceId, uint avatarId, AvatarType type, uint uid) : base(id, groupId, instanceId) public AvatarEntity(uint id, uint avatarId, AvatarType type, uint uid) : base(id, 0, 0)
{ {
AvatarId = avatarId; AvatarId = avatarId;
AvatarType = type; AvatarType = type;

View file

@ -9,7 +9,7 @@ internal class EntityFactory
public AvatarEntity CreateAvatarEntity(uint avatarId, AvatarType type, uint uid) public AvatarEntity CreateAvatarEntity(uint avatarId, AvatarType type, uint uid)
{ {
return new(NextEntityId(), 0, 0, avatarId, type, uid); return new(NextEntityId(), avatarId, type, uid);
} }
public NpcMonsterEntity CreateNpcMonsterEntity(LevelMonsterInfo levelMonster, uint groupId) public NpcMonsterEntity CreateNpcMonsterEntity(LevelMonsterInfo levelMonster, uint groupId)
@ -17,6 +17,11 @@ internal class EntityFactory
return new(NextEntityId(), groupId, levelMonster.ID, levelMonster.NPCMonsterID, levelMonster.EventID); return new(NextEntityId(), groupId, levelMonster.ID, levelMonster.NPCMonsterID, levelMonster.EventID);
} }
public PropEntity CreatePropEntity(LevelPropInfo levelProp, uint groupId)
{
return new(NextEntityId(), groupId, levelProp.ID, levelProp);
}
public void Reset() public void Reset()
{ {
_entityIdSeed = 0; _entityIdSeed = 0;

View file

@ -0,0 +1,34 @@
using RPG.GameCore.Enums;
using RPG.GameCore.Level.Objects;
using RPG.Network.Proto;
namespace RPG.Services.Gameserver.Game.Entity;
internal class PropEntity : EntityBase
{
public uint PropId { get; }
public PropState State { get; set; }
public PropEntity(uint id, uint groupId, uint instanceId, LevelPropInfo info) : base(id, groupId, instanceId)
{
PropId = info.PropID;
State = info.State;
}
public override EntityType Type => EntityType.EntityProp;
public override SceneEntityInfo SceneEntityInfo
{
get
{
SceneEntityInfo info = base.SceneEntityInfo;
info.Prop = new()
{
PropId = PropId,
PropState = (uint)State
};
return info;
}
}
}

View file

@ -8,13 +8,13 @@ using RPG.Network.Proto;
using RPG.Services.Gameserver.Game.Entity; using RPG.Services.Gameserver.Game.Entity;
using RPG.Services.Gameserver.Game.Entity.Factory; using RPG.Services.Gameserver.Game.Entity.Factory;
using RPG.Services.Gameserver.Game.Team; using RPG.Services.Gameserver.Game.Team;
using RPG.Services.Gameserver.Game.Util;
using MazeInfo = RPG.Network.Proto.Maze; using MazeInfo = RPG.Network.Proto.Maze;
namespace RPG.Services.Gameserver.Game.Maze; namespace RPG.Services.Gameserver.Game.Maze;
internal class MazeManager internal class MazeManager
{ {
private readonly EntityManager _entityManager;
private readonly EntityFactory _entityFactory; private readonly EntityFactory _entityFactory;
private readonly ExcelTables _excelTables; private readonly ExcelTables _excelTables;
@ -26,38 +26,35 @@ internal class MazeManager
private PlayerTeam? _playerTeam; private PlayerTeam? _playerTeam;
private uint _uid; private uint _uid;
public EntityManager EntityManager { get; }
public MazeManager(EntityManager entityManager, EntityFactory entityFactory, ExcelTables excelTables, LevelTables levelTables) public MazeManager(EntityManager entityManager, EntityFactory entityFactory, ExcelTables excelTables, LevelTables levelTables)
{ {
_entityManager = entityManager; EntityManager = entityManager;
_entityFactory = entityFactory; _entityFactory = entityFactory;
_excelTables = excelTables; _excelTables = excelTables;
_levelTables = levelTables; _levelTables = levelTables;
} }
public EntityBase? GetEntityById(uint entityId)
{
return _entityManager.GetEntityById(entityId);
}
public void ResetAvatarPosition() public void ResetAvatarPosition()
{ {
foreach (TeamMember? member in _playerTeam!.Members) foreach (TeamMember? member in _playerTeam!.Members)
{ {
if (member == null) continue; if (member == null) continue;
AvatarEntity? entity = _entityManager.GetAvatar(_uid, member.AvatarId); AvatarEntity? entity = EntityManager.GetAvatar(_uid, member.AvatarId);
if (entity != null) if (entity != null)
{ {
entity.SetMotion(CreateInitialAvatarMotion()); entity.SetMotion(CreateInitialAvatarMotion());
_entityManager.NotifyUpdate(entity); EntityManager.NotifyUpdate(entity);
} }
} }
} }
public void RemoveEntities(IEnumerable<uint> entities) public void RemoveEntities(IEnumerable<uint> entities)
{ {
_entityManager.RemoveEntities(entities); EntityManager.RemoveEntities(entities);
} }
public void SetPlayerUid(uint uid) public void SetPlayerUid(uint uid)
@ -104,7 +101,7 @@ internal class MazeManager
{ {
if (_mapEntry == null || _playerTeam == null) throw new InvalidOperationException("GetSceneInfo: scene not loaded!"); if (_mapEntry == null || _playerTeam == null) throw new InvalidOperationException("GetSceneInfo: scene not loaded!");
AvatarEntity? leaderEntity = _entityManager.GetAvatar(_uid, _playerTeam.Leader.AvatarId); AvatarEntity? leaderEntity = EntityManager.GetAvatar(_uid, _playerTeam.Leader.AvatarId);
SceneInfo info = new() SceneInfo info = new()
{ {
@ -114,7 +111,7 @@ internal class MazeManager
LeaderEntityId = leaderEntity?.Id ?? 0, LeaderEntityId = leaderEntity?.Id ?? 0,
}; };
info.EntityList.AddRange(_entityManager.EntityInfoList); info.EntityList.AddRange(EntityManager.EntityInfoList);
return info; return info;
} }
@ -132,9 +129,19 @@ internal class MazeManager
if (!levelMonster.CreateOnInitial) continue; if (!levelMonster.CreateOnInitial) continue;
NpcMonsterEntity monsterEntity = _entityFactory.CreateNpcMonsterEntity(levelMonster, groupInstanceInfo.ID); NpcMonsterEntity monsterEntity = _entityFactory.CreateNpcMonsterEntity(levelMonster, groupInstanceInfo.ID);
monsterEntity.SetMotion(CreateDefaultMotion(levelMonster)); monsterEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelMonster));
_entityManager.AddEntity(monsterEntity); EntityManager.AddEntity(monsterEntity);
}
foreach (LevelPropInfo levelProp in levelGroup.PropList)
{
if (!levelProp.CreateOnInitial) continue;
PropEntity propEntity = _entityFactory.CreatePropEntity(levelProp, groupInstanceInfo.ID);
propEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelProp));
EntityManager.AddEntity(propEntity);
} }
} }
} }
@ -148,7 +155,7 @@ internal class MazeManager
AvatarEntity entity = _entityFactory.CreateAvatarEntity(member.AvatarId, member.AvatarType, _uid); AvatarEntity entity = _entityFactory.CreateAvatarEntity(member.AvatarId, member.AvatarType, _uid);
entity.SetMotion(CreateInitialAvatarMotion()); entity.SetMotion(CreateInitialAvatarMotion());
_entityManager.AddEntity(entity); EntityManager.AddEntity(entity);
} }
} }
@ -157,29 +164,12 @@ internal class MazeManager
LevelGroupInfo startGroup = _levelTables.GetGroupInfo(_floor!.StartGroup.GroupGUID)!; LevelGroupInfo startGroup = _levelTables.GetGroupInfo(_floor!.StartGroup.GroupGUID)!;
LevelAnchorInfo startAnchor = startGroup.AnchorList.First(anchor => anchor.ID == _floor.StartAnchorID); LevelAnchorInfo startAnchor = startGroup.AnchorList.First(anchor => anchor.ID == _floor.StartAnchorID);
return CreateDefaultMotion(startAnchor); return MazeUtil.CreateDefaultMotion(startAnchor);
}
private static MotionInfo CreateDefaultMotion(NamedLevelObjectInfo info)
{
return new()
{
Pos = new()
{
X = MathUtil.GetLogicCoordValue(info.PosX),
Y = MathUtil.GetLogicCoordValue(info.PosY),
Z = MathUtil.GetLogicCoordValue(info.PosZ)
},
Rot = new()
{
Y = MathUtil.GetLogicCoordValue(info.RotY)
}
};
} }
private void BeforeEnter() private void BeforeEnter()
{ {
_entityFactory.Reset(); _entityFactory.Reset();
_entityManager.Clear(); EntityManager.Clear();
} }
} }

View file

@ -0,0 +1,25 @@
using RPG.GameCore.Level.Objects;
using RPG.GameCore.Util;
using RPG.Network.Proto;
namespace RPG.Services.Gameserver.Game.Util;
internal static class MazeUtil
{
public static MotionInfo CreateDefaultMotion(NamedLevelObjectInfo info)
{
return new()
{
Pos = new()
{
X = MathUtil.GetLogicCoordValue(info.PosX),
Y = MathUtil.GetLogicCoordValue(info.PosY),
Z = MathUtil.GetLogicCoordValue(info.PosZ)
},
Rot = new()
{
Y = MathUtil.GetLogicCoordValue(info.RotY)
}
};
}
}

View file

@ -65,11 +65,11 @@ internal class AdventureModule : BaseModule
SceneCastSkillCsReq req = SceneCastSkillCsReq.Parser.ParseFrom(body.Span); SceneCastSkillCsReq req = SceneCastSkillCsReq.Parser.ParseFrom(body.Span);
BattleModule battleModule = ModuleManager.Get<BattleModule>(); BattleModule battleModule = ModuleManager.Get<BattleModule>();
if (_mazeManager.GetEntityById(req.CastEntityId) is NpcMonsterEntity) if (_mazeManager.EntityManager.GetEntityById(req.CastEntityId) is NpcMonsterEntity)
{ {
battleModule.OnBeingHitByMonster(req.CastEntityId, req.AssistMonsterEntityIdList); battleModule.OnBeingHitByMonster(req.CastEntityId, req.AssistMonsterEntityIdList);
} }
else if (_mazeManager.GetEntityById(req.AbilityTargetEntityId) is NpcMonsterEntity) else if (_mazeManager.EntityManager.GetEntityById(req.AbilityTargetEntityId) is NpcMonsterEntity)
{ {
battleModule.OnSuccessfulAttack(req.AbilityTargetEntityId, req.AssistMonsterEntityIdList); battleModule.OnSuccessfulAttack(req.AbilityTargetEntityId, req.AssistMonsterEntityIdList);
} }

View file

@ -72,14 +72,14 @@ internal class BattleModule : BaseModule
List<uint> battleEvents = []; List<uint> battleEvents = [];
if (_mazeManager.GetEntityById(monsterEntityId) is NpcMonsterEntity monster) if (_mazeManager.EntityManager.GetEntityById(monsterEntityId) is NpcMonsterEntity monster)
{ {
battleEvents.Add(monster.EventId); battleEvents.Add(monster.EventId);
} }
foreach (uint assistEntityId in assists) foreach (uint assistEntityId in assists)
{ {
if (_mazeManager.GetEntityById(assistEntityId) is NpcMonsterEntity assistMonster) if (_mazeManager.EntityManager.GetEntityById(assistEntityId) is NpcMonsterEntity assistMonster)
{ {
battleEvents.Add(assistMonster.EventId); battleEvents.Add(assistMonster.EventId);
} }