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
// TODO: public LevelModelInfo[] ModelList { get; set; } // 0x58
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 LevelPathwayInfo[] PathwayList { get; set; } // 0x78
// 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 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;
AvatarType = type;

View file

@ -9,7 +9,7 @@ internal class EntityFactory
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)
@ -17,6 +17,11 @@ internal class EntityFactory
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()
{
_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.Factory;
using RPG.Services.Gameserver.Game.Team;
using RPG.Services.Gameserver.Game.Util;
using MazeInfo = RPG.Network.Proto.Maze;
namespace RPG.Services.Gameserver.Game.Maze;
internal class MazeManager
{
private readonly EntityManager _entityManager;
private readonly EntityFactory _entityFactory;
private readonly ExcelTables _excelTables;
@ -26,38 +26,35 @@ internal class MazeManager
private PlayerTeam? _playerTeam;
private uint _uid;
public EntityManager EntityManager { get; }
public MazeManager(EntityManager entityManager, EntityFactory entityFactory, ExcelTables excelTables, LevelTables levelTables)
{
_entityManager = entityManager;
EntityManager = entityManager;
_entityFactory = entityFactory;
_excelTables = excelTables;
_levelTables = levelTables;
}
public EntityBase? GetEntityById(uint entityId)
{
return _entityManager.GetEntityById(entityId);
}
public void ResetAvatarPosition()
{
foreach (TeamMember? member in _playerTeam!.Members)
{
if (member == null) continue;
AvatarEntity? entity = _entityManager.GetAvatar(_uid, member.AvatarId);
AvatarEntity? entity = EntityManager.GetAvatar(_uid, member.AvatarId);
if (entity != null)
{
entity.SetMotion(CreateInitialAvatarMotion());
_entityManager.NotifyUpdate(entity);
EntityManager.NotifyUpdate(entity);
}
}
}
public void RemoveEntities(IEnumerable<uint> entities)
{
_entityManager.RemoveEntities(entities);
EntityManager.RemoveEntities(entities);
}
public void SetPlayerUid(uint uid)
@ -104,7 +101,7 @@ internal class MazeManager
{
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()
{
@ -114,7 +111,7 @@ internal class MazeManager
LeaderEntityId = leaderEntity?.Id ?? 0,
};
info.EntityList.AddRange(_entityManager.EntityInfoList);
info.EntityList.AddRange(EntityManager.EntityInfoList);
return info;
}
@ -132,9 +129,19 @@ internal class MazeManager
if (!levelMonster.CreateOnInitial) continue;
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);
entity.SetMotion(CreateInitialAvatarMotion());
_entityManager.AddEntity(entity);
EntityManager.AddEntity(entity);
}
}
@ -157,29 +164,12 @@ internal class MazeManager
LevelGroupInfo startGroup = _levelTables.GetGroupInfo(_floor!.StartGroup.GroupGUID)!;
LevelAnchorInfo startAnchor = startGroup.AnchorList.First(anchor => anchor.ID == _floor.StartAnchorID);
return 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)
}
};
return MazeUtil.CreateDefaultMotion(startAnchor);
}
private void BeforeEnter()
{
_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);
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);
}
else if (_mazeManager.GetEntityById(req.AbilityTargetEntityId) is NpcMonsterEntity)
else if (_mazeManager.EntityManager.GetEntityById(req.AbilityTargetEntityId) is NpcMonsterEntity)
{
battleModule.OnSuccessfulAttack(req.AbilityTargetEntityId, req.AssistMonsterEntityIdList);
}

View file

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