Skip to content

Commit

Permalink
Entity Interpolation (space-wizards#789)
Browse files Browse the repository at this point in the history
* add a new GameTick struct.

* Everything now uses the new GameTick struct.

* TickRate was changed to a byte, no way it is going over 255.
Fixed bug with changing TickRate after the loop has started.
Client now properly sets the TickRate when connecting to a server.

* Removed the old CurTime fields from game states.
Getting to the Connected runlevel on the client does not require a gamestate.
GameState processing now only starts after the client runlevel >= Connected.
Added some preprocessor conditions to not catch exceptions in Debug builds.
Nightly work on the GameStateManager, it is still pretty broken.

* NetMessages now have a Size property.
Player states were fixed, you can now join the game again!

* Frame interpolation kinda works.

* Frame Interpolation pretty much works!

* simulation can now catch up if a lag spike causes it to fall behind.

* Added concommand to debug draw the interpolation targets.

* Fixed a bug with applying just the NextState to an entity.

* Skip/replay a tick to slow down if the client is running ahead of the server.

* Solved a null ref exception when an extrapolated packet is applied.

* The TickRate is now officially 10.

* ClientGameStateManager stops running when the client leaves the server.

* Replaced poorly implemented FastForward with new TickTimingAdjustment.

* Update System.Runtime.CompilerServices.Unsafe to get rid of version conflict.

* Added 'net.interp' cvar.

* Disabled frame interpolation by default. The entire feature will be disabled until clientside input prediction is working.

* Removed or disabled log spam.
Fixed Transform unit test.

* Fix compile.
  • Loading branch information
Acruid authored and PJB3005 committed Apr 13, 2019
1 parent 613ad10 commit a2c1ddb
Show file tree
Hide file tree
Showing 63 changed files with 1,077 additions and 320 deletions.
44 changes: 40 additions & 4 deletions SS14.Client/BaseClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using SS14.Client.Interfaces;
using SS14.Client.Interfaces.GameObjects;
using SS14.Client.Interfaces.GameStates;
using SS14.Client.Interfaces.State;
using SS14.Client.Interfaces.Utility;
using SS14.Client.Player;
Expand All @@ -9,6 +10,7 @@
using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.Interfaces.Map;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.Interfaces.Timing;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Network;
Expand All @@ -33,10 +35,20 @@ public class BaseClient : IBaseClient
[Dependency]
private readonly IConfigurationManager _configManager;

[Dependency] private readonly IClientEntityManager _entityManager;
[Dependency]
private readonly IClientEntityManager _entityManager;

[Dependency]
private readonly IMapManager _mapManager;

[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly IDiscordRichPresence _discord;
[Dependency]
private readonly IDiscordRichPresence _discord;

[Dependency]
private readonly IGameTiming _timing;

[Dependency]
private readonly IClientGameStateManager _gameStates;

/// <inheritdoc />
public ushort DefaultPort { get; } = 1212;
Expand Down Expand Up @@ -151,6 +163,8 @@ private void OnNetDisconnect(object sender, NetChannelArgs args)

_stateManager.RequestStateChange<MainScreen>();

_timing.Paused = true;
_gameStates.Shutdown();
_playMan.Shutdown();
_entityManager.Shutdown();
_mapManager.Shutdown();
Expand All @@ -167,6 +181,9 @@ private void HandleServerInfo(MsgServerInfo msg)
info.ServerName = msg.ServerName;
info.ServerMaxPlayers = msg.ServerMaxPlayers;
info.SessionId = msg.PlayerSessionId;
info.TickRate = msg.TickRate;
_timing.TickRate = msg.TickRate;
Logger.InfoS("client", $"Tickrate changed to: {msg.TickRate}");

_discord.Update(info.ServerName, info.SessionId.Username, info.ServerMaxPlayers.ToString());
// start up player management
Expand All @@ -180,6 +197,7 @@ private void HandleServerInfo(MsgServerInfo msg)
private void OnLocalStatusChanged(object obj, StatusEventArgs eventArgs)
{
// player finished fully connecting to the server.
// OldStatus is used here because it can go from connecting-> connected or connecting-> ingame
if (eventArgs.OldStatus == SessionStatus.Connecting)
{
OnPlayerJoinedServer(_playMan.LocalPlayer.Session);
Expand All @@ -195,7 +213,7 @@ private void OnLocalStatusChanged(object obj, StatusEventArgs eventArgs)

private void OnRunLevelChanged(ClientRunLevel newRunLevel)
{
Logger.Debug($"[ENG] Runlevel changed to: {newRunLevel}");
Logger.DebugS("client", $"Runlevel changed to: {newRunLevel}");
var args = new RunLevelChangedEventArgs(RunLevel, newRunLevel);
RunLevel = newRunLevel;
RunLevelChanged?.Invoke(this, args);
Expand All @@ -208,9 +226,25 @@ private void OnRunLevelChanged(ClientRunLevel newRunLevel)
public enum ClientRunLevel
{
Error = 0,

/// <summary>
/// The client has not started connecting to a server (on main menu).
/// </summary>
Initialize,

/// <summary>
/// The client started connecting to the server, and is in the process of building the session.
/// </summary>
Connecting,

/// <summary>
/// The client has successfully finished connecting to the server.
/// </summary>
Connected,

/// <summary>
/// The client is now in the game, moving around.
/// </summary>
InGame,
}

Expand Down Expand Up @@ -273,6 +307,8 @@ public class ServerInfo
/// </summary>
public int ServerMaxPlayers { get; set; }

public byte TickRate { get; internal set; }

public NetSessionId SessionId { get; set; }
}
}
6 changes: 6 additions & 0 deletions SS14.Client/GameController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ private void Update(float frameTime)
_taskManager.ProcessPendingTasks();
_userInterfaceManager.Update(eventArgs);
_stateManager.Update(eventArgs);

if (_client.RunLevel >= ClientRunLevel.Connected)
{
_gameStateManager.ApplyGameState();
}

AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.PostEngine, eventArgs.Elapsed);
}

Expand Down
15 changes: 8 additions & 7 deletions SS14.Client/GameController/GameController.Godot.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using Godot;
using SS14.Client.GodotGlue;
using SS14.Client.Input;
using SS14.Client.Interfaces;
using SS14.Client.Utility;
using SS14.Shared.ContentPack;
using SS14.Shared.Interfaces.Timing;
using SS14.Shared.IoC;
using SS14.Shared.Timing;
Expand Down Expand Up @@ -51,7 +49,7 @@ public override void PhysicsProcess(float delta)
{
if (!_gameTimingGodotGodot.Paused)
{
_gameTimingGodotGodot.CurTick++;
_gameTimingGodotGodot.CurTick = new GameTick(_gameTimingGodotGodot.CurTick.Value + 1);
Update(delta);
}
}
Expand Down Expand Up @@ -201,17 +199,20 @@ public GameTimingGodot()

public double FramesPerSecondAvg => Godot.Performance.GetMonitor(Performance.Monitor.TimeFps);

public uint CurTick { get; set; }
public int TickRate
public GameTick CurTick { get; set; }

public byte TickRate
{
get => Godot.Engine.IterationsPerSecond;
get => (byte) Godot.Engine.IterationsPerSecond;
set => Godot.Engine.IterationsPerSecond = value;
}

public TimeSpan TickPeriod => TimeSpan.FromTicks((long)(1.0 / TickRate * TimeSpan.TicksPerSecond));

public TimeSpan TickRemainder { get; set; }
public uint CurFrame { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool FastForward { get; set; } //TODO: Not implemented
public float TickTimingAdjustment { get; set; } = 1; //TODO: Not implemented

public void ResetRealTime()
{
Expand All @@ -226,7 +227,7 @@ public void StartFrame()
private TimeSpan CalcCurTime()
{
// calculate simulation CurTime
var time = TimeSpan.FromTicks(TickPeriod.Ticks * CurTick);
var time = TimeSpan.FromTicks(TickPeriod.Ticks * CurTick.Value);

if (!InSimulation) // rendering can draw frames between ticks
return time + TickRemainder;
Expand Down
53 changes: 38 additions & 15 deletions SS14.Client/GameObjects/ClientEntityManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using SS14.Client.Interfaces.GameObjects;
using SS14.Shared.GameObjects;
Expand Down Expand Up @@ -111,32 +112,54 @@ public override void Startup()
Started = true;
}

public void ApplyEntityStates(IEnumerable<EntityState> entityStates, IEnumerable<EntityUid> deletions, float serverTime)
public void ApplyEntityStates(List<EntityState> curEntStates, IEnumerable<EntityUid> deletions, List<EntityState> nextEntStates)
{
var toApply = new List<(Entity, EntityState)>();
var toApply = new Dictionary<IEntity, (EntityState, EntityState)>();
var toInitialize = new List<Entity>();
foreach (var es in entityStates)
deletions = deletions ?? new EntityUid[0];

if (curEntStates != null && curEntStates.Count != 0)
{
//Todo defer component state result processing until all entities are loaded and initialized...
es.ReceivedTime = serverTime;
//Known entities
if (Entities.TryGetValue(es.StateData.Uid, out var entity))
foreach (var es in curEntStates)
{
toApply.Add(((Entity)entity, es));
//Known entities
if (Entities.TryGetValue(es.StateData.Uid, out var entity))
{
toApply.Add(entity, (es, null));
}
else //Unknown entities
{
var newEntity = CreateEntity(es.StateData.TemplateName, es.StateData.Uid);
newEntity.Name = es.StateData.Name;
toApply.Add(newEntity, (es, null));
toInitialize.Add(newEntity);
}
}
else //Unknown entities
}

if (nextEntStates != null && nextEntStates.Count != 0)
{
foreach (var es in nextEntStates)
{
var newEntity = CreateEntity(es.StateData.TemplateName, es.StateData.Uid);
newEntity.Name = es.StateData.Name;
toApply.Add((newEntity, es));
toInitialize.Add(newEntity);
if (Entities.TryGetValue(es.StateData.Uid, out var entity))
{
if (toApply.TryGetValue(entity, out var state))
{
toApply[entity] = (state.Item1, es);
}
else
{
toApply[entity] = (null, es);
}
}
}
}

// Make sure this is done after all entities have been instantiated.
foreach (var (entity, es) in toApply)
foreach (var kvStates in toApply)
{
entity.HandleEntityState(es);
var ent = kvStates.Key;
((Entity)ent).HandleEntityState(kvStates.Value.Item1, kvStates.Value.Item2);
}

foreach (var id in deletions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ private void SetData(object key, object value)
AppearanceDirty = true;
}

public override void HandleComponentState(ComponentState state)
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
var actualState = (AppearanceComponentState)state;
if (curState == null)
return;

var actualState = (AppearanceComponentState)curState;
data = actualState.Data;
AppearanceDirty = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,12 @@ public override void Shutdown()
}

/// <inheritdoc />
public override void HandleComponentState(ComponentState state)
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
var newState = (CollidableComponentState) state;
if (curState == null)
return;

var newState = (CollidableComponentState) curState;

// edge triggered
if (newState.CollisionEnabled == _collisionEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,12 @@ public override void OnRemove()
}

/// <inheritdoc />
public override void HandleComponentState(ComponentState state)
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
var newState = (PointLightComponentState) state;
if (curState == null)
return;

var newState = (PointLightComponentState) curState;
State = newState.State;
Color = newState.Color;
Light.ModeClass = newState.Mode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ public override void Initialize()
}

/// <inheritdoc />
public override void HandleComponentState(ComponentState state)
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
var newState = (PhysicsComponentState)state;
if (curState == null)
return;

var newState = (PhysicsComponentState)curState;
Mass = newState.Mass;
Velocity = newState.Velocity;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1567,9 +1567,12 @@ private static void _advanceFrameAnimation(ref Layer layer, RSI.State state, RSI
}
}

public override void HandleComponentState(ComponentState state)
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
var thestate = (SpriteComponentState) state;
if (curState == null)
return;

var thestate = (SpriteComponentState) curState;

Visible = thestate.Visible;
DrawDepth = thestate.DrawDepth;
Expand Down
Loading

0 comments on commit a2c1ddb

Please sign in to comment.