gg.easy.airship 0.1.2127 → 0.1.2129
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/Artifacts/AirshipLocalArtifactDatabase.cs +17 -17
- package/Editor/Artifacts/AirshipReconciliationService.cs +3 -3
- package/Editor/TypescriptServices/Compiler/TypescriptCompilationService.cs +3 -0
- package/Runtime/Code/AirshipConst.cs +2 -2
- package/Runtime/Code/Luau/AirshipComponent.cs +8 -3
- 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 +1094 -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 +1496 -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 +45 -11
- package/Runtime/Code/VoxelWorld/Editor/VoxelBuilderEditorWindow.cs +49 -62
- package/Runtime/Code/VoxelWorld/Editor/VoxelWorldEditor.cs +296 -251
- package/Runtime/Code/VoxelWorld/VoxelWorld.cs +20 -0
- package/Runtime/Code/VoxelWorld/VoxelWorldChunk.cs +227 -188
- package/Runtime/Code/VoxelWorld/VoxelWorldCollision.cs +60 -2
- package/Runtime/Plugins/Android/libLuauPlugin.so +0 -0
- package/Runtime/Plugins/Linux/libLuauPlugin.so +0 -0
- package/Runtime/Plugins/Mac/LuauPlugin.bundle/Contents/MacOS/LuauPlugin +0 -0
- package/Runtime/Plugins/Windows/x64/LuauPlugin.dll +0 -0
- package/Runtime/Plugins/Windows/x64/LuauPlugin.pdb +0 -0
- package/Runtime/Plugins/iOS/LuauPluginIos.a +0 -0
- 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
|
@@ -51,17 +51,17 @@ namespace Airship.Editor {
|
|
|
51
51
|
|
|
52
52
|
[CanBeNull] public GameObject Prefab => asset != null ? AssetDatabase.LoadAssetAtPath<GameObject>(asset) : null;
|
|
53
53
|
|
|
54
|
-
/// <summary>
|
|
55
|
-
/// Will return if the given component is synchronized with this data
|
|
56
|
-
/// </summary>
|
|
57
|
-
/// <param name="component">The component</param>
|
|
58
|
-
/// <returns>True if the component matches this data</returns>
|
|
59
|
-
public bool IsSyncedWith(AirshipComponent component) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
54
|
+
// /// <summary>
|
|
55
|
+
// /// Will return if the given component is synchronized with this data
|
|
56
|
+
// /// </summary>
|
|
57
|
+
// /// <param name="component">The component</param>
|
|
58
|
+
// /// <returns>True if the component matches this data</returns>
|
|
59
|
+
// public bool IsSyncedWith(AirshipComponent component) {
|
|
60
|
+
// if (guid != component.guid) return false;
|
|
61
|
+
// if (metadata == null) return false;
|
|
62
|
+
//
|
|
63
|
+
// return component.componentHash == metadata.hash;
|
|
64
|
+
// }
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
[Serializable]
|
|
@@ -94,12 +94,12 @@ namespace Airship.Editor {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
/// <summary>
|
|
98
|
-
/// Will return true if the hash of the component isn't the same as the DB stored script hash
|
|
99
|
-
/// </summary>
|
|
100
|
-
public bool IsNotSameHashAsComponent(AirshipComponent component) {
|
|
101
|
-
|
|
102
|
-
}
|
|
97
|
+
// /// <summary>
|
|
98
|
+
// /// Will return true if the hash of the component isn't the same as the DB stored script hash
|
|
99
|
+
// /// </summary>
|
|
100
|
+
// public bool IsNotSameHashAsComponent(AirshipComponent component) {
|
|
101
|
+
// return component.componentHash != metadata.hash;
|
|
102
|
+
// }
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/// <summary>
|
|
@@ -192,7 +192,7 @@ namespace Airship.Editor {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
#endif
|
|
195
|
-
component.componentHash = component.script.sourceFileHash;
|
|
195
|
+
// component.componentHash = component.script.sourceFileHash;
|
|
196
196
|
return true;
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -328,7 +328,7 @@ namespace Airship.Editor {
|
|
|
328
328
|
// We can run a default reconcile, it wont matter tbh.
|
|
329
329
|
var component = eventData.Component;
|
|
330
330
|
ReconcileComponent(component);
|
|
331
|
-
component.componentHash = component.scriptHash;
|
|
331
|
+
//component.componentHash = component.scriptHash;
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -374,7 +374,7 @@ namespace Airship.Editor {
|
|
|
374
374
|
else {
|
|
375
375
|
var component = eventData.Component;
|
|
376
376
|
ReconcileComponent(component);
|
|
377
|
-
component.componentHash = component.scriptHash;
|
|
377
|
+
//component.componentHash = component.scriptHash;
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
}
|
|
@@ -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
|
}
|
|
@@ -72,11 +72,16 @@ public class AirshipComponent : MonoBehaviour {
|
|
|
72
72
|
#if UNITY_EDITOR
|
|
73
73
|
internal static event ReconcileAirshipComponent Reconcile;
|
|
74
74
|
[SerializeField] internal string guid;
|
|
75
|
-
[SerializeField] private string hash;
|
|
75
|
+
// [SerializeField] private string hash;
|
|
76
76
|
|
|
77
|
+
[Obsolete]
|
|
77
78
|
internal string componentHash {
|
|
78
|
-
get
|
|
79
|
-
|
|
79
|
+
get {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
set {
|
|
83
|
+
_ = value;
|
|
84
|
+
}
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
internal string scriptHash => script.sourceFileHash;
|
|
@@ -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
|
+
}
|