diff --git a/CScape.Core/Commands/TestCommandClass.cs b/CScape.Core/Commands/TestCommandClass.cs index 89b6ca5..b26786b 100644 --- a/CScape.Core/Commands/TestCommandClass.cs +++ b/CScape.Core/Commands/TestCommandClass.cs @@ -155,8 +155,10 @@ public void SpawnNpc(CommandContext ctx) var factory = ctx.Callee.Parent.Server.Services.ThrowOrGet(); var npc = factory.Create("Spanwed NPC", defId); + + npc.Get().GetTransform().Teleport(ctx.Callee.Parent.GetTransform()); - ctx.Callee.Parent.SystemMessage($"Spawned NPC. Intance ID: {npc.Get().AssertGetNpc().NpcId}", CoreSystemMessageFlags.Debug | CoreSystemMessageFlags.Entity); + ctx.Callee.Parent.SystemMessage($"Spawned NPC. Intance ID: {npc.Get().AssertGetNpc().InstanceId}", CoreSystemMessageFlags.Debug | CoreSystemMessageFlags.Entity); } [CommandMethod("clearinv")] diff --git a/CScape.Core/Game/Entity/Component/NpcComponent.cs b/CScape.Core/Game/Entity/Component/NpcComponent.cs index ab358c8..937bffd 100644 --- a/CScape.Core/Game/Entity/Component/NpcComponent.cs +++ b/CScape.Core/Game/Entity/Component/NpcComponent.cs @@ -13,7 +13,7 @@ public class NpcComponent : EntityComponent, INpcComponent public override int Priority => (int)ComponentPriority.Npc; public short DefinitionId { get; private set; } - public short NpcId { get; } + public short InstanceId { get; } public NpcComponent( IEntity parent, @@ -24,7 +24,7 @@ public NpcComponent( { _destroyCallback = destroyCallback; DefinitionId = defId; - NpcId = npcId; + InstanceId = npcId; } public void ChangeDefinitionId(short newId) @@ -46,6 +46,6 @@ public override void ReceiveMessage(IGameMessage msg) } public override string ToString() - => $"Npc {NpcId} def-id {DefinitionId}"; + => $"Npc {InstanceId} def-id {DefinitionId}"; } } \ No newline at end of file diff --git a/CScape.Core/Game/Entity/Component/PlayerComponent.cs b/CScape.Core/Game/Entity/Component/PlayerComponent.cs index 101bb7e..1ec469e 100644 --- a/CScape.Core/Game/Entity/Component/PlayerComponent.cs +++ b/CScape.Core/Game/Entity/Component/PlayerComponent.cs @@ -29,7 +29,7 @@ public enum Title : byte public const int MaxUsernameChars = 12; public const int MaxPasswordChars = 64; - public int PlayerId { get; } + public int InstanceId { get; } public PlayerAppearance Apperance { get; private set; } @@ -49,7 +49,7 @@ public PlayerComponent( PlayerAppearance appearance, bool isMember, int titleId, - int playerId, + int instanceId, [CanBeNull] Action destroyCallback) :base(parent) { @@ -61,7 +61,7 @@ public PlayerComponent( } _destroyCallback = destroyCallback ?? throw new ArgumentNullException(nameof(destroyCallback)); - PlayerId = playerId; + InstanceId = instanceId; TitleId = titleId; IsMember = isMember; Username = username; @@ -80,7 +80,7 @@ private void InitPlayer() var net = Parent.GetNetwork(); if (net != null) { - net.SendPacket(new InitializePlayerPacket(PlayerId, IsMember)); + net.SendPacket(new InitializePlayerPacket(InstanceId, IsMember)); // TODO : delegate the retrieval of SetPlayerOptionPacket to the current Region net.SendPacket(SetPlayerOptionPacket.Follow); net.SendPacket(SetPlayerOptionPacket.TradeWith); @@ -199,7 +199,7 @@ public override bool Equals(object obj) public override string ToString() { - return $"Player \"{Username}\" PID: {PlayerId})"; + return $"Player \"{Username}\" PID: {InstanceId})"; } public override int GetHashCode() diff --git a/CScape.Core/Game/Entity/Factory/NpcFactory.cs b/CScape.Core/Game/Entity/Factory/NpcFactory.cs index a38686c..c7b5646 100644 --- a/CScape.Core/Game/Entity/Factory/NpcFactory.cs +++ b/CScape.Core/Game/Entity/Factory/NpcFactory.cs @@ -44,6 +44,7 @@ public IEntityHandle Create(string name, int definitionId) ent.Components.Add(new MovementActionComponent(ent)); ent.Components.Add(new TileMovementComponent(ent)); + ent.Components.Add(new FlagAccumulatorComponent(ent)); // TODO : set npc health according to it's definition when creating the npc. var health = new HealthComponent(ent); @@ -67,8 +68,8 @@ public IEntityHandle Create(string name, int definitionId) private void DestroyCallback(NpcComponent npc) { - _log.Normal(this, $"Freeing npc slot {npc.NpcId} named {npc.Parent.Name}"); - InstanceLookup[npc.NpcId] = null; + _log.Normal(this, $"Freeing npc slot {npc.InstanceId} named {npc.Parent.Name}"); + InstanceLookup[npc.InstanceId] = null; } public IEntityHandle Get(int id) => GetById(id); diff --git a/CScape.Core/Game/Entity/Factory/PlayerFactory.cs b/CScape.Core/Game/Entity/Factory/PlayerFactory.cs index b04790b..ac5da81 100644 --- a/CScape.Core/Game/Entity/Factory/PlayerFactory.cs +++ b/CScape.Core/Game/Entity/Factory/PlayerFactory.cs @@ -173,9 +173,9 @@ private void DestroyCallback([NotNull] PlayerComponent component) { if (component == null) throw new ArgumentNullException(nameof(component)); - Log.Normal(this, $"Freeing player slot {component.PlayerId} {component.Username}"); + Log.Normal(this, $"Freeing player slot {component.InstanceId} {component.Username}"); - InstanceLookup[component.PlayerId] = null; + InstanceLookup[component.InstanceId] = null; _usernameLookup.Remove(component.Username); NumAlivePlayers--; diff --git a/CScape.Core/Game/Entity/InteractingEntity/NpcInteractingEntity.cs b/CScape.Core/Game/Entity/InteractingEntity/NpcInteractingEntity.cs index acc457d..aa2c01d 100644 --- a/CScape.Core/Game/Entity/InteractingEntity/NpcInteractingEntity.cs +++ b/CScape.Core/Game/Entity/InteractingEntity/NpcInteractingEntity.cs @@ -14,7 +14,7 @@ public class NpcInteractingEntity : IInteractingEntity public NpcInteractingEntity([NotNull] INpcComponent npc) { Entity = npc.Parent.Handle ?? throw new ArgumentNullException(nameof(npc)); - Id = npc.NpcId; + Id = npc.InstanceId; } } } \ No newline at end of file diff --git a/CScape.Core/Game/Entity/InteractingEntity/PlayerInteractingEntity.cs b/CScape.Core/Game/Entity/InteractingEntity/PlayerInteractingEntity.cs index 829f92d..d00eb41 100644 --- a/CScape.Core/Game/Entity/InteractingEntity/PlayerInteractingEntity.cs +++ b/CScape.Core/Game/Entity/InteractingEntity/PlayerInteractingEntity.cs @@ -14,7 +14,7 @@ public class PlayerInteractingEntity : IInteractingEntity public PlayerInteractingEntity([NotNull] IPlayerComponent player) { Entity = player.Parent.Handle; - Id = (short) (player.PlayerId + 32769); + Id = (short) (player.InstanceId + 32769); } } } \ No newline at end of file diff --git a/CScape.Core/Network/Entity/Component/EntityNetworkSyncComponent.cs b/CScape.Core/Network/Entity/Component/EntityNetworkSyncComponent.cs index ba92140..49a443e 100644 --- a/CScape.Core/Network/Entity/Component/EntityNetworkSyncComponent.cs +++ b/CScape.Core/Network/Entity/Component/EntityNetworkSyncComponent.cs @@ -56,8 +56,10 @@ private void RemoveEntity([NotNull] IEntityHandle ent) protected abstract bool IsHandleableEntity(IEntityHandle h); protected IUpdateSegment CommonSegmentResolve( - FlagAccumulatorComponent flags, bool needsUpdate) + [NotNull] FlagAccumulatorComponent flags, + bool needsUpdate) { + if (flags == null) throw new ArgumentNullException(nameof(flags)); if (flags.Movement != null) { @@ -82,9 +84,12 @@ protected IUpdateSegment CommonSegmentResolve( protected IEnumerable GetSyncSegments( - IList updateSegments, - Func updateWriterFactory) + [NotNull] IList updateSegments, + [NotNull] Func updateWriterFactory) { + if (updateSegments == null) throw new ArgumentNullException(nameof(updateSegments)); + if (updateWriterFactory == null) throw new ArgumentNullException(nameof(updateWriterFactory)); + var removeList = new List(); var syncSegments = new List(); @@ -138,9 +143,14 @@ protected IEnumerable GetSyncSegments( protected abstract void SetInitialFlags(IUpdateWriter writer, IEntity ent); protected IEnumerable GetInitSegments( - IList updateSegments, - Func updateWriterFactory) + [NotNull] IList updateSegments, + [NotNull] Func updateWriterFactory, + [NotNull] Func<(bool needsUpdate, IEntity entityToBeInitialized), IUpdateSegment> initSegmentFactory) { + if (updateSegments == null) throw new ArgumentNullException(nameof(updateSegments)); + if (updateWriterFactory == null) throw new ArgumentNullException(nameof(updateWriterFactory)); + if (initSegmentFactory == null) throw new ArgumentNullException(nameof(initSegmentFactory)); + var init = new List(); /* Initialize */ @@ -156,7 +166,7 @@ protected IEnumerable GetInitSegments( var needsUpd = updater.NeedsUpdate(); - init.Add(new InitPlayerSegment(entity.AssertGetPlayer(), Parent.AssertGetPlayer(), needsUpd)); + init.Add(initSegmentFactory((needsUpd, entity))); if (needsUpd) { diff --git a/CScape.Core/Network/Entity/Component/NpcNetworkSyncComponent.cs b/CScape.Core/Network/Entity/Component/NpcNetworkSyncComponent.cs index 154f483..9053bd1 100644 --- a/CScape.Core/Network/Entity/Component/NpcNetworkSyncComponent.cs +++ b/CScape.Core/Network/Entity/Component/NpcNetworkSyncComponent.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using CScape.Core.Extensions; -using CScape.Core.Game.Entities; using CScape.Core.Game.Entity.Component; using CScape.Core.Network.Entity.Flag; +using CScape.Core.Network.Entity.Segment; using CScape.Core.Network.Packet; using CScape.Models.Extensions; using CScape.Models.Game.Entity; @@ -37,7 +37,7 @@ protected override void Sync() var updates = new List(); var sync = GetSyncSegments(updates, f => new NpcUpdateWriter(f)); - var init = GetInitSegments(updates, f => new NpcUpdateWriter(f)); + var init = CreateNpcInitSegments(updates); Parent.AssertGetNetwork().SendPacket( new NpcUpdatePacket( @@ -45,5 +45,21 @@ protected override void Sync() init, updates)); } + + private IEnumerable CreateNpcInitSegments(List updates) + { + IUpdateWriter UpdateWriterFactory(FlagAccumulatorComponent f) + { + return new NpcUpdateWriter(f); + } + + IUpdateSegment InitSegmentFactory((bool needsUpdate, IEntity entityToBeInitialized) data) + { + return new InitNpcSegment(data.entityToBeInitialized.AssertGetNpc(), Parent, data.needsUpdate); + } + + var init = GetInitSegments(updates, UpdateWriterFactory, InitSegmentFactory); + return init; + } } } diff --git a/CScape.Core/Network/Entity/Component/PlayerNetworkSyncComponent.cs b/CScape.Core/Network/Entity/Component/PlayerNetworkSyncComponent.cs index 198cc91..323b480 100644 --- a/CScape.Core/Network/Entity/Component/PlayerNetworkSyncComponent.cs +++ b/CScape.Core/Network/Entity/Component/PlayerNetworkSyncComponent.cs @@ -1,12 +1,10 @@ using System.Collections.Generic; using CScape.Core.Game.Entity.Component; -using CScape.Core.Game.Entity.Message; using CScape.Core.Network.Entity.Flag; using CScape.Core.Network.Entity.Segment; using CScape.Core.Network.Packet; using CScape.Models.Extensions; using CScape.Models.Game.Entity; -using CScape.Models.Game.Message; namespace CScape.Core.Network.Entity.Component { @@ -46,27 +44,10 @@ protected override void Sync() { var updates = new List(); - /* Local */ - IUpdateSegment local; - { - var flags = Parent.Components.AssertGet(); - var updater = new LocalPlayerUpdateWriter(flags); - var needsUpdate = updater.NeedsUpdate(); - - if (flags.Reinitialize) - { - local = new LocalPlayerInitSegment(Parent.AssertGetPlayer(), needsUpdate); - } - else - local = CommonSegmentResolve(flags, needsUpdate); - - if (needsUpdate) - updates.Add(updater); - } - + var local = CreateUpdateSegmentForParent(updates); var sync = GetSyncSegments(updates, f => new PlayerUpdateWriter(f)); - var init = GetInitSegments(updates, f => new PlayerUpdateWriter(f)); + var init = CreatePlayerInitSegments(updates); /* Send packet */ Parent.Components.AssertGet().SendPacket( @@ -77,5 +58,40 @@ protected override void Sync() updates)); } + private IEnumerable CreatePlayerInitSegments(List updates) + { + IUpdateWriter UpdateWriterFactory(FlagAccumulatorComponent f) => new PlayerUpdateWriter(f); + + IUpdateSegment InitSegmentFactory((bool needsUpdate, IEntity entityToBeInitialized) data) + => new InitPlayerSegment(data.entityToBeInitialized.AssertGetPlayer(), Parent.AssertGetPlayer(), + data.needsUpdate); + + var init = GetInitSegments(updates, + UpdateWriterFactory, + InitSegmentFactory); + + return init; + } + + private IUpdateSegment CreateUpdateSegmentForParent(List updates) + { + IUpdateSegment local; + + var flags = Parent.Components.AssertGet(); + var updater = new LocalPlayerUpdateWriter(flags); + var needsUpdate = updater.NeedsUpdate(); + + if (flags.Reinitialize) + { + local = new LocalPlayerInitSegment(Parent.AssertGetPlayer(), needsUpdate); + } + else + local = CommonSegmentResolve(flags, needsUpdate); + + if (needsUpdate) + updates.Add(updater); + + return local; + } } } \ No newline at end of file diff --git a/CScape.Core/Network/Entity/Segment/InitNpcSegment.cs b/CScape.Core/Network/Entity/Segment/InitNpcSegment.cs new file mode 100644 index 0000000..f75c7e1 --- /dev/null +++ b/CScape.Core/Network/Entity/Segment/InitNpcSegment.cs @@ -0,0 +1,49 @@ +using System; +using CScape.Core.Game.Entities; +using CScape.Models.Extensions; +using CScape.Models.Game.Entity; +using JetBrains.Annotations; + +namespace CScape.Core.Network.Entity.Segment +{ + public sealed class InitNpcSegment : IUpdateSegment + { + private readonly bool _needsUpdate; + private readonly int _npcInstanceId; + private readonly int _yDelta; + private readonly int _xDelta; + private readonly int _definitionId; + + public InitNpcSegment( + [NotNull] INpcComponent npc, + [NotNull] IEntity observerEntity, + bool needsUpdate) + { + if (npc == null) throw new ArgumentNullException(nameof(npc)); + if (observerEntity == null) throw new ArgumentNullException(nameof(observerEntity)); + + var observerTransform = observerEntity.GetTransform(); + var npcTransform = npc.Parent.GetTransform(); + + _yDelta = npcTransform.Y - observerTransform.Y; + _xDelta = npcTransform.X - observerTransform.X; + + _npcInstanceId = npc.InstanceId; + _needsUpdate = needsUpdate; + _definitionId = npc.DefinitionId; + } + + public void Write(OutBlob stream) + { + stream.WriteBits(14, _npcInstanceId); + + stream.WriteBits(5, _yDelta); + stream.WriteBits(5, _xDelta); + + stream.WriteBits(1, 1); // setpos?? flag // todo : setpos flag + stream.WriteBits(12, _definitionId); + stream.WriteBits(1, _needsUpdate ? 1 : 0); + + } + } +} \ No newline at end of file diff --git a/CScape.Core/Network/Entity/Segment/InitPlayerSegment.cs b/CScape.Core/Network/Entity/Segment/InitPlayerSegment.cs index dadf0d2..d799c76 100644 --- a/CScape.Core/Network/Entity/Segment/InitPlayerSegment.cs +++ b/CScape.Core/Network/Entity/Segment/InitPlayerSegment.cs @@ -16,7 +16,7 @@ public InitPlayerSegment( [NotNull] IPlayerComponent newPlayer, [NotNull] IPlayerComponent localPlayer, bool needsUpdate) { - _pid = newPlayer.PlayerId; + _pid = newPlayer.InstanceId; _needsUpdate = needsUpdate; _xdelta = newPlayer.Parent.GetTransform().X - localPlayer.Parent.GetTransform().X; _ydelta = newPlayer.Parent.GetTransform().Y - localPlayer.Parent.GetTransform().Y; diff --git a/CScape.Models/Game/Entity/Component/INpcComponent.cs b/CScape.Models/Game/Entity/Component/INpcComponent.cs index 32bfea8..2e30716 100644 --- a/CScape.Models/Game/Entity/Component/INpcComponent.cs +++ b/CScape.Models/Game/Entity/Component/INpcComponent.cs @@ -12,7 +12,7 @@ public interface INpcComponent : IEntityComponent /// /// The instance id of the npc. /// - short NpcId { get; } + short InstanceId { get; } /// /// Changes the definition id of the npc. diff --git a/CScape.Models/Game/Entity/Component/IPlayerComponent.cs b/CScape.Models/Game/Entity/Component/IPlayerComponent.cs index 57ecab8..6f5c528 100644 --- a/CScape.Models/Game/Entity/Component/IPlayerComponent.cs +++ b/CScape.Models/Game/Entity/Component/IPlayerComponent.cs @@ -7,7 +7,7 @@ public interface IPlayerComponent : IEquatable, IEquatable /// The instance id of the player. /// - int PlayerId { get; } + int InstanceId { get; } /// /// The implementation specific id of the player's title. diff --git a/Tests/CoreTests/Handler/FollowPacketHandlerTests.cs b/Tests/CoreTests/Handler/FollowPacketHandlerTests.cs index b29ead2..95d7ffe 100644 --- a/Tests/CoreTests/Handler/FollowPacketHandlerTests.cs +++ b/Tests/CoreTests/Handler/FollowPacketHandlerTests.cs @@ -45,7 +45,7 @@ public void ValidTarget() var (s, p, h) = Data(); var target = Mock.Player("follow target", s).Get(); - Exec(p, h, (short)target.AssertGetPlayer().PlayerId); + Exec(p, h, (short)target.AssertGetPlayer().InstanceId); Validate(p, target); } @@ -73,7 +73,7 @@ public void FollowSelf() { var d = Data(); - ExecInvalidTarget(d, (short)d.Item2.AssertGetPlayer().PlayerId); + ExecInvalidTarget(d, (short)d.Item2.AssertGetPlayer().InstanceId); } } } diff --git a/Tests/CoreTests/Handler/TalkToPacketHandlerTests.cs b/Tests/CoreTests/Handler/TalkToPacketHandlerTests.cs index 241ea25..6ab87f3 100644 --- a/Tests/CoreTests/Handler/TalkToPacketHandlerTests.cs +++ b/Tests/CoreTests/Handler/TalkToPacketHandlerTests.cs @@ -19,7 +19,7 @@ public void ValidNpc() var h = new TalkToPacketHandler(server.Services); var b = new Blob(sizeof(short)); - b.Write16(npc.AssertGetNpc().NpcId); + b.Write16(npc.AssertGetNpc().InstanceId); h.HandleAll(p, o => PacketMessage.Success((byte)o, b)); }