gg.easy.airship 0.1.2127 → 0.1.2128
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Editor/TypescriptServices/Compiler/TypescriptCompilationService.cs +3 -0
- package/Runtime/Code/AirshipConst.cs +2 -2
- package/Runtime/Code/LuauAPI/Bridge.cs +27 -0
- package/Runtime/Code/Network/Simulation/AirshipNetworkedObject.cs +81 -0
- package/Runtime/Code/Network/Simulation/AirshipNetworkedObject.cs.meta +3 -0
- package/Runtime/Code/Network/Simulation/AirshipOfflineRigidbody.cs +55 -0
- package/Runtime/Code/Network/Simulation/AirshipOfflineRigidbody.cs.meta +3 -0
- package/Runtime/Code/Network/Simulation/AirshipSimulationManager.cs +349 -0
- package/Runtime/Code/Network/Simulation/AirshipSimulationManager.cs.meta +3 -0
- package/Runtime/Code/Network/Simulation/History.cs +255 -0
- package/Runtime/Code/Network/Simulation/History.cs.meta +3 -0
- package/Runtime/Code/Network/Simulation.meta +3 -0
- package/Runtime/Code/Network/StateSystem/AirshipNetworkedStateManager.cs +1091 -0
- package/Runtime/Code/Network/StateSystem/AirshipNetworkedStateManager.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovement.cs +106 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovement.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovementInput.cs +26 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovementInput.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovementState.cs +43 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestMovementState.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestNetworkedStateManager.cs +43 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem/TestNetworkedStateManager.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations/TestMovementSystem.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Implementations.meta +3 -0
- package/Runtime/Code/Network/StateSystem/NetworkedStateSystem.cs +87 -0
- package/Runtime/Code/Network/StateSystem/NetworkedStateSystem.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Structures/InputCommand.cs +24 -0
- package/Runtime/Code/Network/StateSystem/Structures/InputCommand.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Structures/StateSnapshot.cs +35 -0
- package/Runtime/Code/Network/StateSystem/Structures/StateSnapshot.cs.meta +3 -0
- package/Runtime/Code/Network/StateSystem/Structures.meta +3 -0
- package/Runtime/Code/Network/StateSystem.meta +3 -0
- package/Runtime/Code/Network/SyncedBlob.cs +26 -0
- package/Runtime/Code/Network/SyncedBlob.cs.meta +3 -0
- package/Runtime/Code/Player/Character/Animation/CharacterAnimationHelper.cs +317 -246
- package/Runtime/Code/Player/Character/Animation/CharacterAnimationHelper.cs.meta +2 -2
- package/Runtime/Code/Player/Character/Animation/ClipReplacer/AnimatorClipReplacer.cs +0 -1
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterAnimationSyncData.cs +41 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterAnimationSyncData.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterMovement.cs +1447 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterMovement.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterMovementSettings.cs +175 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterMovementSettings.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterNetworkedStateManager.cs +43 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterNetworkedStateManager.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterPhysics.cs +441 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/CharacterPhysics.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/Structures/CharacterInputData.cs +47 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/Structures/CharacterInputData.cs.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/Structures/CharacterSnapshotData.cs +189 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/Structures/CharacterSnapshotData.cs.meta +2 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character/Structures.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems/Character.meta +3 -0
- package/Runtime/Code/Player/Character/MovementSystems.meta +3 -0
- package/Runtime/Code/Player/Entity/Animation/Editor/EntityDebugAnimator.cs +1 -0
- package/Runtime/Code/Player/PlayerInfo.cs +1 -2
- package/Runtime/Code/Player/PlayerManagerBridge.cs +1 -1
- package/Runtime/Code/PreventCodeStripping.cs +1 -1
- package/Runtime/Code/TSCodeGen/Editor/CsToTs/TypeScript/Helper.cs +21 -12
- package/Runtime/Code/TSCodeGen/TypeGenerator.cs +5 -5
- package/Runtime/Code/VoiceChat/AirshipUniVoiceNetwork.cs +24 -11
- package/Runtime/Code/VoxelWorld/VoxelWorld.cs +20 -0
- package/Runtime/Code/VoxelWorld/VoxelWorldChunk.cs +11 -0
- package/Runtime/Code/VoxelWorld/VoxelWorldCollision.cs +60 -2
- package/Runtime/Prefabs/Network.prefab +5 -5
- package/Runtime/Scenes/CoreScene.unity +350 -375
- package/ThirdParty/Mirror/Core/NetworkConnectionToClient.cs +1 -1
- package/URP/AirshipURPAsset.asset +1 -1
- package/package.json +1 -1
- package/Runtime/Code/Player/Character/API/CharacterAction.cs +0 -5
- package/Runtime/Code/Player/Character/API/CharacterAction.cs.meta +0 -3
- package/Runtime/Code/Player/Character/API/CharacterMovementData.cs +0 -188
- package/Runtime/Code/Player/Character/API/CharacterMovementData.cs.meta +0 -3
- package/Runtime/Code/Player/Character/API/CharacterPhysics.cs +0 -322
- package/Runtime/Code/Player/Character/API/CharacterPhysics.cs.meta +0 -3
- package/Runtime/Code/Player/Character/API.meta +0 -3
- package/Runtime/Code/Player/Character/MovementSystem/CharacterAnimationSyncData.cs +0 -36
- package/Runtime/Code/Player/Character/MovementSystem/CharacterAnimationSyncData.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/CharacterMovement.cs +0 -1437
- package/Runtime/Code/Player/Character/MovementSystem/CharacterMovement.cs.meta +0 -14
- package/Runtime/Code/Player/Character/MovementSystem/CharacterMovementTests.cs +0 -68
- package/Runtime/Code/Player/Character/MovementSystem/CharacterMovementTests.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictedController.cs +0 -825
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictedController.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictedState.cs +0 -23
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictedState.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionManager.cs +0 -431
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionManager.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionRPC.cs +0 -39
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionRPC.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionRigidbodyController.cs +0 -91
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/AirshipPredictionRigidbodyController.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/AirshipPredictedCharacterMovement.cs +0 -313
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/AirshipPredictedCharacterMovement.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/AirshipPredictionCharacterMovementRPC.cs +0 -19
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/AirshipPredictionCharacterMovementRPC.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/CharacterMovementState.cs +0 -87
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement/CharacterMovementState.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/CharacterMovement.meta +0 -8
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/Rigidbody/AirshipPredictedRigidbody.cs +0 -188
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/Rigidbody/AirshipPredictedRigidbody.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/Rigidbody/AirshipPredictedRigidbodyState.cs +0 -32
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/Rigidbody/AirshipPredictedRigidbodyState.cs.meta +0 -2
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction/Rigidbody.meta +0 -8
- package/Runtime/Code/Player/Character/MovementSystem/ClientPrediction.meta +0 -8
- package/Runtime/Code/Player/Character/MovementSystem.meta +0 -8
- package/Runtime/Code/Player/Character/Net/MoveInputData.cs +0 -42
- package/Runtime/Code/Player/Character/Net/MoveInputData.cs.meta +0 -3
- package/Runtime/Code/Player/Character/Net.meta +0 -3
- /package/Runtime/Code/Player/Character/{CharacterRig.cs → Animation/CharacterRig.cs} +0 -0
- /package/Runtime/Code/Player/Character/{CharacterRig.cs.meta → Animation/CharacterRig.cs.meta} +0 -0
|
@@ -21,6 +21,7 @@ using Newtonsoft.Json.Linq;
|
|
|
21
21
|
using ParrelSync;
|
|
22
22
|
using UnityEditor;
|
|
23
23
|
using UnityEngine;
|
|
24
|
+
using UnityEngine.Android;
|
|
24
25
|
using UnityEngine.PlayerLoop;
|
|
25
26
|
using UnityEngine.Serialization;
|
|
26
27
|
using Debug = UnityEngine.Debug;
|
|
@@ -55,6 +56,7 @@ using Object = UnityEngine.Object;
|
|
|
55
56
|
/// </summary>
|
|
56
57
|
// [InitializeOnLoad]
|
|
57
58
|
public static class TypescriptCompilationService {
|
|
59
|
+
private const int ExitCodeKill = 137;
|
|
58
60
|
private const string TsCompilerService = "Typescript Compilation Service";
|
|
59
61
|
|
|
60
62
|
/// <summary>
|
|
@@ -768,6 +770,7 @@ using Object = UnityEngine.Object;
|
|
|
768
770
|
|
|
769
771
|
proc.Exited += (_, _) => {
|
|
770
772
|
if (proc.ExitCode <= 0) return;
|
|
773
|
+
if (proc.ExitCode == ExitCodeKill) return;
|
|
771
774
|
|
|
772
775
|
Debug.Log("Compiler process exited with code " + proc.ExitCode);
|
|
773
776
|
var progressId = TypescriptProjectsService.Project!.ProgressId;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// ReSharper disable InconsistentNaming
|
|
2
2
|
namespace Code {
|
|
3
3
|
public static class AirshipConst {
|
|
4
|
-
public const int playerVersion =
|
|
4
|
+
public const int playerVersion = 5;
|
|
5
5
|
|
|
6
6
|
/// <summary>
|
|
7
7
|
/// The server will kick clients that have a playerVersion lower than this value.
|
|
8
8
|
/// </summary>
|
|
9
|
-
public const int minAcceptedPlayerVersionOnServer =
|
|
9
|
+
public const int minAcceptedPlayerVersionOnServer = 5;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -389,6 +389,33 @@ public static class Bridge {
|
|
|
389
389
|
public static void UnloadGlobalSceneByName(string sceneName) {
|
|
390
390
|
// InstanceFinder.SceneManager.UnloadGlobalScenes(new SceneUnloadData(sceneName));
|
|
391
391
|
}
|
|
392
|
+
|
|
393
|
+
[LuauAPI(LuauContext.Protected)]
|
|
394
|
+
public static bool IsLowEndDevice() {
|
|
395
|
+
// CPU check
|
|
396
|
+
string cpu = SystemInfo.processorType.ToLower();
|
|
397
|
+
if (cpu.Contains("celeron") || cpu.Contains("pentium") || cpu.Contains("atom")) {
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// GPU check
|
|
402
|
+
string gpu = SystemInfo.graphicsDeviceName.ToLower();
|
|
403
|
+
if (gpu.Contains("intel") || gpu.Contains("uhd") || gpu.Contains("hd graphics")) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// RAM check
|
|
408
|
+
if (SystemInfo.systemMemorySize < 8000) { // Less than 8GB RAM
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// GPU memory check
|
|
413
|
+
if (SystemInfo.graphicsMemorySize < 2000) { // Less than 2GB VRAM
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
392
419
|
|
|
393
420
|
public static void MoveGameObjectToScene(GameObject gameObject, Scene scene) {
|
|
394
421
|
if (LuauCore.IsProtectedScene(scene) && LuauCore.CurrentContext == LuauContext.Game) {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using Mirror;
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
|
|
5
|
+
namespace Code.Network.Simulation
|
|
6
|
+
{
|
|
7
|
+
struct TransformSnapshot
|
|
8
|
+
{
|
|
9
|
+
public Vector3 position;
|
|
10
|
+
public Quaternion rotation;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This component is used to allow lag compensation, prediction, and other networked state systems to
|
|
15
|
+
* work with a networked object controlled by the server.
|
|
16
|
+
*
|
|
17
|
+
* When this component is placed on a object being networked with Mirror, the server can include it
|
|
18
|
+
* in lag compensation and clients can resimulate their predictions more accurately.
|
|
19
|
+
*/
|
|
20
|
+
public class AirshipNetworkedObject : NetworkBehaviour
|
|
21
|
+
{
|
|
22
|
+
private History<TransformSnapshot> history;
|
|
23
|
+
|
|
24
|
+
private void Start()
|
|
25
|
+
{
|
|
26
|
+
if (isServer && authority)
|
|
27
|
+
{
|
|
28
|
+
history = new History<TransformSnapshot>(NetworkServer.sendRate);
|
|
29
|
+
AirshipSimulationManager.Instance.OnCaptureSnapshot += this.CaptureSnapshot;
|
|
30
|
+
AirshipSimulationManager.Instance.OnSetSnapshot += this.SetSnapshot;
|
|
31
|
+
AirshipSimulationManager.Instance.OnLagCompensationCheck += this.LagCompensationCheck;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (isClient && !authority)
|
|
35
|
+
{
|
|
36
|
+
history = new History<TransformSnapshot>(NetworkClient.sendRate);
|
|
37
|
+
AirshipSimulationManager.Instance.OnCaptureSnapshot += this.CaptureSnapshot;
|
|
38
|
+
AirshipSimulationManager.Instance.OnSetSnapshot += this.SetSnapshot;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private void OnDestroy()
|
|
43
|
+
{
|
|
44
|
+
AirshipSimulationManager.Instance.OnCaptureSnapshot -= this.CaptureSnapshot;
|
|
45
|
+
AirshipSimulationManager.Instance.OnSetSnapshot -= this.SetSnapshot;
|
|
46
|
+
AirshipSimulationManager.Instance.OnLagCompensationCheck -= this.LagCompensationCheck;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private void CaptureSnapshot(double time, bool replay)
|
|
50
|
+
{
|
|
51
|
+
if (replay)
|
|
52
|
+
{
|
|
53
|
+
var state = this.history.Get(time);
|
|
54
|
+
this.transform.position = state.position;
|
|
55
|
+
this.transform.rotation = state.rotation;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.history.Add(time, new TransformSnapshot()
|
|
60
|
+
{
|
|
61
|
+
position = this.transform.position,
|
|
62
|
+
rotation = this.transform.rotation
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private void SetSnapshot(object objTime)
|
|
67
|
+
{
|
|
68
|
+
if (objTime is double time) {
|
|
69
|
+
var snapshot = this.history.Get(time);
|
|
70
|
+
this.transform.position = snapshot.position;
|
|
71
|
+
this.transform.rotation = snapshot.rotation;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private void LagCompensationCheck(int clientId, double time, double latency)
|
|
76
|
+
{
|
|
77
|
+
var bufferedTime = time - latency - NetworkClient.bufferTime;
|
|
78
|
+
this.SetSnapshot(bufferedTime);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using UnityEngine;
|
|
3
|
+
|
|
4
|
+
namespace Code.Network.Simulation
|
|
5
|
+
{
|
|
6
|
+
/**
|
|
7
|
+
* Disables a rigidbodies physics (sets it to kinematic) when resimulation or lag compensation is taking place.
|
|
8
|
+
*/
|
|
9
|
+
public class AirshipOfflineRigidbody : MonoBehaviour
|
|
10
|
+
{
|
|
11
|
+
public Rigidbody rigidbody;
|
|
12
|
+
private bool kinematicSetting = false;
|
|
13
|
+
|
|
14
|
+
private Vector3 position;
|
|
15
|
+
private Quaternion rotation;
|
|
16
|
+
private Vector3 linearVelocity;
|
|
17
|
+
private Vector3 angularVelocity;
|
|
18
|
+
|
|
19
|
+
public void Start()
|
|
20
|
+
{
|
|
21
|
+
this.rigidbody = this.GetComponent<Rigidbody>();
|
|
22
|
+
AirshipSimulationManager.Instance.OnSetPaused += OnPause;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private void OnDestroy()
|
|
26
|
+
{
|
|
27
|
+
AirshipSimulationManager.Instance.OnSetPaused -= OnPause;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private void OnPause(bool paused)
|
|
31
|
+
{
|
|
32
|
+
if (this.rigidbody == null) return;
|
|
33
|
+
if (paused)
|
|
34
|
+
{
|
|
35
|
+
this.kinematicSetting = this.rigidbody.isKinematic;
|
|
36
|
+
this.rigidbody.isKinematic = true;
|
|
37
|
+
this.position = this.rigidbody.position;
|
|
38
|
+
this.rotation = this.rigidbody.rotation;
|
|
39
|
+
this.linearVelocity = this.rigidbody.linearVelocity;
|
|
40
|
+
this.angularVelocity = this.rigidbody.angularVelocity;
|
|
41
|
+
}
|
|
42
|
+
else
|
|
43
|
+
{
|
|
44
|
+
this.rigidbody.isKinematic = this.kinematicSetting;
|
|
45
|
+
this.rigidbody.position = this.position;
|
|
46
|
+
this.rigidbody.rotation = this.rotation;
|
|
47
|
+
if (!this.kinematicSetting)
|
|
48
|
+
{
|
|
49
|
+
this.rigidbody.linearVelocity = this.linearVelocity;
|
|
50
|
+
this.rigidbody.angularVelocity = this.angularVelocity;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Linq;
|
|
4
|
+
using Mirror;
|
|
5
|
+
using UnityEngine;
|
|
6
|
+
using UnityEngine.Serialization;
|
|
7
|
+
|
|
8
|
+
namespace Code.Network.Simulation
|
|
9
|
+
{
|
|
10
|
+
/**
|
|
11
|
+
* Callback used to check the world state at the time requested. You should consider the physics world
|
|
12
|
+
* to be read only while this function executes. Changes to the physics state will be overwritten after
|
|
13
|
+
* your function returns. Use the RollbackComplete callback to modify the physics world based on the
|
|
14
|
+
* results of your check.
|
|
15
|
+
*/
|
|
16
|
+
public delegate void CheckWorld();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Callback used to modify physics in the next server tick. The physics world is set to the most recent
|
|
20
|
+
* server tick, and can be modified freely. These modifications will be reconciled to the clients as part
|
|
21
|
+
* of the next server tick.
|
|
22
|
+
*
|
|
23
|
+
* Use this callback to do things like add impulses to hit characters, move them, or anything else that
|
|
24
|
+
* changes physics results.
|
|
25
|
+
*/
|
|
26
|
+
public delegate void RollbackComplete();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Requests a simulation based on the provided time. Requesting a simulation will roll back the physics
|
|
30
|
+
* world to the snapshot just before or at the base time provided. Calling the returned tick function
|
|
31
|
+
* will advance the simulation and re-simulate the calls to OnPerformTick, Physics.Simulate(), and OnCaptureSnapshot
|
|
32
|
+
*
|
|
33
|
+
* When this call completes, the world will be at the last completed tick.
|
|
34
|
+
*/
|
|
35
|
+
public delegate void PerformResimulate(double baseTime);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Function that will be run when the simulation manager is ready to perform a resimulation. Remember that
|
|
39
|
+
* the simulation base time provided to the resimulate function is the **local time** you wish to resimulate from.
|
|
40
|
+
* The local time should be one provided by the SimulationManager during a tick.
|
|
41
|
+
* Do not pass NetworkTime.time or a similar server derived time to this resimulate function.
|
|
42
|
+
*
|
|
43
|
+
* This function should not be used on the server.
|
|
44
|
+
*/
|
|
45
|
+
public delegate void PerformResimulationCallback(PerformResimulate simulateFunction);
|
|
46
|
+
|
|
47
|
+
struct LagCompensationRequest
|
|
48
|
+
{
|
|
49
|
+
public CheckWorld check;
|
|
50
|
+
public RollbackComplete complete;
|
|
51
|
+
public NetworkConnectionToClient client;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
struct ResimulationRequest
|
|
55
|
+
{
|
|
56
|
+
public PerformResimulationCallback callback;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The simulation manager is responsible for calling Physics.Simulate and providing generic hooks for other systems to use.
|
|
61
|
+
* Server authoritative networking uses the simulation manager to perform resimulations of its client predictions.
|
|
62
|
+
*/
|
|
63
|
+
[LuauAPI]
|
|
64
|
+
public class AirshipSimulationManager : Singleton<AirshipSimulationManager>
|
|
65
|
+
{
|
|
66
|
+
/**
|
|
67
|
+
* This function notifies all watching components that a re-simulation
|
|
68
|
+
* is about to occur. The boolean parameter will be true if a re-simulation
|
|
69
|
+
* is about to occur, and will be false if the re-simulation has finished.
|
|
70
|
+
*
|
|
71
|
+
* Most components watching this will want to set their rigidbodies to
|
|
72
|
+
* kinematic if they do not wish to take part in the re-simulation. Physics
|
|
73
|
+
* will be ticked during re-simulation.
|
|
74
|
+
*/
|
|
75
|
+
public event Action<bool> OnSetPaused;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* This action notifies all watching components that they need to set their
|
|
79
|
+
* state to be based on the snapshot captured just before or on the provided
|
|
80
|
+
* time. Components should expect a PerformTick() call sometime after this
|
|
81
|
+
* function completes.
|
|
82
|
+
*/
|
|
83
|
+
public event Action<object> OnSetSnapshot;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* This action notifies listeners that we are performing a lag compensation check.
|
|
87
|
+
* This action is only ever invoked on the server. Components listening to this
|
|
88
|
+
* action should set their state to be what the client would have seen at the provided
|
|
89
|
+
* tick time. Keep in mind, this means that any components the client would have been
|
|
90
|
+
* observing (ie. other player characters) should be rolled back an additional amount to account for the client
|
|
91
|
+
* interpolation. You can convert a time to an exact tick time using
|
|
92
|
+
* GetLastSimulationTime() to find the correct tick time for any given time in the
|
|
93
|
+
* last 1 second.
|
|
94
|
+
*
|
|
95
|
+
* After a lag compensation check is completed, OnSetSnapshot will be called to correct
|
|
96
|
+
* the physics world to it's current state.
|
|
97
|
+
*
|
|
98
|
+
* clientId - The connectionId of the client we are simulating the view of
|
|
99
|
+
* currentTime - The tick time that triggered this compensation check
|
|
100
|
+
* rtt - The estimated time it takes for a message to reach the client and then be returned to the server (aka. ping) (rtt / 2 = latency)
|
|
101
|
+
*/
|
|
102
|
+
public event Action<int, double, double> OnLagCompensationCheck;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* This action tells all watching components that they need to perform a tick.
|
|
106
|
+
* A Physics.Simulate() call will be made after PerformTick completes.
|
|
107
|
+
*/
|
|
108
|
+
public event Action<double, bool> OnPerformTick;
|
|
109
|
+
|
|
110
|
+
public event Action<object, object> OnTick;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Informs all watching components that the simulation tick has been performed
|
|
114
|
+
* and that a new snapshot of the resulting Physics.Simulate() should be captured.
|
|
115
|
+
* This snapshot should be the state for the provided tick number in history.
|
|
116
|
+
*/
|
|
117
|
+
public event Action<double, bool> OnCaptureSnapshot;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Fired when a tick leaves local history and will never be referenced again. You can use this
|
|
121
|
+
* event to clean up any data that is no longer required.
|
|
122
|
+
*/
|
|
123
|
+
public event Action<object> OnHistoryLifetimeReached;
|
|
124
|
+
|
|
125
|
+
[NonSerialized] public bool replaying = false;
|
|
126
|
+
|
|
127
|
+
private bool isActive = false;
|
|
128
|
+
private List<double> tickTimes = new List<double>();
|
|
129
|
+
private List<LagCompensationRequest> lagCompensationRequests = new();
|
|
130
|
+
private Queue<ResimulationRequest> resimulationRequests = new();
|
|
131
|
+
|
|
132
|
+
public void ActivateSimulationManager()
|
|
133
|
+
{
|
|
134
|
+
if (isActive) return;
|
|
135
|
+
Physics.simulationMode = SimulationMode.Script;
|
|
136
|
+
this.isActive = true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public void FixedUpdate()
|
|
140
|
+
{
|
|
141
|
+
// Clients use their own timelines for physics. Do not compare times generated on a client with a time generated
|
|
142
|
+
// on the server. The Server should estimate when a client created a command using it's own timeline and ping calculations
|
|
143
|
+
// and a client should convert server authoritative state received to its own timeline by interpolating with NetworkTime.time
|
|
144
|
+
// and capturing snapshots of the interpolated state on its own timeline.
|
|
145
|
+
var time = NetworkServer.active ? NetworkTime.time : Time.unscaledTimeAsDouble;
|
|
146
|
+
|
|
147
|
+
if (!isActive) return;
|
|
148
|
+
if (Physics.simulationMode != SimulationMode.Script) return;
|
|
149
|
+
|
|
150
|
+
// Before running any commands, we perform any resimulation requests that were made during
|
|
151
|
+
// the last tick. This ensures that resimulations don't affect command processing and
|
|
152
|
+
// that all commands run on the most up to date predictions.
|
|
153
|
+
var resimBackTo = time;
|
|
154
|
+
while (this.resimulationRequests.TryDequeue(out ResimulationRequest request))
|
|
155
|
+
{
|
|
156
|
+
try
|
|
157
|
+
{
|
|
158
|
+
request.callback((requestedTime) =>
|
|
159
|
+
{
|
|
160
|
+
if (resimBackTo > requestedTime) resimBackTo = requestedTime;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (Exception e)
|
|
164
|
+
{
|
|
165
|
+
Debug.LogError(e);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Only resimulate once. Go back to the farthest back time that was requested.
|
|
170
|
+
if (resimBackTo != time) this.PerformResimulation(resimBackTo);
|
|
171
|
+
|
|
172
|
+
// Perform the standard tick behavior
|
|
173
|
+
OnPerformTick?.Invoke(time, false);
|
|
174
|
+
OnTick?.Invoke(time, false);
|
|
175
|
+
// Debug.Log("Simulate call. Main Tick: " + NetworkTime.time);
|
|
176
|
+
Physics.Simulate(Time.fixedDeltaTime);
|
|
177
|
+
OnCaptureSnapshot?.Invoke(time, false);
|
|
178
|
+
|
|
179
|
+
// Process any lag compensation requests now that we have completed the ticking and snapshot creation
|
|
180
|
+
// Note: This process is placed after snapshot processing so that changes made to physics (like an impulse)
|
|
181
|
+
// are processed on the _next_ tick. This is safe because the server never resimulates.
|
|
182
|
+
var processedLagCompensation = false;
|
|
183
|
+
foreach (var request in this.lagCompensationRequests)
|
|
184
|
+
{
|
|
185
|
+
processedLagCompensation = true;
|
|
186
|
+
try
|
|
187
|
+
{
|
|
188
|
+
// Debug.LogWarning("Server lag compensation rolling back for client " + request.client.connectionId);
|
|
189
|
+
OnLagCompensationCheck?.Invoke(request.client.connectionId, time,
|
|
190
|
+
request.client.rtt);
|
|
191
|
+
request.check();
|
|
192
|
+
}
|
|
193
|
+
catch (Exception e)
|
|
194
|
+
{
|
|
195
|
+
Debug.LogError(e);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// If we processed lag compensation, we have some additional work to do
|
|
200
|
+
if (processedLagCompensation)
|
|
201
|
+
{
|
|
202
|
+
// Debug.LogWarning("Server completed " + this.lagCompensationRequests.Count + " lag compensation requests. Resetting to current tick (" + time + ") and finalizing.");
|
|
203
|
+
// Reset back to the server view of the world at the current time.
|
|
204
|
+
OnSetSnapshot?.Invoke(time);
|
|
205
|
+
// Invoke all of the callbacks for modifying physics that should be applied in the next tick.
|
|
206
|
+
while (this.lagCompensationRequests.Count > 0)
|
|
207
|
+
{
|
|
208
|
+
this.lagCompensationRequests[0].complete();
|
|
209
|
+
this.lagCompensationRequests.RemoveAt(0);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Add our completed tick time into our history
|
|
214
|
+
this.tickTimes.Add(time);
|
|
215
|
+
// Keep the tick history around only for 1 second. This limits our lag compensation amount.
|
|
216
|
+
while (this.tickTimes.Count > 0 && time - this.tickTimes[0] > 1)
|
|
217
|
+
{
|
|
218
|
+
OnHistoryLifetimeReached?.Invoke(this.tickTimes[0]);
|
|
219
|
+
this.tickTimes.RemoveAt(0);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Submits callbacks to be run later that will be able to view the physics world as the client
|
|
225
|
+
* would have seen it at the current tick. This allows you to confirm if a clients input would
|
|
226
|
+
* have hit a target from their point of view.
|
|
227
|
+
*
|
|
228
|
+
* This uses the clients estimated round trip time to determine what tick the client was likely
|
|
229
|
+
* seeing and rolls back Physics to that tick. Once physics is rolled back, the callback function
|
|
230
|
+
* is executed.
|
|
231
|
+
*/
|
|
232
|
+
public void ScheduleLagCompensation(NetworkConnectionToClient client, CheckWorld checkCallback,
|
|
233
|
+
RollbackComplete completeCallback)
|
|
234
|
+
{
|
|
235
|
+
this.lagCompensationRequests.Add(new LagCompensationRequest()
|
|
236
|
+
{
|
|
237
|
+
check = checkCallback,
|
|
238
|
+
complete = completeCallback,
|
|
239
|
+
client = client,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Schedules a resimulation to occur on the next tick. This allows correcting predicted history on a non authoritative client.
|
|
245
|
+
* The callback provided will be called when the resimulation should occur. The callback will be passed a resimulate
|
|
246
|
+
* function to trigger a resimulation of all ticks from the provided base time back to the present time.
|
|
247
|
+
*/
|
|
248
|
+
public void ScheduleResimulation(PerformResimulationCallback callback)
|
|
249
|
+
{
|
|
250
|
+
this.resimulationRequests.Enqueue(new ResimulationRequest() { callback = callback });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Allows typescript to request a resimulation from the provided time.
|
|
255
|
+
*/
|
|
256
|
+
public void RequestResimulation(double time)
|
|
257
|
+
{
|
|
258
|
+
this.ScheduleResimulation((resim => resim(time)));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Requests a simulation based on the provided time. Requesting a simulation will roll back the physics
|
|
263
|
+
* world to the snapshot just before or at the base time provided. Calling the returned tick function
|
|
264
|
+
* will advance the simulation and re-simulate the calls to OnPerformTick, Physics.Simulate(), and OnCaptureSnapshot
|
|
265
|
+
*
|
|
266
|
+
* This function is used internally to implement the scheduled resimulations.
|
|
267
|
+
*/
|
|
268
|
+
private void PerformResimulation(double baseTime)
|
|
269
|
+
{
|
|
270
|
+
Debug.Log($"T:{Time.unscaledTimeAsDouble} Resimulating from {baseTime}");
|
|
271
|
+
|
|
272
|
+
if (replaying)
|
|
273
|
+
{
|
|
274
|
+
Debug.LogWarning("Resim already active");
|
|
275
|
+
throw new ApplicationException(
|
|
276
|
+
"Re-simulation requested while a re-simulation is already active. Report this.");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// If the base time further in the past that our history goes, we reset to the oldest history we have (0) instead.
|
|
280
|
+
int tickIndex = this.CalculateIndexBeforeTime(baseTime);
|
|
281
|
+
|
|
282
|
+
this.replaying = true;
|
|
283
|
+
try
|
|
284
|
+
{
|
|
285
|
+
OnSetPaused?.Invoke(true);
|
|
286
|
+
OnSetSnapshot?.Invoke(this.tickTimes[tickIndex]);
|
|
287
|
+
Physics.SyncTransforms();
|
|
288
|
+
// Advance the tick so that we are re-processing the next tick after the base time provided.
|
|
289
|
+
tickIndex++;
|
|
290
|
+
|
|
291
|
+
while (tickIndex < this.tickTimes.Count)
|
|
292
|
+
{
|
|
293
|
+
OnPerformTick?.Invoke(this.tickTimes[tickIndex], true);
|
|
294
|
+
// Debug.Log("Simulate call. Replay Tick: " + this.tickTimes[tickIndex]);
|
|
295
|
+
Physics.Simulate(Time.fixedDeltaTime);
|
|
296
|
+
OnCaptureSnapshot?.Invoke(this.tickTimes[tickIndex], true);
|
|
297
|
+
tickIndex++;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
OnSetPaused?.Invoke(false);
|
|
301
|
+
}
|
|
302
|
+
catch (Exception e)
|
|
303
|
+
{
|
|
304
|
+
Debug.LogError(e);
|
|
305
|
+
}
|
|
306
|
+
finally
|
|
307
|
+
{
|
|
308
|
+
this.replaying = false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Gets the exact time of the last simulation provided a given time less than 1 second ago.
|
|
314
|
+
* Does not get times into the future.
|
|
315
|
+
*/
|
|
316
|
+
public double GetLastSimulationTime(double time)
|
|
317
|
+
{
|
|
318
|
+
var index = this.CalculateIndexBeforeTime(time);
|
|
319
|
+
return this.tickTimes[index];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Calculates the index of the tick time just before or exactly at the time provided.
|
|
324
|
+
*/
|
|
325
|
+
private int CalculateIndexBeforeTime(double baseTime)
|
|
326
|
+
{
|
|
327
|
+
if (this.tickTimes.Count == 0)
|
|
328
|
+
{
|
|
329
|
+
throw new ApplicationException("Resimulation requested before any ticks have occured. Report this.");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
int afterIndex = this.tickTimes.FindIndex((time) =>
|
|
333
|
+
{
|
|
334
|
+
if (time > baseTime) return true;
|
|
335
|
+
return false;
|
|
336
|
+
});
|
|
337
|
+
if (afterIndex == -1)
|
|
338
|
+
{
|
|
339
|
+
Debug.LogWarning("Time calculation request used a base time of " + baseTime +
|
|
340
|
+
", but the last tick time was " + this.tickTimes[^1] +
|
|
341
|
+
". Current time is: " + NetworkTime.time + ". Is your network ok?");
|
|
342
|
+
return this.tickTimes.Count - 1;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// If the base time further in the past that our history goes, we reset to the oldest history we have (0) instead.
|
|
346
|
+
return afterIndex == 0 ? 0 : afterIndex - 1;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|