diff --git a/Engine/Client/Client.csproj b/Engine/Client/Client.csproj
index 0913d7e..6d84b08 100644
--- a/Engine/Client/Client.csproj
+++ b/Engine/Client/Client.csproj
@@ -11,6 +11,18 @@
+
+
+ ..\Dependencies\BEPUutilities.dll
+
+
+ ..\Dependencies\Entitas.dll
+
+
+ ..\Dependencies\FixMath.NET.dll
+
+
+
diff --git a/Unity/Assets/Scripts/Commands/NavigateCommand.cs b/Engine/Client/Commands/NavigateCommand.cs
similarity index 87%
rename from Unity/Assets/Scripts/Commands/NavigateCommand.cs
rename to Engine/Client/Commands/NavigateCommand.cs
index ff7c4f3..2142c68 100644
--- a/Unity/Assets/Scripts/Commands/NavigateCommand.cs
+++ b/Engine/Client/Commands/NavigateCommand.cs
@@ -1,9 +1,11 @@
-using BEPUutilities;
-using Lockstep.Client.Interfaces;
+using System;
+using BEPUutilities;
+using Lockstep.Client.Interfaces;
using Lockstep.Network.Utils;
-namespace Lockstep.Commands
+namespace Lockstep.Client.Commands
{
+ [Serializable]
public class NavigateCommand : ISerializableCommand
{
public ushort Tag => 1;
diff --git a/Unity/Assets/Scripts/Commands/SpawnCommand.cs b/Engine/Client/Commands/SpawnCommand.cs
similarity index 90%
rename from Unity/Assets/Scripts/Commands/SpawnCommand.cs
rename to Engine/Client/Commands/SpawnCommand.cs
index afbf829..41ed269 100644
--- a/Unity/Assets/Scripts/Commands/SpawnCommand.cs
+++ b/Engine/Client/Commands/SpawnCommand.cs
@@ -1,9 +1,11 @@
-using BEPUutilities;
+using System;
+using BEPUutilities;
using Lockstep.Client.Interfaces;
using Lockstep.Network.Utils;
-namespace Lockstep.Commands
+namespace Lockstep.Client.Commands
{
+ [Serializable]
public class SpawnCommand : ISerializableCommand
{
public ushort Tag => 2;
diff --git a/Engine/Client/Implementations/NetworkCommandBuffer.cs b/Engine/Client/Implementations/NetworkCommandBuffer.cs
index fbf5a7f..53fab91 100644
--- a/Engine/Client/Implementations/NetworkCommandBuffer.cs
+++ b/Engine/Client/Implementations/NetworkCommandBuffer.cs
@@ -9,10 +9,10 @@
namespace Lockstep.Client.Implementations
{
- public class NetworkCommandBuffer : CommandBuffer
+ public sealed class NetworkCommandBuffer : CommandBuffer
{
- //TODO: refactor: don't receive meta information through commandbuffer
- public event Action InitReceived;
+ //TODO: refactor: don't do meta stuff through commandbuffer just because it has INetwork
+ public event Action InitReceived;
private readonly INetwork _network;
private readonly IDictionary> _commandFactories = new Dictionary>();
@@ -28,7 +28,7 @@ public void RegisterCommand(Func commandFactory)
var tag = commandFactory.Invoke().Tag;
if (_commandFactories.ContainsKey(tag))
{
- throw new InvalidDataException("The command tag " + tag + " is already registered. Every command tag must be unique.");
+ throw new InvalidDataException($"The command tag {tag} is already registered. Every command tag must be unique.");
}
_commandFactories.Add(tag, commandFactory);
}
@@ -51,7 +51,8 @@ public override void Insert(uint frameNumber, byte commanderId, ICommand[] comma
}
_network.Send(Compressor.Compress(writer));
- }
+ }
+
private void OnDataReceived(byte[] data)
{
diff --git a/Engine/Client/Interfaces/ICommandBuffer.cs b/Engine/Client/Interfaces/ICommandBuffer.cs
deleted file mode 100644
index 86554a0..0000000
--- a/Engine/Client/Interfaces/ICommandBuffer.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-using Lockstep.Core.Interfaces;
-
-namespace Lockstep.Client.Interfaces
-{
- public interface ICommandBuffer
- {
- uint LastInsertedFrame { get; }
-
- void Insert(uint frame, byte commanderId, ICommand[] commands);
-
- Dictionary> Get(uint frame);
- }
-}
\ No newline at end of file
diff --git a/Engine/Client/Simulation.cs b/Engine/Client/Simulation.cs
index 29d0020..97fac90 100644
--- a/Engine/Client/Simulation.cs
+++ b/Engine/Client/Simulation.cs
@@ -1,8 +1,10 @@
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
-using Lockstep.Client.Interfaces;
+using Lockstep.Client.Interfaces;
using Lockstep.Core.Interfaces;
using Lockstep.Network.Messages;
+using Lockstep.Network.Utils;
namespace Lockstep.Client
{
@@ -20,8 +22,7 @@ public class Simulation
public byte LocalPlayerId { get; private set; }
private float _tickDt;
- private float _accumulatedTime;
- private uint _lastValidatedFrame;
+ private float _accumulatedTime;
private readonly IWorld _world;
private readonly ICommandBuffer _remoteCommandBuffer;
@@ -51,6 +52,13 @@ public void Execute(ICommand command)
return;
}
+ if (command is ISerializableCommand s)
+ {
+ var er = new Serializer();
+ s.Serialize(er);
+ s.Deserialize(new Deserializer(er.Data));
+ }
+
lock (_commandCache)
{
_commandCache.Add(command);
@@ -97,35 +105,24 @@ private void Tick()
private void SyncCommandBuffer()
{
- var currentRemoteFrame = _remoteCommandBuffer.LastInsertedFrame;
+ var commands = _remoteCommandBuffer.GetChanges();
- if (_lastValidatedFrame < currentRemoteFrame)
+ if (commands.Count > 0)
{
//We guess everything was predicted correctly (except the last received frame)
- var firstMispredictedFrame = currentRemoteFrame;
-
- for (var remoteFrame = _lastValidatedFrame + 1; remoteFrame <= currentRemoteFrame; remoteFrame++)
- {
- //All frames that have no commands were predicted correctly => increase remote frame
- var allPlayerCommands = _remoteCommandBuffer.Get(remoteFrame);
- if (allPlayerCommands.Count == 0)
- {
- continue;
- }
+ var firstMispredictedFrame = commands.Keys.Min();
+ var lastInputFrame = commands.Keys.Max();
- if (firstMispredictedFrame > remoteFrame)
- {
- //Set the first mispredicted frame to the first frame which contains commands
- firstMispredictedFrame = remoteFrame;
- }
- //TODO: if command contains entity-ids (which can be predicted) and due to rollback->fast-forward we generated local ids, the command's entity-ids have to be adjusted
- //https://github.com/proepkes/UnityLockstep/wiki/Rollback-devlog
- foreach (var playerCommands in allPlayerCommands)
+ _world.Services.Get().Trace(">>>Input from " + firstMispredictedFrame + " to " + lastInputFrame);
+
+ foreach (var tick in commands.Keys)
+ {
+ foreach (var actorId in commands[tick].Keys)
{
- _world.AddInput(remoteFrame, playerCommands.Key, playerCommands.Value);
+ _world.AddInput(tick, actorId, commands[tick][actorId]);
}
- }
+ }
//Only rollback if the mispredicted frame was in the past (the frame can be in the future due to high lag compensation)
if (firstMispredictedFrame <= _world.CurrentTick)
@@ -134,19 +131,20 @@ private void SyncCommandBuffer()
_world.RevertToTick(firstMispredictedFrame);
- while (_world.CurrentTick < firstMispredictedFrame)
+ //Restore last local state
+ while (_world.CurrentTick <= lastInputFrame)
{
_world.Simulate();
}
-
- //Restore last local state
+
+ _world.Services.Get().Trace(">>>Predicting up to " + targetTick);
while (_world.CurrentTick < targetTick)
{
_world.Predict();
}
- }
- _lastValidatedFrame = currentRemoteFrame;
+ _world.Services.Get().Trace(">>>Done: now at " + _world.CurrentTick);
+ }
}
}
diff --git a/Engine/Client/Implementations/CommandBuffer.cs b/Engine/Core/CommandBuffer.cs
similarity index 58%
rename from Engine/Client/Implementations/CommandBuffer.cs
rename to Engine/Core/CommandBuffer.cs
index 8f23850..1f66be2 100644
--- a/Engine/Client/Implementations/CommandBuffer.cs
+++ b/Engine/Core/CommandBuffer.cs
@@ -1,17 +1,17 @@
-using System.Collections.Generic;
-using Lockstep.Client.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
using Lockstep.Core.Interfaces;
namespace Lockstep.Client.Implementations
-{
+{
+ [Serializable]
public class CommandBuffer : ICommandBuffer
{
///
/// Mapping: FrameNumber -> Commands per player(Id)
///
- protected Dictionary>> Buffer { get; } = new Dictionary>>(5000);
-
- public uint LastInsertedFrame { get; private set; }
+ public Dictionary>> Buffer { get; } = new Dictionary>>(5000);
public virtual void Insert(uint frameNumber, byte commanderId, ICommand[] commands)
{
@@ -27,24 +27,18 @@ public virtual void Insert(uint frameNumber, byte commanderId, ICommand[] comman
Buffer[frameNumber].Add(commanderId, new List(5)); //Initial size of 5 commands per frame per player
}
- Buffer[frameNumber][commanderId].AddRange(commands);
-
- LastInsertedFrame = frameNumber;
+ Buffer[frameNumber][commanderId].AddRange(commands);
}
}
- public Dictionary> Get(uint frame)
+ public Dictionary>> GetChanges()
{
lock (Buffer)
- {
- //If no commands were inserted then return an empty list
- if (!Buffer.ContainsKey(frame))
- {
- Buffer.Add(frame, new Dictionary>());
- }
-
- return Buffer[frame];
+ {
+ var result = Buffer.ToDictionary(pair => pair.Key, pair => pair.Value);
+ Buffer.Clear();
+ return result;
}
- }
+ }
}
}
diff --git a/Engine/Core/Components/Input/TargetPlayerIdComponent.cs b/Engine/Core/Components/Input/TargetPlayerIdComponent.cs
index 12453ae..2b826c5 100644
--- a/Engine/Core/Components/Input/TargetPlayerIdComponent.cs
+++ b/Engine/Core/Components/Input/TargetPlayerIdComponent.cs
@@ -3,7 +3,7 @@
namespace Lockstep.Core.Components.Input
{
[Input]
- public class TargetPlayerIdComponent : IComponent
+ public class TargetActorIdComponent : IComponent
{
public byte value;
}
diff --git a/Engine/Core/Core.csproj b/Engine/Core/Core.csproj
index 9a990c7..c3087c4 100644
--- a/Engine/Core/Core.csproj
+++ b/Engine/Core/Core.csproj
@@ -1,4 +1,4 @@
-
+
@@ -56,6 +56,9 @@
+
+
+
@@ -78,7 +81,7 @@
-
+
@@ -152,7 +155,10 @@
+
+
+
@@ -191,7 +197,6 @@
-
@@ -207,10 +212,10 @@
-
+
-
+
diff --git a/Engine/Core/DefaultServices/DefaultHashService.cs b/Engine/Core/DefaultServices/DefaultHashService.cs
index eced90f..2ac029a 100644
--- a/Engine/Core/DefaultServices/DefaultHashService.cs
+++ b/Engine/Core/DefaultServices/DefaultHashService.cs
@@ -1,19 +1,32 @@
using System.Collections.Generic;
+using System.Linq;
using Lockstep.Core.Interfaces;
namespace Lockstep.Core.DefaultServices
{
- class DefaultHashService : IHashService
+ public class DefaultHashService : IHashService
{
- public long CalculateHashCode(IEnumerable entities)
+ public long CalculateHashCode(IEnumerable hashableEntities, GameStateContext context, ILogService logger)
{
long hashCode = 0;
- foreach (var entity in entities)
+ foreach (var entity in hashableEntities.OrderBy(entity => entity.localId.value))
{
- hashCode ^= entity.position.value.X.RawValue;
- hashCode ^= entity.position.value.Y.RawValue;
+ hashCode ^= CalculateHashCode(entity);
+ if (context.tick.value > 170 && context.tick.value < 175 && entity.actorId.value == 2 && entity.id.value == 89)
+ //if (context.tick.value == 38)
+ {
+ logger.Warn(entity.actorId.value + "/" + entity.id.value + ": (" + entity.position.value + ")");
+ }
}
return hashCode;
}
+
+ public long CalculateHashCode(GameEntity entity)
+ {
+ long hashCode = 0;
+ hashCode ^= entity.position.value.X.RawValue;
+ hashCode ^= entity.position.value.Y.RawValue;
+ return hashCode;
+ }
}
}
diff --git a/Engine/Core/DefaultServices/DefaultIDebugService.cs b/Engine/Core/DefaultServices/DefaultIDebugService.cs
new file mode 100644
index 0000000..5ebdd88
--- /dev/null
+++ b/Engine/Core/DefaultServices/DefaultIDebugService.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using BEPUutilities;
+using Lockstep.Core.Interfaces;
+
+namespace Lockstep.Core.DefaultServices
+{
+ public class DefaultIDebugService : IDebugService
+ {
+ public Dictionary> Buffer { get; } = new Dictionary>(5000);
+ public Dictionary Hashes { get; } = new Dictionary(5000);
+
+
+ public void Register(uint tick, long hash)
+ {
+ Hashes.Add(tick, hash);
+ }
+
+ public long GetHash(uint tick)
+ {
+ return Hashes[tick];
+ }
+
+ public bool HasHash(uint tick)
+ {
+ return Hashes.ContainsKey(tick);
+ }
+
+ public void Register(uint tick, uint entityId, Vector2 pos)
+ {
+ if (!Buffer.ContainsKey(tick))
+ {
+ Buffer.Add(tick, new Dictionary(10));
+ }
+
+ if (!Buffer[tick].ContainsKey(entityId))
+ {
+ Buffer[tick].Add(entityId, pos); //Initial size of 5 commands per frame per player
+ }
+ else
+ {
+ throw new Exception();
+ }
+ }
+
+ public bool Validate(uint tick, uint entityId, Vector2 pos)
+ {
+ return Buffer[tick][entityId].X.RawValue == pos.X.RawValue &&
+ Buffer[tick][entityId].Y.RawValue == pos.Y.RawValue;
+ }
+ }
+}
diff --git a/Engine/Core/DefaultServices/DefaultSnapshotIndexService.cs b/Engine/Core/DefaultServices/DefaultSnapshotIndexService.cs
index 1daf360..1bc8f9c 100644
--- a/Engine/Core/DefaultServices/DefaultSnapshotIndexService.cs
+++ b/Engine/Core/DefaultServices/DefaultSnapshotIndexService.cs
@@ -13,9 +13,17 @@ public void AddIndex(uint value)
_snapShotIndices.Add(value);
}
+ public void RemoveIndex(uint value)
+ {
+ if (_snapShotIndices.Contains(value))
+ {
+ _snapShotIndices.Remove(value);
+ }
+ }
+
public uint GetFirstIndexBefore(uint value)
{
- return _snapShotIndices.Where(index => index <= value).Max();
+ return _snapShotIndices.Any() ? _snapShotIndices.Where(index => index <= value).Max() : 0;
}
}
}
diff --git a/Engine/Core/Features/HashCodeFeature.cs b/Engine/Core/Features/HashCodeFeature.cs
deleted file mode 100644
index 2fa9101..0000000
--- a/Engine/Core/Features/HashCodeFeature.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Lockstep.Core.Interfaces;
-using Lockstep.Core.Systems;
-
-namespace Lockstep.Core.Features
-{
- public sealed class HashCodeFeature : Feature
- {
- public HashCodeFeature(Contexts contexts, Services services)
- {
- Add(new CalculateHashCode(contexts, services.Get()));
- }
- }
-}
diff --git a/Engine/Core/Features/InputFeature.cs b/Engine/Core/Features/InputFeature.cs
index 54c2c58..28bb448 100644
--- a/Engine/Core/Features/InputFeature.cs
+++ b/Engine/Core/Features/InputFeature.cs
@@ -8,7 +8,7 @@ public InputFeature(Contexts contexts, Services services)
{
//TODO: Add InputValidationSystem
- Add(new OnSpawnInputCreateEntity(contexts, services));
+ Add(new ExecuteSpawnInput(contexts, services));
//TODO: Add CleanupInput that removes input of validated frames (no rollback required => can be removed)
diff --git a/Engine/Core/Features/NavigationFeature.cs b/Engine/Core/Features/NavigationFeature.cs
index 3913454..bb15160 100644
--- a/Engine/Core/Features/NavigationFeature.cs
+++ b/Engine/Core/Features/NavigationFeature.cs
@@ -10,7 +10,7 @@ public NavigationFeature(Contexts contexts, Services services)
var navigationService = services.Get();
//Add(new OnNavigableDoRegisterAgent(contexts, navigationService));
- Add(new OnNavigationInputDoSetDestination(contexts, navigationService));
+ Add(new ExecuteNavigationInput(contexts, services));
Add(new NavigationTick(contexts, navigationService));
//Add(new SyncAgentVelocity(contexts, navigationService));
//Add(new UpdateAgentPosition(contexts, navigationService));
diff --git a/Engine/Core/GameLog.cs b/Engine/Core/GameLog.cs
new file mode 100644
index 0000000..a311703
--- /dev/null
+++ b/Engine/Core/GameLog.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Lockstep.Core.Interfaces;
+
+namespace Lockstep.Core
+{
+ [Serializable]
+ public class GameLog
+ {
+ public Dictionary>>> Log { get; } = new Dictionary>>>();
+ public void Add(uint tickId, uint targetTickId, byte actorId, IEnumerable commands)
+ {
+ if (!Log.ContainsKey(tickId))
+ {
+ Log.Add(tickId, new Dictionary>>());
+ }
+
+ if (!Log[tickId].ContainsKey(targetTickId))
+ {
+ Log[tickId].Add(targetTickId, new Dictionary>());
+ }
+
+ if (!Log[tickId][targetTickId].ContainsKey(actorId))
+ {
+ Log[tickId][targetTickId].Add(actorId, new List());
+ }
+
+ Log[tickId][targetTickId][actorId].AddRange(commands);
+ }
+
+ public List>>>> GetAllCommandsForFrame(uint frame)
+ {
+ return Log.Reverse().Where(pair => pair.Key == frame).ToList();
+ }
+ }
+}
diff --git a/Engine/Core/Generated/Input/Components/InputTargetActorIdComponent.cs b/Engine/Core/Generated/Input/Components/InputTargetActorIdComponent.cs
new file mode 100644
index 0000000..c5e0d97
--- /dev/null
+++ b/Engine/Core/Generated/Input/Components/InputTargetActorIdComponent.cs
@@ -0,0 +1,56 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by Entitas.CodeGeneration.Plugins.ComponentEntityApiGenerator.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+public partial class InputEntity {
+
+ public Lockstep.Core.Components.Input.TargetActorIdComponent targetActorId { get { return (Lockstep.Core.Components.Input.TargetActorIdComponent)GetComponent(InputComponentsLookup.TargetActorId); } }
+ public bool hasTargetActorId { get { return HasComponent(InputComponentsLookup.TargetActorId); } }
+
+ public void AddTargetActorId(byte newValue) {
+ var index = InputComponentsLookup.TargetActorId;
+ var component = (Lockstep.Core.Components.Input.TargetActorIdComponent)CreateComponent(index, typeof(Lockstep.Core.Components.Input.TargetActorIdComponent));
+ component.value = newValue;
+ AddComponent(index, component);
+ }
+
+ public void ReplaceTargetActorId(byte newValue) {
+ var index = InputComponentsLookup.TargetActorId;
+ var component = (Lockstep.Core.Components.Input.TargetActorIdComponent)CreateComponent(index, typeof(Lockstep.Core.Components.Input.TargetActorIdComponent));
+ component.value = newValue;
+ ReplaceComponent(index, component);
+ }
+
+ public void RemoveTargetActorId() {
+ RemoveComponent(InputComponentsLookup.TargetActorId);
+ }
+}
+
+//------------------------------------------------------------------------------
+//
+// This code was generated by Entitas.CodeGeneration.Plugins.ComponentMatcherApiGenerator.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+public sealed partial class InputMatcher {
+
+ static Entitas.IMatcher _matcherTargetActorId;
+
+ public static Entitas.IMatcher TargetActorId {
+ get {
+ if (_matcherTargetActorId == null) {
+ var matcher = (Entitas.Matcher)Entitas.Matcher.AllOf(InputComponentsLookup.TargetActorId);
+ matcher.componentNames = InputComponentsLookup.componentNames;
+ _matcherTargetActorId = matcher;
+ }
+
+ return _matcherTargetActorId;
+ }
+ }
+}
diff --git a/Engine/Core/Generated/Input/Components/InputTargetPlayerIdComponent.cs b/Engine/Core/Generated/Input/Components/InputTargetPlayerIdComponent.cs
deleted file mode 100644
index c87c43b..0000000
--- a/Engine/Core/Generated/Input/Components/InputTargetPlayerIdComponent.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by Entitas.CodeGeneration.Plugins.ComponentEntityApiGenerator.
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-public partial class InputEntity {
-
- public Lockstep.Core.Components.Input.TargetPlayerIdComponent targetPlayerId { get { return (Lockstep.Core.Components.Input.TargetPlayerIdComponent)GetComponent(InputComponentsLookup.TargetPlayerId); } }
- public bool hasTargetPlayerId { get { return HasComponent(InputComponentsLookup.TargetPlayerId); } }
-
- public void AddTargetPlayerId(byte newValue) {
- var index = InputComponentsLookup.TargetPlayerId;
- var component = (Lockstep.Core.Components.Input.TargetPlayerIdComponent)CreateComponent(index, typeof(Lockstep.Core.Components.Input.TargetPlayerIdComponent));
- component.value = newValue;
- AddComponent(index, component);
- }
-
- public void ReplaceTargetPlayerId(byte newValue) {
- var index = InputComponentsLookup.TargetPlayerId;
- var component = (Lockstep.Core.Components.Input.TargetPlayerIdComponent)CreateComponent(index, typeof(Lockstep.Core.Components.Input.TargetPlayerIdComponent));
- component.value = newValue;
- ReplaceComponent(index, component);
- }
-
- public void RemoveTargetPlayerId() {
- RemoveComponent(InputComponentsLookup.TargetPlayerId);
- }
-}
-
-//------------------------------------------------------------------------------
-//
-// This code was generated by Entitas.CodeGeneration.Plugins.ComponentMatcherApiGenerator.
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-public sealed partial class InputMatcher {
-
- static Entitas.IMatcher _matcherTargetPlayerId;
-
- public static Entitas.IMatcher TargetPlayerId {
- get {
- if (_matcherTargetPlayerId == null) {
- var matcher = (Entitas.Matcher)Entitas.Matcher.AllOf(InputComponentsLookup.TargetPlayerId);
- matcher.componentNames = InputComponentsLookup.componentNames;
- _matcherTargetPlayerId = matcher;
- }
-
- return _matcherTargetPlayerId;
- }
- }
-}
diff --git a/Engine/Core/Generated/Input/InputComponentsLookup.cs b/Engine/Core/Generated/Input/InputComponentsLookup.cs
index 2464fd6..ff77cbc 100644
--- a/Engine/Core/Generated/Input/InputComponentsLookup.cs
+++ b/Engine/Core/Generated/Input/InputComponentsLookup.cs
@@ -12,7 +12,7 @@ public static class InputComponentsLookup {
public const int Coordinate = 1;
public const int EntityConfigId = 2;
public const int Selection = 3;
- public const int TargetPlayerId = 4;
+ public const int TargetActorId = 4;
public const int Tick = 5;
public const int TotalComponents = 6;
@@ -22,7 +22,7 @@ public static class InputComponentsLookup {
"Coordinate",
"EntityConfigId",
"Selection",
- "TargetPlayerId",
+ "TargetActorId",
"Tick"
};
@@ -31,7 +31,7 @@ public static class InputComponentsLookup {
typeof(Lockstep.Core.Components.Input.CoordinateComponent),
typeof(Lockstep.Core.Components.Input.EntityConfigIdComponent),
typeof(Lockstep.Core.Components.Input.SelectionComponent),
- typeof(Lockstep.Core.Components.Input.TargetPlayerIdComponent),
+ typeof(Lockstep.Core.Components.Input.TargetActorIdComponent),
typeof(Lockstep.Core.Components.Input.TickComponent)
};
}
diff --git a/Engine/Core/Interfaces/ICommandBuffer.cs b/Engine/Core/Interfaces/ICommandBuffer.cs
new file mode 100644
index 0000000..0d00bdd
--- /dev/null
+++ b/Engine/Core/Interfaces/ICommandBuffer.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace Lockstep.Core.Interfaces
+{
+ public interface ICommandBuffer
+ {
+ Dictionary>> Buffer { get; }
+
+ void Insert(uint frame, byte commanderId, ICommand[] commands);
+
+ Dictionary>> GetChanges();
+ }
+}
\ No newline at end of file
diff --git a/Engine/Core/Interfaces/IDebugService.cs b/Engine/Core/Interfaces/IDebugService.cs
new file mode 100644
index 0000000..f371b85
--- /dev/null
+++ b/Engine/Core/Interfaces/IDebugService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BEPUutilities;
+
+namespace Lockstep.Core.Interfaces
+{
+ public interface IDebugService : IService
+ {
+ void Register(uint tick, long hash);
+ long GetHash(uint tick);
+ bool HasHash(uint tick);
+
+ void Register(uint tick, uint entityId, Vector2 pos);
+
+ bool Validate(uint tick, uint entityId, Vector2 pos);
+ }
+}
diff --git a/Engine/Core/Interfaces/IHashService.cs b/Engine/Core/Interfaces/IHashService.cs
index c9b9002..5361115 100644
--- a/Engine/Core/Interfaces/IHashService.cs
+++ b/Engine/Core/Interfaces/IHashService.cs
@@ -3,7 +3,9 @@
namespace Lockstep.Core.Interfaces
{
public interface IHashService : IService
- {
- long CalculateHashCode(IEnumerable hashableEntities);
+ {
+ long CalculateHashCode(IEnumerable hashableEntities, GameStateContext context, ILogService logger);
+
+ long CalculateHashCode(GameEntity entity);
}
}
\ No newline at end of file
diff --git a/Engine/Core/Interfaces/ILogService.cs b/Engine/Core/Interfaces/ILogService.cs
index f71449d..155ec63 100644
--- a/Engine/Core/Interfaces/ILogService.cs
+++ b/Engine/Core/Interfaces/ILogService.cs
@@ -3,5 +3,6 @@
public interface ILogService : IService
{
void Warn(object message);
+ void Trace(object message);
}
}
\ No newline at end of file
diff --git a/Engine/Core/Interfaces/ISnapshotIndexService.cs b/Engine/Core/Interfaces/ISnapshotIndexService.cs
index 3ae9770..c6a1bf7 100644
--- a/Engine/Core/Interfaces/ISnapshotIndexService.cs
+++ b/Engine/Core/Interfaces/ISnapshotIndexService.cs
@@ -7,6 +7,8 @@ public interface ISnapshotIndexService : IService
{
void AddIndex(uint value);
+ void RemoveIndex(uint value);
+
uint GetFirstIndexBefore(uint value);
}
}
diff --git a/Engine/Core/Interfaces/IWorld.cs b/Engine/Core/Interfaces/IWorld.cs
index f61f0c9..c721c51 100644
--- a/Engine/Core/Interfaces/IWorld.cs
+++ b/Engine/Core/Interfaces/IWorld.cs
@@ -1,9 +1,12 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
+using Lockstep.Client.Implementations;
namespace Lockstep.Core.Interfaces
{
public interface IWorld
{
+ GameLog GameLog { get; }
+
Services Services { get; }
int EntitiesInCurrentTick { get; }
diff --git a/Engine/Core/Services.cs b/Engine/Core/Services.cs
index c624c58..453beb0 100644
--- a/Engine/Core/Services.cs
+++ b/Engine/Core/Services.cs
@@ -17,6 +17,7 @@ public Services()
RegisterDefault(new DefaultViewService());
RegisterDefault(new DefaultNavigationService());
RegisterDefault(new DefaultSnapshotIndexService());
+ RegisterDefault(new DefaultIDebugService());
}
public void Register(IService instance)
diff --git a/Engine/Core/Systems/CalculateHashCode.cs b/Engine/Core/Systems/CalculateHashCode.cs
index 200fd03..fa80d54 100644
--- a/Engine/Core/Systems/CalculateHashCode.cs
+++ b/Engine/Core/Systems/CalculateHashCode.cs
@@ -5,27 +5,30 @@ namespace Lockstep.Core.Systems
{
public class CalculateHashCode : IInitializeSystem, IExecuteSystem
{
+ private readonly Services _services;
private readonly IHashService _hashService;
private readonly IGroup _hashableEntities;
private readonly GameStateContext _gameStateContext;
- public CalculateHashCode(Contexts contexts, IHashService hashService)
+ public CalculateHashCode(Contexts contexts, Services services)
{
- _hashService = hashService;
+ _services = services;
+ _hashService = services.Get();
+
_gameStateContext = contexts.gameState;
- _hashableEntities = contexts.game.GetGroup(GameMatcher.AllOf(GameMatcher.LocalId, GameMatcher.Hashable));
+ _hashableEntities = contexts.game.GetGroup(GameMatcher.AllOf(GameMatcher.LocalId, GameMatcher.Position).NoneOf(GameMatcher.Backup));
}
public void Initialize()
{
- _gameStateContext.SetHashCode(0);
+ _gameStateContext.ReplaceHashCode(0);
}
public void Execute()
{
- _gameStateContext.ReplaceHashCode(_hashService.CalculateHashCode(_hashableEntities.GetEntities()));
+ _gameStateContext.ReplaceHashCode(_hashService.CalculateHashCode(_hashableEntities.GetEntities(), _gameStateContext, _services.Get()));
}
}
}
diff --git a/Engine/Core/Systems/Debugging/VerifySelectionIdExists.cs b/Engine/Core/Systems/Debugging/VerifySelectionIdExists.cs
new file mode 100644
index 0000000..4f56cdc
--- /dev/null
+++ b/Engine/Core/Systems/Debugging/VerifySelectionIdExists.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Entitas;
+using Lockstep.Core.Interfaces;
+
+namespace Lockstep.Core.Systems.Debugging
+{
+ public class VerifySelectionIdExists : IExecuteSystem
+ {
+ private readonly Services _services;
+ private readonly GameContext _gameContext;
+ private readonly InputContext _inputContext;
+ private readonly GameStateContext _gameStateContext;
+
+ public VerifySelectionIdExists(Contexts contexts, Services services)
+ {
+ _services = services;
+ _gameContext = contexts.game;
+ _inputContext = contexts.input;
+ _gameStateContext = contexts.gameState;
+ }
+
+ public void Execute()
+ {
+ foreach (var input in _inputContext.GetEntities(
+ InputMatcher.AllOf(
+ InputMatcher.Tick,
+ InputMatcher.Coordinate,
+ InputMatcher.Selection,
+ InputMatcher.ActorId))
+ .Where(entity => entity.tick.value < _gameStateContext.tick.value))
+ {
+ var ents = _gameContext.GetEntities(GameMatcher.LocalId)
+ .Where(entity => entity.actorId.value == input.actorId.value).Select(entity => entity.id.value);
+ var missing = input.selection.entityIds.Where(u => !ents.Contains(u)).ToList();
+ if (missing.Any())
+ {
+ _services.Get().Warn(missing.Count + " missing for actor: " + input.actorId.value);
+ }
+
+ }
+ }
+ }
+}
diff --git a/Engine/Core/Systems/Input/OnSpawnInputCreateEntity.cs b/Engine/Core/Systems/Input/ExecuteSpawnInput.cs
similarity index 73%
rename from Engine/Core/Systems/Input/OnSpawnInputCreateEntity.cs
rename to Engine/Core/Systems/Input/ExecuteSpawnInput.cs
index 67c66a1..d16b360 100644
--- a/Engine/Core/Systems/Input/OnSpawnInputCreateEntity.cs
+++ b/Engine/Core/Systems/Input/ExecuteSpawnInput.cs
@@ -5,8 +5,9 @@
namespace Lockstep.Core.Systems.Input
{
- public class OnSpawnInputCreateEntity : IExecuteSystem
- {
+ public class ExecuteSpawnInput : IExecuteSystem
+ {
+ private readonly Services _services;
private readonly IViewService _viewService;
private readonly GameContext _gameContext;
private readonly GameStateContext _gameStateContext;
@@ -15,8 +16,9 @@ public class OnSpawnInputCreateEntity : IExecuteSystem
private uint _localIdCounter;
private readonly ActorContext _actorContext;
- public OnSpawnInputCreateEntity(Contexts contexts, Services services)
+ public ExecuteSpawnInput(Contexts contexts, Services services)
{
+ _services = services;
_viewService = services.Get();
_gameContext = contexts.game;
_gameStateContext = contexts.gameState;
@@ -31,17 +33,17 @@ public OnSpawnInputCreateEntity(Contexts contexts, Services services)
}
public void Execute()
- {
- //TODO: order by timestamp instead of actorId => if commands intersect, the first one should win, timestamp should be added by server, RTT has to be considered
- foreach (var input in _spawnInputs.GetEntities().Where(entity => entity.tick.value == _gameStateContext.tick.value).OrderBy(entity => entity.actorId.value))
+ {
+ foreach (var input in _spawnInputs.GetEntities().Where(entity => entity.tick.value == _gameStateContext.tick.value))
{
var actor = _actorContext.GetEntityWithId(input.actorId.value);
- var nextEntityId = actor.entityCount.value + 1;
+ var nextEntityId = actor.entityCount.value;
var e = _gameContext.CreateEntity();
e.isNew = true;
-
+ _services.Get().Trace(actor.id.value + " -> " + nextEntityId);
+
//composite primary key
e.AddId(nextEntityId);
e.AddActorId(input.actorId.value);
@@ -55,7 +57,7 @@ public void Execute()
_viewService.LoadView(e, input.entityConfigId.value);
- actor.ReplaceEntityCount(nextEntityId);
+ actor.ReplaceEntityCount(nextEntityId + 1);
_localIdCounter += 1;
}
}
diff --git a/Engine/Core/Systems/Navigation/ExecuteNavigationInput.cs b/Engine/Core/Systems/Navigation/ExecuteNavigationInput.cs
new file mode 100644
index 0000000..4f05975
--- /dev/null
+++ b/Engine/Core/Systems/Navigation/ExecuteNavigationInput.cs
@@ -0,0 +1,55 @@
+using System.Linq;
+using Entitas;
+using Lockstep.Core.Interfaces;
+
+namespace Lockstep.Core.Systems.Navigation
+{
+ public class ExecuteNavigationInput : IExecuteSystem
+ {
+ private readonly Services _services;
+ private readonly INavigationService _navigationService;
+ private readonly GameContext _gameContext;
+ readonly IGroup _navigationInput;
+ private readonly GameStateContext _gameStateContext;
+
+ public ExecuteNavigationInput(Contexts contexts, Services services)
+ {
+ _services = services;
+ _navigationService = services.Get();
+ _gameContext = contexts.game;
+ _gameStateContext = contexts.gameState;
+
+ _navigationInput = contexts.input.GetGroup(InputMatcher.AllOf(
+ InputMatcher.Coordinate,
+ InputMatcher.Selection,
+ InputMatcher.ActorId,
+ InputMatcher.Tick));
+ }
+
+
+ public void Execute()
+ {
+ foreach (var input in _navigationInput.GetEntities().Where(entity => entity.tick.value == _gameStateContext.tick.value))
+ {
+ var destination = input.coordinate.value;
+ var targetActorId = input.hasTargetActorId ? input.targetActorId.value : input.actorId.value;
+
+ var selectedEntities = _gameContext
+ .GetEntities(GameMatcher.LocalId)
+ .Where(entity =>
+ input.selection.entityIds.Contains(entity.id.value) &&
+ entity.actorId.value == targetActorId);
+
+
+ _services.Get().Trace(targetActorId + " moving " + string.Join(", ", selectedEntities.Select(entity => entity.id.value)));
+
+ foreach (var entity in selectedEntities)
+ {
+ entity.ReplaceDestination(destination);
+
+ //_navigationService.SetAgentDestination(entityId, destination);
+ }
+ }
+ }
+ }
+}
diff --git a/Engine/Core/Systems/Navigation/NavigationTick.cs b/Engine/Core/Systems/Navigation/NavigationTick.cs
index bf22499..c687d55 100644
--- a/Engine/Core/Systems/Navigation/NavigationTick.cs
+++ b/Engine/Core/Systems/Navigation/NavigationTick.cs
@@ -29,9 +29,11 @@ public void Execute()
velocity.Normalize();
}
- if ((entity.destination.value - entity.position.value).LengthSquared() > 2)
+ if ((entity.destination.value - entity.position.value).LengthSquared() > 1)
{
entity.ReplacePosition(entity.position.value + velocity);
+ //TODO: undo after debugging
+ //entity.ReplacePosition(entity.destination.value);
}
}
}
diff --git a/Engine/Core/Systems/Navigation/OnNavigationInputDoSetDestination.cs b/Engine/Core/Systems/Navigation/OnNavigationInputDoSetDestination.cs
deleted file mode 100644
index 5a24a60..0000000
--- a/Engine/Core/Systems/Navigation/OnNavigationInputDoSetDestination.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Entitas;
-using Lockstep.Core.Interfaces;
-
-namespace Lockstep.Core.Systems.Navigation
-{
- public class OnNavigationInputDoSetDestination : ReactiveSystem
- {
- private readonly INavigationService _navigationService;
- private readonly GameContext _contextsGame;
-
- public OnNavigationInputDoSetDestination(Contexts contexts, INavigationService navigationService) : base(contexts.input)
- {
- _navigationService = navigationService;
- _contextsGame = contexts.game;
- }
-
- protected override ICollector GetTrigger(IContext context)
- {
- return context.CreateCollector(InputMatcher.AllOf(InputMatcher.Coordinate, InputMatcher.Selection, InputMatcher.ActorId));
- }
-
- protected override bool Filter(InputEntity entity)
- {
- return entity.hasCoordinate && entity.hasSelection && entity.hasActorId;
- }
-
- protected override void Execute(List inputs)
- {
- foreach (var input in inputs)
- {
- var destination = input.coordinate.value;
-
- var selectedEntities = _contextsGame
- .GetEntities(GameMatcher.LocalId)
- .Where(entity =>
- input.selection.entityIds.Contains(entity.id.value) &&
- entity.actorId.value == input.actorId.value);
-
- foreach (var entity in selectedEntities)
- {
- entity.ReplaceDestination(destination);
-
- //_navigationService.SetAgentDestination(entityId, destination);
- }
- }
- }
- }
-}
diff --git a/Engine/Core/Systems/Navigation/UpdateAgentPosition.cs b/Engine/Core/Systems/Navigation/UpdateAgentPosition.cs
index 8be62bc..9fe8ee9 100644
--- a/Engine/Core/Systems/Navigation/UpdateAgentPosition.cs
+++ b/Engine/Core/Systems/Navigation/UpdateAgentPosition.cs
@@ -23,12 +23,11 @@ public void Execute()
foreach (var entity in _gameContext.GetEntities().Where(e => e.hasId))
{
- if (entity.velocity.value != Vector2.Zero)
- {
- entity.ReplacePosition(entity.position.value + entity.velocity.value);
+ if (entity.velocity.value == Vector2.Zero)
+ continue;
+ entity.ReplacePosition(entity.position.value + entity.velocity.value);
- updatedPositions.Add(entity.localId.value, entity.position.value);
- }
+ updatedPositions.Add(entity.localId.value, entity.position.value);
}
_navigationService.SetAgentPositions(updatedPositions);
diff --git a/Engine/Core/Systems/OnNewPredictionCreateBackup.cs b/Engine/Core/Systems/OnNewPredictionCreateBackup.cs
index 997c859..cae9ab9 100644
--- a/Engine/Core/Systems/OnNewPredictionCreateBackup.cs
+++ b/Engine/Core/Systems/OnNewPredictionCreateBackup.cs
@@ -68,7 +68,9 @@ protected override void Execute(List entities)
foreach (var e in gameEnts)
{
var shadowEntity = _gameContext.CreateEntity();
-
+
+ _services.Get().Register(currentTick, e.localId.value, e.position.value);
+
//LocalId is primary index => don't copy; id+actorId should be readonly and stay the same throughout the game
foreach (var index in e.GetComponentIndices().Except(new[] { GameComponentsLookup.LocalId, GameComponentsLookup.Id, GameComponentsLookup.ActorId }))
{
@@ -80,8 +82,7 @@ protected override void Execute(List entities)
shadowEntity.AddBackup(e.localId.value, currentTick);
}
-
-
+
_services.Get().Warn("New backup for " + currentTick + "(" + actors.Length + " actors, " + gameEnts.Length + " entities)");
}
}
diff --git a/Engine/Core/World.cs b/Engine/Core/World.cs
index 55c2cb1..38e32bc 100644
--- a/Engine/Core/World.cs
+++ b/Engine/Core/World.cs
@@ -1,6 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
-using Entitas;
+using Entitas;
using Lockstep.Core.Features;
using Lockstep.Core.Interfaces;
using Lockstep.Core.Systems;
@@ -13,6 +14,8 @@ public sealed class World : Feature, IWorld
{
private Contexts Contexts { get; }
+ public GameLog GameLog { get; } = new GameLog();
+
public Services Services { get; }
public uint CurrentTick => Contexts.gameState.tick.value;
@@ -23,6 +26,7 @@ public sealed class World : Feature, IWorld
private readonly GameContext _gameContext;
private readonly INavigationService _navigation;
private readonly ActorContext _actorContext;
+
public World(Contexts contexts, params IService[] additionalServices)
{
@@ -45,15 +49,19 @@ public World(Contexts contexts, params IService[] additionalServices)
private void AddFeatures(Contexts contexts)
{
+ Add(new CalculateHashCode(contexts, Services));
+
Add(new OnNewPredictionCreateBackup(contexts, Services));
Add(new InputFeature(contexts, Services));
+ Add(new VerifySelectionIdExists(contexts, Services));
+
Add(new NavigationFeature(contexts, Services));
Add(new GameEventSystems(contexts));
- Add(new HashCodeFeature(contexts, Services));
+ Add(new CalculateHashCode(contexts, Services));
Add(new RemoveNewFlag(contexts));
@@ -75,6 +83,8 @@ public void Initialize(byte[] allActorIds)
public void AddInput(uint tickId, byte actor, List input)
{
+ GameLog.Add(CurrentTick, tickId, actor, input.ToArray());
+
foreach (var command in input)
{
var inputEntity = Contexts.input.CreateEntity();
@@ -83,6 +93,10 @@ public void AddInput(uint tickId, byte actor, List input)
inputEntity.AddTick(tickId);
inputEntity.AddActorId(actor);
}
+
+ //TODO: after adding input, order input by timestamp => if commands intersect, the first one should win, timestamp should be added by server, RTT has to be considered
+ //ordering by timestamp requires loopback functionality because we have to wait for server-response; at the moment commands get distributed to all clients except oneself
+ //if a command comes back from server and it was our own command, the local command has to be overwritten instead of just adding it (as it is at the moment)
}
public void Predict()
@@ -92,6 +106,7 @@ public void Predict()
Contexts.gameState.isPredicting = true;
}
+ Services.Get().Trace("Predict " + CurrentTick);
Execute();
Cleanup();
}
@@ -101,10 +116,15 @@ public void Simulate()
if (Contexts.gameState.isPredicting)
{
Contexts.gameState.isPredicting = false;
- }
+ }
+
+ Services.Get().Trace("Simulate " + CurrentTick);
Execute();
Cleanup();
+
+ Services.Get().Register(Contexts.gameState.tick.value, Contexts.gameState.hashCode.value);
+
}
///
@@ -112,7 +132,9 @@ public void Simulate()
///
///
public void RevertToTick(uint tick)
- {
+ {
+
+ Services.Get().Trace("Rollback to " + tick);
//Get the actual tick that we have a snapshot for
var resultTick = Services.Get().GetFirstIndexBefore(tick);
@@ -125,66 +147,62 @@ public void RevertToTick(uint tick)
foreach (var backedUpActor in backedUpActors)
{
backedUpActor.CopyTo(
- _actorContext.GetEntityWithId(backedUpActor.backup.actorId), //Current Actor
- true, //Replace components
+ _actorContext.GetEntityWithId(backedUpActor.backup.actorId), //Current Actor
+ true, //Replace components
backedUpActor.GetComponentIndices().Except(new []{ ActorComponentsLookup.Backup }).ToArray()); //Copy everything except the backup-component
}
+
/*
* ====================== Revert game-entities ======================
*/
var currentEntities = _gameContext.GetEntities(GameMatcher.LocalId);
- var backedUpEntities = _gameContext.GetEntities(GameMatcher.Backup).Where(e => e.backup.tick == resultTick).Select(entity => entity.backup.localEntityId).ToList();
-
- //Entities that were created in the prediction have to be destroyed
- var invalidEntities = currentEntities.Where(entity => !backedUpEntities.Contains(entity.localId.value));
+ var backupEntities = _gameContext.GetEntities(GameMatcher.Backup).Where(e => e.backup.tick == resultTick).ToList();
+ var backupEntityIds = backupEntities.Select(entity => entity.backup.localEntityId);
+
+ //Entities that were created in the prediction have to be destroyed
+ var invalidEntities = currentEntities.Where(entity => !backupEntityIds.Contains(entity.localId.value)).ToList();
foreach (var invalidEntity in invalidEntities)
{
//Here we have the actual entities, we can safely refer to them via the internal id
_view.DeleteView(invalidEntity.localId.value);
- _gameContext.GetEntityWithLocalId(invalidEntity.localId.value).Destroy();
+ invalidEntity.Destroy();
+ }
+
+ foreach (var invalidBackupEntity in _gameContext.GetEntities(GameMatcher.Backup).Where(e => e.backup.tick > resultTick))
+ {
+ Services.Get().RemoveIndex(invalidBackupEntity.backup.tick);
+ invalidBackupEntity.Destroy();
}
+ //Copy old state to the entity
+ foreach (var backupEntity in backupEntities)
+ {
+ var target = _gameContext.GetEntityWithLocalId(backupEntity.backup.localEntityId);
+ var additionalComponentIndices = target.GetComponentIndices().Except(
+ backupEntity
+ .GetComponentIndices()
+ .Except(new[] {GameComponentsLookup.Backup})
+ .Concat(new[] {GameComponentsLookup.Id, GameComponentsLookup.ActorId, GameComponentsLookup.LocalId}))
+ ;
+ foreach (var index in additionalComponentIndices)
+ {
+ target.RemoveComponent(index);
+ }
+
+ backupEntity.CopyTo(target, true, backupEntity.GetComponentIndices().Except(new []{GameComponentsLookup.Backup}).ToArray());
+
+
+ if (!Services.Get().Validate(resultTick, backupEntity.backup.localEntityId, target.position.value))
+ {
+ throw new Exception();
+ }
+ }
+ //TODO: restore locally destroyed entities
-
- //Apply old values to the components
- //foreach (var shadow in shadows.Except(spawnedShadows))
- //{
- // var referencedEntity = currentEntities.FirstOrDefault(e => e.hasId && e.hasOwnerId && e.id.value == shadow.id.value && e.ownerId.value == shadow.ownerId.value);
-
- // //Check if the entity got destroyed locally
- // if (referencedEntity == null)
- // {
- // //TODO: restore locally destroyed entities
- // }
- // else
- // {
- // //Entity is in the game locally, revert to old state
- // var currentComponents = referencedEntity.GetComponentIndices();
- // var previousComponents = shadow.GetComponentIndices().Except(new[] { GameComponentsLookup.Shadow, GameComponentsLookup.Tick }).ToArray();
-
- // var sameComponents = previousComponents.Intersect(currentComponents);
- // var missingComponents = previousComponents.Except(currentComponents).ToArray();
- // var onlyLocalComponents = currentComponents.Except(new[] { GameComponentsLookup.LocalId }).Except(previousComponents);
-
- // shadow.CopyTo(referencedEntity, true, sameComponents.ToArray());
-
- // //CopyTo with 0 params would copy all...
- // if (missingComponents.Length > 0)
- // {
- // shadow.CopyTo(referencedEntity, false, missingComponents);
- // }
-
- // foreach (var index in onlyLocalComponents)
- // {
- // referencedEntity.RemoveComponent(index);
- // }
- // }
- //}
-
- Contexts.gameState.ReplaceTick(resultTick);
+ Contexts.gameState.ReplaceTick(resultTick);
}
}
}
\ No newline at end of file
diff --git a/Engine/Dependencies/BEPUutilities.dll b/Engine/Dependencies/BEPUutilities.dll
index ef002e3..5805c07 100644
Binary files a/Engine/Dependencies/BEPUutilities.dll and b/Engine/Dependencies/BEPUutilities.dll differ
diff --git a/Engine/Dependencies/BEPUutilities.pdb b/Engine/Dependencies/BEPUutilities.pdb
index ae6365c..7393618 100644
Binary files a/Engine/Dependencies/BEPUutilities.pdb and b/Engine/Dependencies/BEPUutilities.pdb differ
diff --git a/Engine/Dependencies/FixMath.NET.dll b/Engine/Dependencies/FixMath.NET.dll
index 13aafbd..c01fa24 100644
Binary files a/Engine/Dependencies/FixMath.NET.dll and b/Engine/Dependencies/FixMath.NET.dll differ
diff --git a/Engine/Dependencies/FixMath.NET.pdb b/Engine/Dependencies/FixMath.NET.pdb
index a80fa73..961310d 100644
Binary files a/Engine/Dependencies/FixMath.NET.pdb and b/Engine/Dependencies/FixMath.NET.pdb differ
diff --git a/Engine/Test/Converter.cs b/Engine/Test/Converter.cs
index bdc85d9..01c612a 100644
--- a/Engine/Test/Converter.cs
+++ b/Engine/Test/Converter.cs
@@ -37,5 +37,10 @@ public void Warn(object message)
{
_outputHelper.WriteLine($"Warn: {message}");
}
+
+ public void Trace(object message)
+ {
+ _outputHelper.WriteLine($"Trace: {message}");
+ }
}
}
\ No newline at end of file
diff --git a/Engine/Test/DumpTests.cs b/Engine/Test/DumpTests.cs
new file mode 100644
index 0000000..9c2618b
--- /dev/null
+++ b/Engine/Test/DumpTests.cs
@@ -0,0 +1,169 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Net.WebSockets;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using Lockstep.Client;
+using Lockstep.Client.Commands;
+using Lockstep.Client.Implementations;
+using Lockstep.Core;
+using Lockstep.Core.Interfaces;
+using Lockstep.Network.Messages;
+using Lockstep.Network.Utils;
+using Shouldly;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Test
+{
+ public class GettingSerious
+ {
+ private readonly ITestOutputHelper _output;
+
+ public GettingSerious(ITestOutputHelper output)
+ {
+ _output = output;
+ Console.SetOut(new Converter(output));
+ }
+
+ [Fact]
+ public void TestDump1()
+ {
+ TestDump("2_-535026177646_log");
+ }
+
+ [Fact]
+ public void TestDump2()
+ {
+ TestDump("37_-546443594864_log");
+ }
+
+ private void TestDump(string fileName)
+ {
+ var contexts = new Contexts();
+ var systems = new World(contexts, new TestLogger(_output));
+ var commandBuffer = new CommandBuffer();
+
+ var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
+ var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
+ var dirPath = Path.GetDirectoryName(codeBasePath);
+
+ var data = ReadFile($@"{dirPath}\Dumps\{fileName}.txt");
+ var deserializer = new Deserializer(data);
+ var hashCode = deserializer.GetLong();
+ var tick = deserializer.GetUInt();
+ var localActorId = deserializer.GetByte();
+ var allActors = deserializer.GetBytesWithLength();
+
+ IFormatter formatter = new BinaryFormatter();
+ GameLog log;
+ using (var stream = new MemoryStream(deserializer.GetRemainingBytes()))
+ {
+ log = (GameLog) formatter.Deserialize(stream);
+ }
+
+ var sim = new Simulation(systems, commandBuffer) {LagCompensation = 0, SendCommandsToBuffer = false};
+ sim.Initialize(new Init {TargetFPS = 1000, AllActors = allActors, ActorID = localActorId});
+
+ for (uint i = 0; i < tick; i++)
+ {
+ if (log.Log.ContainsKey(i))
+ {
+ var tickCommands = log.Log[i];
+ {
+ foreach (var (tickId, allCommands) in tickCommands)
+ {
+ foreach (var (actorId, commands) in allCommands)
+ {
+ if (actorId == localActorId)
+ {
+ _output.WriteLine("Local: " + commands.Count + " commands");
+
+ systems.AddInput(tickId, actorId, commands);
+ }
+ else
+ {
+ commandBuffer.Insert(tickId, actorId, commands.ToArray());
+ }
+ }
+ }
+ }
+ }
+
+ sim.Update(1);
+ }
+
+ contexts.gameState.hashCode.value.ShouldBe(hashCode);
+ commandBuffer.Buffer.ShouldBeEmpty();
+
+
+ contexts.Reset();
+ var debug = systems.Services.Get();
+ systems = new World(contexts, new TestLogger(_output));
+ sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
+ sim.Initialize(new Init { TargetFPS = 1000, AllActors = allActors, ActorID = localActorId });
+
+ foreach (var (occurTickId, tickCommands) in log.Log)
+ {
+ foreach (var (tickId, allCommands) in tickCommands)
+ {
+ foreach (var (actorId, commands) in allCommands)
+ {
+ if (commands.Any(command => command is NavigateCommand))
+ {
+ }
+ if (actorId == localActorId)
+ {
+ _output.WriteLine("Local: " + commands.Count + " commands");
+
+ systems.AddInput(tickId, actorId, commands);
+ }
+ else
+ {
+ commandBuffer.Insert(tickId, actorId, commands.ToArray());
+ }
+ }
+ }
+ }
+
+ var debug2 = systems.Services.Get();
+ debug.ShouldNotBeSameAs(debug2);
+
+ for (uint i = 0; i < tick; i++)
+ {
+ sim.Update(1);
+ if (debug.HasHash(systems.CurrentTick))
+ {
+ debug.GetHash(systems.CurrentTick).ShouldBe(contexts.gameState.hashCode.value);
+ }
+ }
+
+ contexts.gameState.hashCode.value.ShouldBe(hashCode);
+ }
+
+
+ public static byte[] ReadFile(string filePath)
+ {
+ byte[] buffer;
+ FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+ try
+ {
+ int length = (int)fileStream.Length; // get file length
+ buffer = new byte[length]; // create buffer
+ int count; // actual number of bytes read
+ int sum = 0; // total number of bytes read
+
+ // read until Read method returns 0 (end of the stream has been reached)
+ while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
+ sum += count; // sum is a buffer offset for next reading
+ }
+ finally
+ {
+ fileStream.Close();
+ }
+ return buffer;
+ }
+ }
+}
diff --git a/Engine/Test/Dumps/2_-535026177646_log.txt b/Engine/Test/Dumps/2_-535026177646_log.txt
new file mode 100644
index 0000000..f4a465a
Binary files /dev/null and b/Engine/Test/Dumps/2_-535026177646_log.txt differ
diff --git a/Engine/Test/Dumps/3_-533374750893_log.txt b/Engine/Test/Dumps/3_-533374750893_log.txt
new file mode 100644
index 0000000..d75d4e7
Binary files /dev/null and b/Engine/Test/Dumps/3_-533374750893_log.txt differ
diff --git a/Engine/Test/InputTests.cs b/Engine/Test/InputTests.cs
index c7a644d..a9193c6 100644
--- a/Engine/Test/InputTests.cs
+++ b/Engine/Test/InputTests.cs
@@ -22,25 +22,7 @@ public InputParseTest(ITestOutputHelper output)
{
_output = output;
Console.SetOut(new Converter(output));
- }
-
- [Fact]
- public void TestGameEntityHasUniqueId()
- {
-
- var contexts = new Contexts();
-
- const int numEntities = 10;
-
- for (uint i = 0; i < numEntities; i++)
- {
- contexts.game.CreateEntity();
- }
-
- contexts.game.count.ShouldBe(numEntities);
- contexts.game.GetEntities().Select(entity => entity.hasId).ShouldAllBe(b => true);
- contexts.game.GetEntities().Select(entity => entity.id.value).ShouldBeUnique();
- }
+ }
[Fact]
public void TestCreateEntityRollbackLocal()
@@ -52,89 +34,72 @@ public void TestCreateEntityRollbackLocal()
var sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
- sim.Initialize(new Init { TargetFPS = 1});
-
+ sim.Initialize(new Init { TargetFPS = 1, AllActors = new byte[] { 0, 1 }, ActorID = 0 });
systems.CurrentTick.ShouldBe((uint)0);
sim.Update(1000); //0
systems.CurrentTick.ShouldBe((uint)1);
- for (int i = 0; i < 1; i++)
- {
- sim.Execute(new Spawn());
- }
+
+ sim.Execute(new Spawn());
sim.Update(1000); //1
systems.CurrentTick.ShouldBe((uint)2);
ExpectEntityCount(contexts, 1);
- ExpectBackupCount(contexts, 1);
+ ExpectBackupCount(contexts, 0);
sim.Update(1000); //2
systems.CurrentTick.ShouldBe((uint)3);
ExpectEntityCount(contexts, 1);
- ExpectBackupCount(contexts, 1);
+ ExpectBackupCount(contexts, 0);
commandBuffer.Insert(1, 1, new ICommand[] { });
sim.Update(1000); //3
systems.CurrentTick.ShouldBe((uint)4);
ExpectEntityCount(contexts, 1);
- ExpectBackupCount(contexts, 1);
-
-
- commandBuffer.Insert(2, 1, new ICommand[] { new MoveAll(contexts.game), });
+ ExpectBackupCount(contexts, 1);
+ commandBuffer.Insert(2, 1, new ICommand[] { new MoveAll(contexts.game, 1) });
sim.Update(1000); //4
systems.CurrentTick.ShouldBe((uint)5);
ExpectEntityCount(contexts, 1);
ExpectBackupCount(contexts, 2);
- for (int i = 0; i < 1; i++)
- {
- sim.Execute(new Spawn());
- }
+ sim.Execute(new Spawn());
sim.Update(1000); //5
systems.CurrentTick.ShouldBe((uint)6);
ExpectEntityCount(contexts, 2);
- ExpectBackupCount(contexts, 3);
+ ExpectBackupCount(contexts, 2);
-
- for (int i = 0; i < 1; i++)
- {
- sim.Execute(new Spawn());
- }
+ sim.Execute(new Spawn());
sim.Update(1000); //6
ExpectEntityCount(contexts, 3);
- ExpectBackupCount(contexts, 4);
+ ExpectBackupCount(contexts, 2);
commandBuffer.Insert(3, 1, new ICommand[] { }); //Revert to 3
sim.Update(1000);
ExpectEntityCount(contexts, 3);
- ExpectBackupCount(contexts, 4);
+ ExpectBackupCount(contexts, 3);
sim.Update(1000);
commandBuffer.Insert(4, 1, new ICommand[] { });
- for (int i = 0; i < 1; i++)
- {
- sim.Execute(new Spawn());
- }
+ sim.Execute(new Spawn());
+
sim.Update(1000);
ExpectEntityCount(contexts, 4);
- ExpectBackupCount(contexts, 5);
+ ExpectBackupCount(contexts, 4);
sim.Update(1000);
sim.Update(1000);
- for (int i = 0; i < 1; i++)
- {
- commandBuffer.Insert(5, 1, new ICommand[] { new Spawn() });
- }
- sim.Update(1000);
+ commandBuffer.Insert(5, 1, new ICommand[] { new Spawn() });
+ sim.Update(1000);
ExpectEntityCount(contexts, 5);
}
@@ -258,7 +223,7 @@ public void TestEntityRollbackWithLocalChanges()
GameEntityCountMatchesActorEntityCount(contexts, 0, 1);
GameEntityCountMatchesActorEntityCount(contexts, 1, 0);
- commandBuffer.Insert(2, 1, new ICommand[] { new MoveAll(contexts.game), });
+ commandBuffer.Insert(2, 1, new ICommand[] { new MoveAll(contexts.game, 1) });
sim.Update(1000); //4
systems.CurrentTick.ShouldBe(frameCounter++);
@@ -271,7 +236,7 @@ public void TestEntityRollbackWithLocalChanges()
ExpectEntityCount(contexts, 1);
ExpectBackupCount(contexts, 1);
- sim.Execute(new MoveEntitesOfSpecificActor(contexts.game, 0));
+ sim.Execute(new MoveEntitesOfSpecificActor(contexts.game, 0, Vector2.Zero));
sim.Update(1000); //6
systems.CurrentTick.ShouldBe(frameCounter++);
@@ -285,7 +250,7 @@ public void TestEntityRollbackWithLocalChanges()
sim.Update(1000); //7
systems.CurrentTick.ShouldBe(frameCounter++);
ExpectEntityCount(contexts, 2);
- ExpectBackupCount(contexts, 2);
+ ExpectBackupCount(contexts, 3);
GameEntityCountMatchesActorEntityCount(contexts, 0, 1);
GameEntityCountMatchesActorEntityCount(contexts, 1, 1);
@@ -294,7 +259,7 @@ public void TestEntityRollbackWithLocalChanges()
sim.Update(1000); //8
systems.CurrentTick.ShouldBe(frameCounter++);
ExpectEntityCount(contexts, 3);
- ExpectBackupCount(contexts, 4);
+ ExpectBackupCount(contexts, 6);
GameEntityCountMatchesActorEntityCount(contexts, 0, 1);
GameEntityCountMatchesActorEntityCount(contexts, 1, 2);
@@ -303,7 +268,7 @@ public void TestEntityRollbackWithLocalChanges()
sim.Update(1000);
systems.CurrentTick.ShouldBe(frameCounter++);
ExpectEntityCount(contexts, 9);
- ExpectBackupCount(contexts, 7);
+ ExpectBackupCount(contexts, 15);
GameEntityCountMatchesActorEntityCount(contexts, 0, 1);
GameEntityCountMatchesActorEntityCount(contexts, 1, 8);
@@ -315,22 +280,259 @@ public void TestEntityRollbackWithLocalChanges()
systems.CurrentTick.ShouldBe(frameCounter++);
sim.Execute(new Spawn());
- commandBuffer.Insert(6, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1), });
+ commandBuffer.Insert(6, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1, Vector2.Zero) });
sim.Update(1000);
ExpectEntityCount(contexts, 10);
- ExpectBackupCount(contexts, 16);
+ ExpectBackupCount(contexts, 24);
GameEntityCountMatchesActorEntityCount(contexts, 0, 2);
GameEntityCountMatchesActorEntityCount(contexts, 1, 8);
sim.Execute(new Spawn());
- commandBuffer.Insert(11, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1), });
+ commandBuffer.Insert(11, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1, new Vector2(3,4)) });
sim.Update(1000);
ExpectEntityCount(contexts, 11);
- ExpectBackupCount(contexts, 25);
+ ExpectBackupCount(contexts, 33);
GameEntityCountMatchesActorEntityCount(contexts, 0, 3);
GameEntityCountMatchesActorEntityCount(contexts, 1, 8);
+
+ _output.WriteLine("========================================");
+
+ var input = systems.GameLog.Log;
+ var finalTick = systems.CurrentTick;
+ var finalHash = contexts.gameState.hashCode.value;
+
+ commandBuffer.Buffer.ShouldBeEmpty();
+ var debug = systems.Services.Get();
+
+ contexts.Reset();
+ systems = new World(contexts, new TestLogger(_output));
+ sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
+ sim.Initialize(new Init { TargetFPS = 1, AllActors = new byte[] { 0, 1 }, ActorID = 0 });
+
+ foreach (var (occurTickId, tickCommands) in input)
+ {
+ foreach (var (tickId, allCommands) in tickCommands)
+ {
+ foreach (var (actorId, commands) in allCommands)
+ {
+ if (actorId == 0)
+ {
+ _output.WriteLine("Local: " + commands.Count + " commands");
+
+ systems.AddInput(tickId, actorId, commands);
+ }
+ else
+ {
+ commandBuffer.Insert(tickId, actorId, commands.ToArray());
+ }
+ }
+ }
+ }
+
+ while (systems.CurrentTick < finalTick)
+ {
+ sim.Update(1);
+ if (debug.HasHash(systems.CurrentTick))
+ {
+ debug.GetHash(systems.CurrentTick).ShouldBe(contexts.gameState.hashCode.value);
+ }
+ }
+
+ contexts.gameState.hashCode.value.ShouldBe(finalHash);
+ }
+ [Fact]
+ public void TestGameLogReplay()
+ {
+ var contexts = new Contexts();
+
+ var systems = new World(contexts, new TestLogger(_output));
+ var commandBuffer = new CommandBuffer();
+
+ var sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
+
+ sim.Initialize(new Init { TargetFPS = 1, AllActors = new byte[] { 0, 1 }, ActorID = 0 });
+
+ sim.Update(1000); //0
+
+ sim.Execute(new Spawn());
+
+ sim.Update(1000); //1
+ sim.Update(1000); //2
+ sim.Update(1000); //3
+
+ commandBuffer.Insert(2, 1, new ICommand[] { new MoveAll(contexts.game, 1) });
+
+ sim.Update(1000); //4
+ sim.Update(1000); //5
+
+ sim.Execute(new MoveEntitesOfSpecificActor(contexts.game, 0, Vector2.Zero));
+
+ sim.Update(1000); //6
+
+ commandBuffer.Insert(3, 1, new ICommand[] { new Spawn() }); //Revert to 3
+
+ sim.Update(1000); //7
+
+ commandBuffer.Insert(4, 1, new ICommand[] { new Spawn() }); //Revert to 4
+
+ sim.Update(1000); //8
+
+ commandBuffer.Insert(5, 1, new ICommand[] { new Spawn(), new Spawn(), new Spawn(), new Spawn(), new Spawn(), new Spawn(), new Spawn() }); //Revert to 5
+
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Update(1000);
+
+ sim.Execute(new Spawn());
+ sim.Execute(new MoveAll(contexts.game, 0));
+ commandBuffer.Insert(6, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1, Vector2.Zero) });
+
+ sim.Update(1000);
+
+ sim.Execute(new Spawn());
+ commandBuffer.Insert(11, 1, new ICommand[] { new MoveEntitesOfSpecificActor(contexts.game, 1, new Vector2(3, 4)) });
+ sim.Update(1000);
+
+ _output.WriteLine("========================================");
+
+ var input = systems.GameLog.Log;
+ var finalTick = systems.CurrentTick;
+ var finalHash = contexts.gameState.hashCode.value;
+
+ commandBuffer.Buffer.ShouldBeEmpty();
+ var debug = systems.Services.Get();
+
+ contexts.Reset();
+ systems = new World(contexts, new TestLogger(_output));
+ sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
+ sim.Initialize(new Init { TargetFPS = 1, AllActors = new byte[] { 0, 1 }, ActorID = 0 });
+
+ foreach (var (occurTickId, tickCommands) in input)
+ {
+ foreach (var (tickId, allCommands) in tickCommands)
+ {
+ foreach (var (actorId, commands) in allCommands)
+ {
+ if (actorId == 0)
+ {
+ _output.WriteLine("Local: " + commands.Count + " commands");
+
+ systems.AddInput(tickId, actorId, commands);
+ }
+ else
+ {
+ commandBuffer.Insert(tickId, actorId, commands.ToArray());
+ }
+ }
+ }
+ }
+
+ while (systems.CurrentTick < finalTick)
+ {
+ sim.Update(1);
+ if (debug.HasHash(systems.CurrentTick))
+ {
+ debug.GetHash(systems.CurrentTick).ShouldBe(contexts.gameState.hashCode.value);
+ }
+ }
+
+ contexts.gameState.hashCode.value.ShouldBe(finalHash);
+ }
+ [Fact]
+ //This test requires a navigation-service that just sets the position to destination: entity.ReplacePosition(entity.destination.value);
+ public void TestCommandUsesCorrectEntityIds()
+ {
+ var contexts = new Contexts();
+
+ var systems = new World(contexts, new TestLogger(_output));
+ var commandBuffer = new CommandBuffer();
+
+ var sim = new Simulation(systems, commandBuffer) { LagCompensation = 0, SendCommandsToBuffer = false };
+
+ sim.Initialize(new Init { TargetFPS = 1, AllActors = new byte[] { 0, 1 }, ActorID = 0 });
+
+
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Update(1000);
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Update(1000);
+
+ var selection = new uint[] { 0, 1, 3, 13 };
+ var destination = new Vector2(14 , 15);
+
+ commandBuffer.Insert(1, 1, new ICommand[] {
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn() });
+
+ commandBuffer.Insert(8, 1, new ICommand[] {
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn(),
+ new Spawn() });
+ commandBuffer.Insert(9, 1, new ICommand[]
+ {
+ new MoveSelection(selection, destination)
+ });
+
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Execute(new Spawn());
+ sim.Update(1000);
+
+ sim.Execute(new MoveSelection(new uint[]{1,4,2,8,3}, destination));
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Update(1000);
+ sim.Update(1000);
+ contexts.game.GetEntities(GameMatcher.Id).Where(entity => entity.actorId.value == 1).Select(entity => entity.id.value).ShouldBeUnique();
+ contexts.game.GetEntities(GameMatcher.Id)
+ .Where(entity => entity.actorId.value == 1 && selection.Contains(entity.id.value))
+ .Select(entity => entity.position.value).ShouldAllBe(vector2 => vector2.X == destination.X && vector2.Y == destination.Y);
+
+ destination = new Vector2(5, 15);
+ commandBuffer.Insert(10, 1, new ICommand[]
+ {
+ new MoveSelection(selection, destination)
+ });
+
+ sim.Update(1000);
+ contexts.game.GetEntities(GameMatcher.Id).Where(entity => entity.actorId.value == 1).Select(entity => entity.id.value).ShouldBeUnique();
+ contexts.game.GetEntities(GameMatcher.Id)
+ .Where(entity => entity.actorId.value == 1 && selection.Contains(entity.id.value))
+ .Select(entity => entity.position.value).ShouldAllBe(vector2 => vector2.X == destination.X && vector2.Y == destination.Y);
}
[Fact]
@@ -382,44 +584,70 @@ public void Execute(InputEntity e)
}
}
- //Hacky commands, don't do this in production. Commands should only modify the given input-entity
public class MoveAll : ICommand
- {
+ {
private readonly GameContext _contexts;
+ private readonly byte _actorId;
+ private uint[] selection;
- public MoveAll(GameContext contexts)
+ public MoveAll(GameContext contexts, byte actorId)
{
_contexts = contexts;
+ _actorId = actorId;
+ selection = _contexts.GetEntities(GameMatcher.LocalId).Where(entity => entity.actorId.value == _actorId)
+ .Select(entity => entity.id.value).ToArray();
}
public void Execute(InputEntity e)
{
- foreach (var gameEntity in _contexts.GetEntities(GameMatcher.LocalId))
- {
- gameEntity.ReplacePosition(new Vector2(2, 2));
- }
- }
+ e.AddSelection(selection);
+ e.AddCoordinate(new Vector2(2, 2));
+ }
}
+
public class MoveEntitesOfSpecificActor : ICommand
{
private readonly GameContext _contexts;
private readonly byte _actorId;
+ private readonly Vector2 _dest;
+ private uint[] selection;
- public MoveEntitesOfSpecificActor(GameContext contexts, byte actorId)
+ public MoveEntitesOfSpecificActor(GameContext contexts, byte actorId, Vector2 dest)
{
_contexts = contexts;
_actorId = actorId;
+ _dest = dest;
+
+ selection = _contexts.GetEntities(GameMatcher.LocalId).Where(entity => entity.actorId.value == _actorId).Select(entity => entity.id.value).ToArray();
}
public void Execute(InputEntity e)
{
- foreach (var gameEntity in _contexts.GetEntities(GameMatcher.LocalId).Where(entity => entity.actorId.value == _actorId))
- {
- gameEntity.ReplacePosition(new Vector2(2, 2));
- }
+ e.AddSelection(selection);
+ e.AddCoordinate(_dest);
+ e.AddTargetActorId(_actorId);
+
+ }
+ }
+
+ public class MoveSelection : ICommand
+ {
+ private readonly uint[] _selection;
+ private readonly Vector2 _destination;
+
+ public MoveSelection(uint[] selection, Vector2 destination)
+ {
+ _selection = selection;
+ _destination = destination;
}
+ public void Execute(InputEntity e)
+ {
+ e.AddSelection(_selection);
+ e.AddCoordinate(_destination);
+ }
}
}
+
}
diff --git a/Engine/Test/Test.csproj b/Engine/Test/Test.csproj
index 78e5889..9f8db19 100644
--- a/Engine/Test/Test.csproj
+++ b/Engine/Test/Test.csproj
@@ -34,4 +34,13 @@
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
diff --git a/Unity/Assets/Integration/BEPUutilities.dll b/Unity/Assets/Integration/BEPUutilities.dll
index ef002e3..5805c07 100644
Binary files a/Unity/Assets/Integration/BEPUutilities.dll and b/Unity/Assets/Integration/BEPUutilities.dll differ
diff --git a/Unity/Assets/Integration/BEPUutilities.dll.mdb b/Unity/Assets/Integration/BEPUutilities.dll.mdb
new file mode 100644
index 0000000..6c53d1f
Binary files /dev/null and b/Unity/Assets/Integration/BEPUutilities.dll.mdb differ
diff --git a/Unity/Assets/Integration/Lockstep.Core.dll.mdb.meta b/Unity/Assets/Integration/BEPUutilities.dll.mdb.meta
similarity index 74%
rename from Unity/Assets/Integration/Lockstep.Core.dll.mdb.meta
rename to Unity/Assets/Integration/BEPUutilities.dll.mdb.meta
index ed189eb..c07c2c9 100644
--- a/Unity/Assets/Integration/Lockstep.Core.dll.mdb.meta
+++ b/Unity/Assets/Integration/BEPUutilities.dll.mdb.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: e5525b9d03bec99428536dbc44bc43c5
+guid: 519cd96ebdb47f54c94f3ee4617e170d
DefaultImporter:
externalObjects: {}
userData:
diff --git a/Unity/Assets/Integration/FixMath.NET.dll b/Unity/Assets/Integration/FixMath.NET.dll
index 13aafbd..c01fa24 100644
Binary files a/Unity/Assets/Integration/FixMath.NET.dll and b/Unity/Assets/Integration/FixMath.NET.dll differ
diff --git a/Unity/Assets/Integration/FixMath.NET.dll.mdb b/Unity/Assets/Integration/FixMath.NET.dll.mdb
new file mode 100644
index 0000000..1308cfd
Binary files /dev/null and b/Unity/Assets/Integration/FixMath.NET.dll.mdb differ
diff --git a/Unity/Assets/Scripts/Commands.meta b/Unity/Assets/Integration/FixMath.NET.dll.mdb.meta
similarity index 67%
rename from Unity/Assets/Scripts/Commands.meta
rename to Unity/Assets/Integration/FixMath.NET.dll.mdb.meta
index d72543e..5efcfd9 100644
--- a/Unity/Assets/Scripts/Commands.meta
+++ b/Unity/Assets/Integration/FixMath.NET.dll.mdb.meta
@@ -1,6 +1,5 @@
fileFormatVersion: 2
-guid: 1ac998c1e1661fd42af4b3bda201f9f8
-folderAsset: yes
+guid: 8bb751eecd3ab7a47aa22761b49051fc
DefaultImporter:
externalObjects: {}
userData:
diff --git a/Unity/Assets/Integration/Lockstep.Client.deps.json b/Unity/Assets/Integration/Lockstep.Client.deps.json
index 4cfc5a2..c3a95ac 100644
--- a/Unity/Assets/Integration/Lockstep.Client.deps.json
+++ b/Unity/Assets/Integration/Lockstep.Client.deps.json
@@ -11,7 +11,10 @@
"dependencies": {
"Core": "1.0.0",
"Lockstep.Network": "1.0.0",
- "NETStandard.Library": "2.0.3"
+ "NETStandard.Library": "2.0.3",
+ "BEPUutilities": "1.5.0.0",
+ "Entitas": "0.0.0.0",
+ "FixMath.NET": "1.0.0.0"
},
"runtime": {
"Lockstep.Client.dll": {}
@@ -25,9 +28,6 @@
},
"Core/1.0.0": {
"dependencies": {
- "Entitas": "0.0.0.0",
- "BEPUutilities": "1.5.0.0",
- "FixMath.NET": "1.0.0.0",
"Entitas.CodeGeneration.Attributes": "0.0.0.0",
"DesperateDevs.Utils": "0.0.0.0"
},
@@ -40,23 +40,23 @@
"Lockstep.Network.dll": {}
}
},
- "Entitas.Reference/0.0.0.0": {
+ "BEPUutilities/1.5.0.0": {
"runtime": {
- "Entitas.dll": {
- "assemblyVersion": "0.0.0.0",
+ "BEPUutilities.dll": {
+ "assemblyVersion": "1.5.0.0",
"fileVersion": "0.0.0.0"
}
}
},
- "BEPUutilities.Reference/1.5.0.0": {
+ "Entitas/0.0.0.0": {
"runtime": {
- "BEPUutilities.dll": {
- "assemblyVersion": "1.5.0.0",
+ "Entitas.dll": {
+ "assemblyVersion": "0.0.0.0",
"fileVersion": "0.0.0.0"
}
}
},
- "FixMath.NET.Reference/1.0.0.0": {
+ "FixMath.NET/1.0.0.0": {
"runtime": {
"FixMath.NET.dll": {
"assemblyVersion": "1.0.0.0",
@@ -112,17 +112,17 @@
"serviceable": false,
"sha512": ""
},
- "Entitas.Reference/0.0.0.0": {
+ "BEPUutilities/1.5.0.0": {
"type": "reference",
"serviceable": false,
"sha512": ""
},
- "BEPUutilities.Reference/1.5.0.0": {
+ "Entitas/0.0.0.0": {
"type": "reference",
"serviceable": false,
"sha512": ""
},
- "FixMath.NET.Reference/1.0.0.0": {
+ "FixMath.NET/1.0.0.0": {
"type": "reference",
"serviceable": false,
"sha512": ""
diff --git a/Unity/Assets/Integration/Lockstep.Client.deps.json.meta b/Unity/Assets/Integration/Lockstep.Client.deps.json.meta
index d3bf87f..3e61fc2 100644
--- a/Unity/Assets/Integration/Lockstep.Client.deps.json.meta
+++ b/Unity/Assets/Integration/Lockstep.Client.deps.json.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: f0f6a6a10e51e01458ac0f2b82f6e87d
+guid: 92438ca6807eda74c946d800dd0772c3
TextScriptImporter:
externalObjects: {}
userData:
diff --git a/Unity/Assets/Integration/Lockstep.Client.dll b/Unity/Assets/Integration/Lockstep.Client.dll
index 0d9db6b..820ae1d 100644
Binary files a/Unity/Assets/Integration/Lockstep.Client.dll and b/Unity/Assets/Integration/Lockstep.Client.dll differ
diff --git a/Unity/Assets/Integration/Lockstep.Client.dll.meta b/Unity/Assets/Integration/Lockstep.Client.dll.meta
index b1b4dc1..bf9a493 100644
--- a/Unity/Assets/Integration/Lockstep.Client.dll.meta
+++ b/Unity/Assets/Integration/Lockstep.Client.dll.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: ca1d17b043bd96b45b16484310e0c175
+guid: b590b5c1953ff4a498947c8e1b6077e9
PluginImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Unity/Assets/Integration/Lockstep.Client.pdb.meta b/Unity/Assets/Integration/Lockstep.Client.pdb.meta
index 88d0bdd..398ce19 100644
--- a/Unity/Assets/Integration/Lockstep.Client.pdb.meta
+++ b/Unity/Assets/Integration/Lockstep.Client.pdb.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: a181bebce9a5a474eb3f809f4fd8ffa8
+guid: 424d8ccc96e61164ca327661360064b2
DefaultImporter:
externalObjects: {}
userData:
diff --git a/Unity/Assets/Integration/Lockstep.Core.dll b/Unity/Assets/Integration/Lockstep.Core.dll
index 271b9fa..c7bc3fa 100644
Binary files a/Unity/Assets/Integration/Lockstep.Core.dll and b/Unity/Assets/Integration/Lockstep.Core.dll differ
diff --git a/Unity/Assets/Integration/Lockstep.Core.dll.mdb b/Unity/Assets/Integration/Lockstep.Core.dll.mdb
index 9aebcf4..b7acf1c 100644
Binary files a/Unity/Assets/Integration/Lockstep.Core.dll.mdb and b/Unity/Assets/Integration/Lockstep.Core.dll.mdb differ
diff --git a/Unity/Assets/Integration/Lockstep.Core.dll.meta b/Unity/Assets/Integration/Lockstep.Core.dll.meta
index 6fa39c8..5d3391a 100644
--- a/Unity/Assets/Integration/Lockstep.Core.dll.meta
+++ b/Unity/Assets/Integration/Lockstep.Core.dll.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 8e72ba2a3ed579a488597effe3f8e208
+guid: b1b3238031e73d448af7f633056a804a
PluginImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Unity/Assets/Integration/Lockstep.Core.pdb.meta b/Unity/Assets/Integration/Lockstep.Core.pdb.meta
index c03bdae..5c235f4 100644
--- a/Unity/Assets/Integration/Lockstep.Core.pdb.meta
+++ b/Unity/Assets/Integration/Lockstep.Core.pdb.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: bd0d65c2573aa3d4ca4030c9de4c17fb
+guid: 5fa3cd151dd86bf41ac3b64248cac38d
DefaultImporter:
externalObjects: {}
userData:
diff --git a/Unity/Assets/Scenes/SampleScene.unity b/Unity/Assets/Scenes/SampleScene.unity
index 062f323..5ef91c2 100644
--- a/Unity/Assets/Scenes/SampleScene.unity
+++ b/Unity/Assets/Scenes/SampleScene.unity
@@ -372,6 +372,7 @@ RectTransform:
- {fileID: 1549690252}
- {fileID: 855587569}
- {fileID: 1923207267}
+ - {fileID: 904096880}
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -612,6 +613,214 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 855587568}
m_CullTransparentMesh: 0
+--- !u!1 &904096879
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 904096880}
+ - component: {fileID: 904096883}
+ - component: {fileID: 904096882}
+ - component: {fileID: 904096881}
+ m_Layer: 5
+ m_Name: Log input to file
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &904096880
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 904096879}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children:
+ - {fileID: 1416586627}
+ m_Father: {fileID: 97464393}
+ m_RootOrder: 5
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 0.5, y: 0.5}
+ m_AnchoredPosition: {x: 209, y: 182}
+ m_SizeDelta: {x: 200, y: 30}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &904096881
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 904096879}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 904096882}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 1524441391}
+ m_MethodName: DumpInputContext
+ m_Mode: 1
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument:
+ m_BoolArgument: 0
+ m_CallState: 2
+ m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
+ Culture=neutral, PublicKeyToken=null
+--- !u!114 &904096882
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 904096879}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+ Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+--- !u!222 &904096883
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 904096879}
+ m_CullTransparentMesh: 0
+--- !u!1 &1416586626
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1416586627}
+ - component: {fileID: 1416586629}
+ - component: {fileID: 1416586628}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1416586627
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1416586626}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 904096880}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1416586628
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1416586626}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+ Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Dump InputContext to file
+--- !u!222 &1416586629
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1416586626}
+ m_CullTransparentMesh: 0
--- !u!1 &1524441390
GameObject:
m_ObjectHideFlags: 0
diff --git a/Unity/Assets/Scripts/Commands/CommandTag.cs b/Unity/Assets/Scripts/Commands/CommandTag.cs
deleted file mode 100644
index 6e05086..0000000
--- a/Unity/Assets/Scripts/Commands/CommandTag.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-public enum CommandTag : ushort
-{
- Spawn,
- Navigate
-}
diff --git a/Unity/Assets/Scripts/Commands/CommandTag.cs.meta b/Unity/Assets/Scripts/Commands/CommandTag.cs.meta
deleted file mode 100644
index 63232bc..0000000
--- a/Unity/Assets/Scripts/Commands/CommandTag.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: e4223b766c0ceb143b394e520d8c33dc
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Unity/Assets/Scripts/Commands/NavigateCommand.cs.meta b/Unity/Assets/Scripts/Commands/NavigateCommand.cs.meta
deleted file mode 100644
index 437f104..0000000
--- a/Unity/Assets/Scripts/Commands/NavigateCommand.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: efee9af8b5ab4be4fa819c2fea33a97d
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Unity/Assets/Scripts/Commands/SpawnCommand.cs.meta b/Unity/Assets/Scripts/Commands/SpawnCommand.cs.meta
deleted file mode 100644
index d1dca46..0000000
--- a/Unity/Assets/Scripts/Commands/SpawnCommand.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: d1aa00ba0d55f9f47a91de3c76383b40
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Unity/Assets/Scripts/RTSEntitySpawner.cs b/Unity/Assets/Scripts/RTSEntitySpawner.cs
index be54a2b..2ad4ca4 100644
--- a/Unity/Assets/Scripts/RTSEntitySpawner.cs
+++ b/Unity/Assets/Scripts/RTSEntitySpawner.cs
@@ -1,4 +1,4 @@
-using Lockstep.Commands;
+using Lockstep.Client.Commands;
using UnityEngine;
using Vector2 = BEPUutilities.Vector2;
diff --git a/Unity/Assets/Scripts/RTSNetworkedSimulation.cs b/Unity/Assets/Scripts/RTSNetworkedSimulation.cs
index f18640e..845a1b7 100644
--- a/Unity/Assets/Scripts/RTSNetworkedSimulation.cs
+++ b/Unity/Assets/Scripts/RTSNetworkedSimulation.cs
@@ -1,11 +1,19 @@
-using System.Collections;
+
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using Entitas;
using Lockstep.Client;
+using Lockstep.Client.Commands;
using Lockstep.Client.Implementations;
using Lockstep.Client.Interfaces;
-using Lockstep.Commands;
using Lockstep.Core;
using Lockstep.Core.Interfaces;
using Lockstep.Network.Messages;
+using Lockstep.Network.Utils;
using UnityEngine;
public class RTSNetworkedSimulation : MonoBehaviour
@@ -21,6 +29,9 @@ public class RTSNetworkedSimulation : MonoBehaviour
public bool Connected => _client.Connected;
+ public byte PlayerId { get; private set; }
+ public byte[] AllActorIds { get; private set; }
+
private NetworkCommandBuffer _remoteCommandBuffer;
private readonly LiteNetLibClient _client = new LiteNetLibClient();
@@ -45,7 +56,9 @@ private void Awake()
}
private void StartSimulation(Init data)
- {
+ {
+ PlayerId = data.ActorID;
+ AllActorIds = data.AllActors;
Debug.Log($"Starting simulation. Total actors: {data.AllActors.Length}. Local ActorID: {data.ActorID}");
Simulation.Initialize(data);
@@ -53,6 +66,45 @@ private void StartSimulation(Init data)
}
+ public void DumpInputContext()
+ {
+ var serializer = new Serializer();
+ serializer.Put(Contexts.sharedInstance.gameState.hashCode.value);
+ serializer.Put(Contexts.sharedInstance.gameState.tick.value);
+ serializer.Put(PlayerId);
+ serializer.PutBytesWithLength(AllActorIds);
+ IFormatter formatter = new BinaryFormatter();
+
+ Stream stream = new FileStream(@"C:\Log\"+ PlayerId + "_"+ Contexts.sharedInstance.gameState.hashCode.value+"_log.txt", FileMode.Create, FileAccess.Write);
+ stream.Write(serializer.Data, 0, serializer.Length);
+ formatter.Serialize(stream, Systems.GameLog);
+ stream.Close();
+
+
+ var data = new List();
+ foreach (var entity in Contexts.sharedInstance.game.GetEntities(GameMatcher.AllOf(GameMatcher.Id, GameMatcher.ActorId)).OrderBy(entity => entity.actorId.value).ThenBy(entity => entity.id.value))
+ {
+ data.Add(entity.actorId.value.ToString());
+ data.Add(entity.id.value.ToString());
+ data.Add(entity.position.value.ToString());
+ data.Add("----------");
+ }
+ File.WriteAllLines(@"C:\Log\" + PlayerId + "_" + Contexts.sharedInstance.gameState.hashCode.value + "_Ents.txt", data);
+
+
+ data = new List();
+ foreach (var entity in Contexts.sharedInstance.input.GetEntities())
+ {
+ data.Add(entity.actorId.value.ToString());
+ data.Add(entity.tick.value.ToString());
+ data.Add(entity.hasCoordinate.ToString());
+ data.Add(entity.hasSelection.ToString());
+ data.Add("----------");
+ }
+ File.WriteAllLines(@"C:\Log\" + PlayerId + "_" + Contexts.sharedInstance.gameState.hashCode.value + "_Input.txt", data);
+ }
+
+
public void Execute(ISerializableCommand command)
{
Simulation.Execute(command);
@@ -67,8 +119,7 @@ private void Start()
private void OnDestroy()
{
_client.Stop();
- }
-
+ }
void Update()
{
@@ -86,4 +137,4 @@ public IEnumerator AutoConnect()
yield return null;
}
-}
+}
diff --git a/Unity/Assets/Scripts/UnityInput.cs b/Unity/Assets/Scripts/UnityInput.cs
index 253d252..1b92a7e 100644
--- a/Unity/Assets/Scripts/UnityInput.cs
+++ b/Unity/Assets/Scripts/UnityInput.cs
@@ -1,7 +1,7 @@
using System.Linq;
using Entitas;
using FixMath.NET;
-using Lockstep.Commands;
+using Lockstep.Client.Commands;
using UnityEngine;
public class UnityInput : MonoBehaviour
@@ -27,9 +27,14 @@ void Update()
if (Input.GetKeyDown(KeyCode.X))
{
- var e = Contexts.sharedInstance.game.GetEntities(GameMatcher.LocalId).Select(entity => entity.id.value).ToArray();
+ var e = Contexts.sharedInstance.game
+ .GetEntities(GameMatcher.AllOf(
+ GameMatcher.Id,
+ GameMatcher.ActorId))
+ .Where(entity => entity.actorId.value == RTSNetworkedSimulation.Instance.PlayerId)
+ .Select(entity => entity.id.value).ToArray();
- Debug.Log("Navigating: " + string.Join(", ", e));
+ //Debug.Log("Navigating: " + string.Join(", ", e));
RTSNetworkedSimulation.Instance.Execute(new NavigateCommand
{
diff --git a/Unity/Assets/Scripts/UnityServices.cs b/Unity/Assets/Scripts/UnityServices.cs
index a2bd81b..0bdd756 100644
--- a/Unity/Assets/Scripts/UnityServices.cs
+++ b/Unity/Assets/Scripts/UnityServices.cs
@@ -70,7 +70,12 @@ public void DeleteView(uint entityId)
public class UnityLogger : ILogService
{
public void Warn(object message)
- {
+ {
Debug.LogWarning(message);
}
+
+ public void Trace(object message)
+ {
+ //Debug.Log(message);
+ }
}
\ No newline at end of file