mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Expose more state/tick logic to content (#3474)
This commit is contained in:
@@ -518,9 +518,16 @@ namespace Robust.Client
|
||||
{
|
||||
using (_prof.Group("Entity"))
|
||||
{
|
||||
// The last real tick is the current tick! This way we won't be in "prediction" mode.
|
||||
_gameTiming.LastRealTick = _gameTiming.LastProcessedTick = _gameTiming.CurTick;
|
||||
_entityManager.TickUpdate(frameEventArgs.DeltaSeconds, noPredictions: false);
|
||||
if (ContentEntityTickUpdate != null)
|
||||
{
|
||||
ContentEntityTickUpdate.Invoke(frameEventArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The last real tick is the current tick! This way we won't be in "prediction" mode.
|
||||
_gameTiming.LastRealTick = _gameTiming.LastProcessedTick = _gameTiming.CurTick;
|
||||
_entityManager.TickUpdate(frameEventArgs.DeltaSeconds, noPredictions: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,5 +694,7 @@ namespace Robust.Client
|
||||
string? SplashLogo,
|
||||
bool AutoConnect
|
||||
);
|
||||
|
||||
public event Action<FrameEventArgs>? ContentEntityTickUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
var (_, msg) = _queue.Take();
|
||||
// Logger.DebugS("net.ent", "Dispatching: {0}: {1}", seq, msg);
|
||||
DispatchMsgEntity(msg);
|
||||
DispatchReceivedNetworkMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (message.SourceTick <= _gameTiming.LastRealTick)
|
||||
{
|
||||
DispatchMsgEntity(message);
|
||||
DispatchReceivedNetworkMsg(message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -168,20 +168,24 @@ namespace Robust.Client.GameObjects
|
||||
_queue.Add((++_incomingMsgSequence, message));
|
||||
}
|
||||
|
||||
private void DispatchMsgEntity(MsgEntity message)
|
||||
private void DispatchReceivedNetworkMsg(MsgEntity message)
|
||||
{
|
||||
switch (message.Type)
|
||||
{
|
||||
case EntityMessageType.SystemMessage:
|
||||
var msg = message.SystemMessage;
|
||||
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
||||
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalPlayer!.Session), msg)!;
|
||||
ReceivedSystemMessage?.Invoke(this, msg);
|
||||
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
||||
DispatchReceivedNetworkMsg(message.SystemMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void DispatchReceivedNetworkMsg(EntityEventArgs msg)
|
||||
{
|
||||
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
||||
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalPlayer!.Session), msg)!;
|
||||
ReceivedSystemMessage?.Invoke(this, msg);
|
||||
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
||||
}
|
||||
|
||||
private sealed class MessageTickComparer : IComparer<(uint seq, MsgEntity msg)>
|
||||
{
|
||||
public int Compare((uint seq, MsgEntity msg) x, (uint seq, MsgEntity msg) y)
|
||||
|
||||
@@ -4,5 +4,9 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface IClientEntityManager : IEntityManager, IEntityNetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises a networked message as if it had arrived from the sever.
|
||||
/// </summary>
|
||||
public void DispatchReceivedNetworkMsg(EntityEventArgs msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.GameStates;
|
||||
/// <summary>
|
||||
/// Tracks dirty entities on the client for the purposes of gamestatemanager.
|
||||
/// </summary>
|
||||
internal sealed class ClientDirtySystem : EntitySystem
|
||||
public sealed class ClientDirtySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IClientGameTiming _timing = default!;
|
||||
[Dependency] private readonly IComponentFactory _compFact = default!;
|
||||
@@ -65,7 +65,7 @@ internal sealed class ClientDirtySystem : EntitySystem
|
||||
RemovedComponents.GetOrNew(comp.Owner).Add(netId.Value);
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
public void Reset()
|
||||
{
|
||||
DirtyEntities.Clear();
|
||||
RemovedComponents.Clear();
|
||||
|
||||
@@ -192,6 +192,8 @@ namespace Robust.Client.GameStates
|
||||
AckGameState(message.State.ToSequence);
|
||||
}
|
||||
|
||||
public void UpdateFullRep(GameState state) => _processor.UpdateFullRep(state);
|
||||
|
||||
private void HandlePvsLeaveMessage(MsgStateLeavePvs message)
|
||||
{
|
||||
_processor.AddLeavePvsMessage(message);
|
||||
@@ -272,7 +274,7 @@ namespace Robust.Client.GameStates
|
||||
// Update the cached server state.
|
||||
using (_prof.Group("FullRep"))
|
||||
{
|
||||
_processor.UpdateFullRep(curState, _entities);
|
||||
_processor.UpdateFullRep(curState);
|
||||
}
|
||||
|
||||
IEnumerable<EntityUid> createdEntities;
|
||||
@@ -440,7 +442,7 @@ namespace Robust.Client.GameStates
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetPredictedEntities()
|
||||
public void ResetPredictedEntities()
|
||||
{
|
||||
PredictionNeedsResetting = false;
|
||||
|
||||
@@ -587,7 +589,7 @@ namespace Robust.Client.GameStates
|
||||
_network.ClientSendMessage(new MsgStateAck() { Sequence = sequence });
|
||||
}
|
||||
|
||||
private IEnumerable<EntityUid> ApplyGameState(GameState curState, GameState? nextState)
|
||||
public IEnumerable<EntityUid> ApplyGameState(GameState curState, GameState? nextState)
|
||||
{
|
||||
using var _ = _timing.StartStateApplicationArea();
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Robust.Client.GameStates
|
||||
return applyNextState;
|
||||
}
|
||||
|
||||
public void UpdateFullRep(GameState state, IEntityManager entMan)
|
||||
public void UpdateFullRep(GameState state)
|
||||
{
|
||||
// Note: the most recently received server state currently doesn't include pvs-leave messages (detaching
|
||||
// transform to null-space). This is because a client should never predict an entity being moved back from
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -70,6 +72,16 @@ namespace Robust.Client.GameStates
|
||||
/// </summary>
|
||||
void ApplyGameState();
|
||||
|
||||
/// <summary>
|
||||
/// Applies a given set of game states.
|
||||
/// </summary>
|
||||
IEnumerable<EntityUid> ApplyGameState(GameState curState, GameState? nextState);
|
||||
|
||||
/// <summary>
|
||||
/// Resets any entities that have changed while predicting future ticks.
|
||||
/// </summary>
|
||||
void ResetPredictedEntities();
|
||||
|
||||
/// <summary>
|
||||
/// An input command has been dispatched.
|
||||
/// </summary>
|
||||
@@ -82,5 +94,7 @@ namespace Robust.Client.GameStates
|
||||
public void RequestFullState(EntityUid? missingEntity = null);
|
||||
|
||||
uint SystemMessageDispatched<T>(T message) where T : EntityEventArgs;
|
||||
|
||||
void UpdateFullRep(GameState state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace Robust.Client;
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client;
|
||||
|
||||
public interface IGameController
|
||||
{
|
||||
@@ -15,5 +19,12 @@ public interface IGameController
|
||||
/// <param name="address">The server address, such as "ss14://localhost:1212/".</param>
|
||||
/// <param name="text">Informational text on the cause of the reconnect. Empty or null gives a default reason.</param>
|
||||
void Redial(string address, string? text = null);
|
||||
|
||||
/// <summary>
|
||||
/// This event gets invoked prior to performing entity tick update logic. If this is null the game
|
||||
/// controller will simply call <see cref="IEntityManager.TickUpdate(float, bool, Prometheus.Histogram?)"/>.
|
||||
/// This exists to give content module more control over tick updating.
|
||||
/// </summary>
|
||||
event Action<FrameEventArgs>? ContentEntityTickUpdate;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,8 @@ namespace Robust.Client.Player
|
||||
// This happens when the server says "nothing changed!"
|
||||
return;
|
||||
}
|
||||
DebugTools.Assert(_network.IsConnected, "Received player state without being connected?");
|
||||
DebugTools.Assert(_network.IsConnected || _client.RunLevel == ClientRunLevel.SinglePlayerGame // replays use state application.
|
||||
, "Received player state without being connected?");
|
||||
DebugTools.Assert(LocalPlayer != null, "Call Startup()");
|
||||
DebugTools.Assert(LocalPlayer!.Session != null, "Received player state before Session finished setup.");
|
||||
|
||||
@@ -213,7 +214,8 @@ namespace Robust.Client.Player
|
||||
// clear slot, player left
|
||||
if (!hitSet.Contains(existing))
|
||||
{
|
||||
DebugTools.Assert(LocalPlayer!.UserId != existing, "I'm still connected to the server, but i left?");
|
||||
DebugTools.Assert(LocalPlayer!.UserId != existing || _client.RunLevel == ClientRunLevel.SinglePlayerGame, // replays apply player states.
|
||||
"I'm still connected to the server, but i left?");
|
||||
_sessions.Remove(existing);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Robust.UnitTesting
|
||||
public GameControllerOptions Options { get; } = new();
|
||||
public bool ContentStart { get; set; }
|
||||
|
||||
public event Action<FrameEventArgs>? ContentEntityTickUpdate;
|
||||
|
||||
public void Shutdown(string? reason = null)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user