Compare commits

...

5 Commits

Author SHA1 Message Date
Sveske_Juice 0e9b82ca43 Store in circular buffer & gizmo for local and server rope on client 2024-03-17 18:53:53 +01:00
Sveske_Juice c9b874667e Property drawer for circular buffer 2024-03-17 18:17:12 +01:00
Sveske_Juice 35117a5d8b Send game state to client rpc with tick info.
Still WIP on fields in game state (should include player pos, enemies in future)
2024-03-17 17:55:35 +01:00
Sveske_Juice 2d7d7f2d4e Big cleanup of unused packages 2024-03-17 17:36:20 +01:00
Sveske_Juice 2b6f6606fc No need for rope collider and rigidbody on rope points 2024-03-17 13:55:28 +01:00
16 changed files with 159 additions and 204 deletions

View File

@ -9,8 +9,6 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 3817028170077760731} - component: {fileID: 3817028170077760731}
- component: {fileID: 4590407122831754579}
- component: {fileID: 8963967235500975272}
m_Layer: 0 m_Layer: 0
m_Name: RopePoint m_Name: RopePoint
m_TagString: Untagged m_TagString: Untagged
@ -33,66 +31,3 @@ Transform:
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!58 &4590407122831754579
CircleCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4736158799711156794}
m_Enabled: 1
serializedVersion: 3
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 128
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_CompositeOperation: 0
m_CompositeOrder: 0
m_Offset: {x: 0, y: 0}
m_Radius: 0.5
--- !u!50 &8963967235500975272
Rigidbody2D:
serializedVersion: 4
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4736158799711156794}
m_BodyType: 1
m_Simulated: 1
m_UseFullKinematicContacts: 0
m_UseAutoMass: 0
m_Mass: 1
m_LinearDrag: 0
m_AngularDrag: 0.05
m_GravityScale: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_Interpolate: 0
m_SleepingMode: 1
m_CollisionDetection: 0
m_Constraints: 0

View File

@ -1,15 +1,8 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Unity.Mathematics;
using Unity.Netcode; using Unity.Netcode;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
using UnityEngine.AI; using UnityEngine.AI;
using UnityEngine.UIElements;
public class EnemySpawner : NetworkBehaviour public class EnemySpawner : NetworkBehaviour
{ {

View File

@ -2,7 +2,6 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
public class AudioManager : MonoBehaviour public class AudioManager : MonoBehaviour

View File

@ -1,11 +1,6 @@
using Netcode.Transports.Facepunch; using Netcode.Transports.Facepunch;
using Steamworks;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Netcode; using Unity.Netcode;
using Unity.Netcode.Transports.UTP; using Unity.Netcode.Transports.UTP;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;

View File

@ -2,7 +2,6 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Unity.Netcode; using Unity.Netcode;
using Unity.VisualScripting.YamlDotNet.Core.Tokens;
using UnityEngine; using UnityEngine;
public struct MoveData : INetworkSerializable public struct MoveData : INetworkSerializable

View File

@ -0,0 +1,25 @@
using Unity.Netcode;
[System.Serializable]
public struct GameState : INetworkSerializable
{
public int tick;
public NetworkRope nrope;
public override int GetHashCode()
{
return tick;
}
public override bool Equals(object obj)
{
GameState other = (GameState) obj;
return this.GetHashCode() == obj.GetHashCode();
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref tick);
nrope.NetworkSerialize(serializer);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1cdca75ffd9bfc5b9b1c9ffe1a501dcf

View File

@ -9,7 +9,8 @@
"GUID:c0e1b40f519e6e84b8f4af9930403ecb", "GUID:c0e1b40f519e6e84b8f4af9930403ecb",
"GUID:3b8ed52f1b5c64994af4c4e0aa4b6c4b", "GUID:3b8ed52f1b5c64994af4c4e0aa4b6c4b",
"GUID:1491147abca9d7d4bb7105af628b223e", "GUID:1491147abca9d7d4bb7105af628b223e",
"GUID:068707ae079d6e851b7a76adaa3014f8" "GUID:068707ae079d6e851b7a76adaa3014f8",
"GUID:f0aa6e1ec272fc041a727a9dfb7c1e67"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@ -137,6 +137,7 @@ public class Rope
} */ } */
} }
[System.Serializable]
public struct NetworkRope : INetworkSerializable public struct NetworkRope : INetworkSerializable
{ {
// For rope points // For rope points

View File

@ -4,6 +4,8 @@ using System.Linq;
using Unity.Netcode; using Unity.Netcode;
using UnityEngine; using UnityEngine;
using UnityEngine.Assertions; using UnityEngine.Assertions;
using Utilities;
using UnityUtils;
public class RopeSimulator : NetworkBehaviour public class RopeSimulator : NetworkBehaviour
{ {
@ -64,10 +66,14 @@ public class RopeSimulator : NetworkBehaviour
[SerializeField] float pullAnimationOvershootThreshold = 0.2f; [SerializeField] float pullAnimationOvershootThreshold = 0.2f;
[Header("Netcode")] [Header("Netcode")]
private const float k_serverTickRate = 60f;
private const int k_rngSeed = 6969; private const int k_rngSeed = 6969;
private const float k_sendRopeDataRPCThreshold = 0.1f; public float k_ropeReconciliateThreshold = 10f;
public float k_ropeReconciliateThreshold = 8f;
private System.Random rng = new System.Random(k_rngSeed); private System.Random rng = new System.Random(k_rngSeed);
private int currentTick => NetworkManager.Singleton.NetworkTickSystem.LocalTime.Tick;
[SerializeField] private CircularBuffer<GameState> stateBuffer;
private GameState lastReceivedServerGameState;
private const int k_bufferSize = 512;
private int[] order; private int[] order;
@ -92,16 +98,20 @@ public class RopeSimulator : NetworkBehaviour
{ {
Destroy(instance); Destroy(instance);
} }
stateBuffer = new(k_bufferSize);
} }
private void OnEnable() private void OnEnable()
{ {
GameManager.OnPlayersReady += PlayersReady; GameManager.OnPlayersReady += PlayersReady;
NetworkManager.Singleton.NetworkTickSystem.Tick += NetworkTick;
} }
private void OnDisable() private void OnDisable()
{ {
GameManager.OnPlayersReady -= PlayersReady; GameManager.OnPlayersReady -= PlayersReady;
NetworkManager.Singleton.NetworkTickSystem.Tick -= NetworkTick;
} }
public void PlayersReady(GameObject[] players) public void PlayersReady(GameObject[] players)
@ -256,11 +266,6 @@ public class RopeSimulator : NetworkBehaviour
ropeCollider.transform.position = point.position; ropeCollider.transform.position = point.position;
ropeCollider.tag = colliderTag; ropeCollider.tag = colliderTag;
ropeCollider.layer = LayerMask.NameToLayer("Rope"); ropeCollider.layer = LayerMask.NameToLayer("Rope");
ropeCollider.GetComponent<CircleCollider2D>().radius = ropeRadius;
var rigidBody = ropeCollider.GetComponent<Rigidbody2D>();
rigidBody.isKinematic = true;
} }
} }
@ -277,19 +282,43 @@ public class RopeSimulator : NetworkBehaviour
} }
[Rpc(SendTo.NotServer)] [Rpc(SendTo.NotServer)]
private void ServerRopeDataReceivedRpc(NetworkRope nrope) private void ServerToClientGameStateRpc(GameState serverState)
{ {
Debug.Log($"Received rope data from server: {nrope}"); this.lastReceivedServerGameState = serverState;
Rope serverRope = Rope.FromNetworkRope(nrope, distBetweenRopePoints);
float diff = Rope.CalcDiff(this.rope, serverRope); Debug.Log($"Received server state. Server tick: {serverState.tick}, client: {currentTick}");
Debug.Log(diff);
if (diff > k_ropeReconciliateThreshold) // Not enough information
{ if (stateBuffer.Get(serverState.tick).Equals(default(GameState))) return;
// Debug.LogWarning("Reconciliating rope!");
// this.rope = serverRope; // TODO: investigate why this is zero at start of game sometimes
// Debug.Log(Rope.CalcDiff(this.rope, serverRope)); if (stateBuffer.Get(serverState.tick).nrope.positions.Length == 0) return;
Debug.Log($"client len: {stateBuffer.Get(serverState.tick).nrope.positions.Length}, server len {serverState.nrope.positions.Length}");
Rope serverRope = Rope.FromNetworkRope(serverState.nrope, distBetweenRopePoints);
Rope oldLocalRope = Rope.FromNetworkRope(stateBuffer.Get(serverState.tick).nrope, distBetweenRopePoints);
float serverLocalRopeDiff = Rope.CalcDiff(serverRope, oldLocalRope);
Debug.Log($"Server to client sync error: {serverLocalRopeDiff}");
} }
private void NetworkTick()
{
stateBuffer.Add(ProcessGame(), currentTick);
// Send to clients if is server
if (IsServer)
ServerToClientGameStateRpc(stateBuffer.Get(currentTick));
}
private GameState ProcessGame()
{
GameState localState = new() {
tick = currentTick,
nrope = Rope.ToNetworkRope(this.rope)
};
return localState;
} }
private void Update() private void Update()
@ -303,14 +332,6 @@ public class RopeSimulator : NetworkBehaviour
rope.points.Last().position = end.position; rope.points.Last().position = end.position;
float ropeDiff = Simulate(Time.fixedDeltaTime); float ropeDiff = Simulate(Time.fixedDeltaTime);
if (IsServer)
{
Debug.Log($"Sending rope to client");
NetworkRope nrope = Rope.ToNetworkRope(this.rope);
// Send server rope to client for reconciliation
ServerRopeDataReceivedRpc(nrope);
}
// Update the rope collider positions // Update the rope collider positions
for (int i = 0; i < rope.points.Length; i++) for (int i = 0; i < rope.points.Length; i++)
@ -412,14 +433,22 @@ public class RopeSimulator : NetworkBehaviour
private void OnDrawGizmos() private void OnDrawGizmos()
{ {
return; if (!IsInitialized) return;
if (IsInitialized) return;
if (!Application.isPlaying) return; if (!Application.isPlaying) return;
// Local rope
Gizmos.color = Color.green;
foreach (var point in rope.points) foreach (var point in rope.points)
{ {
//Debug.Log($"pos: {point.position}"); Gizmos.DrawSphere(point.position, ropeRadius);
}
// Last received server rope
if (lastReceivedServerGameState.Equals(default(GameState))) return;
Gizmos.color = Color.red;
foreach (var point in Rope.FromNetworkRope(lastReceivedServerGameState.nrope, distBetweenRopePoints).points)
{
Gizmos.DrawSphere(point.position, ropeRadius); Gizmos.DrawSphere(point.position, ropeRadius);
} }
} }

View File

@ -1,6 +1,4 @@
using System.Collections; using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;

View File

@ -1,6 +1,7 @@
[System.Serializable]
public class CircularBuffer<T> { public class CircularBuffer<T> {
T[] buffer; public T[] buffer;
int bufferSize; public int bufferSize;
public CircularBuffer(int bufferSize) { public CircularBuffer(int bufferSize) {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;

View File

@ -0,0 +1,50 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(CircularBuffer<>))]
public class CircularBufferDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
EditorGUI.indentLevel++;
SerializedProperty bufferSizeProp = property.FindPropertyRelative("bufferSize");
int bufferSize = bufferSizeProp.intValue;
EditorGUI.PropertyField(
new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight, position.width, EditorGUIUtility.singleLineHeight),
bufferSizeProp);
SerializedProperty bufferProp = property.FindPropertyRelative("buffer");
EditorGUI.LabelField(
new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * 2, position.width, EditorGUIUtility.singleLineHeight),
"Buffer Elements");
float lineHeight = EditorGUIUtility.singleLineHeight;
float bufferHeight = lineHeight * bufferSize;
Rect bufferRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * 3, position.width, bufferHeight);
EditorGUI.PropertyField(bufferRect, bufferProp, GUIContent.none, true);
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty bufferSizeProp = property.FindPropertyRelative("bufferSize");
int bufferSize = bufferSizeProp.intValue;
return EditorGUIUtility.singleLineHeight * (bufferSize + 3); // 1 for buffer size, 1 for label, and bufferSize for buffer elements
}
}
#endif

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 53ed82cd9cfbdb1868c0d12e415dd33f

View File

@ -1,10 +1,11 @@
{ {
"dependencies": { "dependencies": {
"com.unity.2d.animation": "10.1.1",
"com.unity.2d.pixel-perfect": "5.0.3",
"com.unity.2d.spriteshape": "10.0.3",
"com.unity.2d.tilemap": "1.0.0",
"com.unity.ai.navigation": "2.0.0", "com.unity.ai.navigation": "2.0.0",
"com.unity.cinemachine": "2.9.7", "com.unity.cinemachine": "2.9.7",
"com.unity.collab-proxy": "2.2.0",
"com.unity.feature.2d": "2.0.0",
"com.unity.ide.rider": "3.0.27",
"com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.visualstudio": "2.0.22",
"com.unity.inputsystem": "1.7.0", "com.unity.inputsystem": "1.7.0",
"com.unity.multiplayer.playmode": "0.6.0", "com.unity.multiplayer.playmode": "0.6.0",
@ -15,7 +16,6 @@
"com.unity.timeline": "1.8.6", "com.unity.timeline": "1.8.6",
"com.unity.toolchain.linux-x86_64": "2.0.6", "com.unity.toolchain.linux-x86_64": "2.0.6",
"com.unity.ugui": "2.0.0", "com.unity.ugui": "2.0.0",
"com.unity.visualscripting": "1.9.1",
"com.unity.modules.accessibility": "1.0.0", "com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.ai": "1.0.0", "com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0", "com.unity.modules.androidjni": "1.0.0",

View File

@ -1,11 +1,11 @@
{ {
"dependencies": { "dependencies": {
"com.unity.2d.animation": { "com.unity.2d.animation": {
"version": "10.1.0", "version": "10.1.1",
"depth": 1, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
"com.unity.2d.common": "9.0.3", "com.unity.2d.common": "9.0.4",
"com.unity.2d.sprite": "1.0.0", "com.unity.2d.sprite": "1.0.0",
"com.unity.collections": "1.2.4", "com.unity.collections": "1.2.4",
"com.unity.modules.animation": "1.0.0", "com.unity.modules.animation": "1.0.0",
@ -13,21 +13,9 @@
}, },
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.2d.aseprite": {
"version": "1.1.1",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.common": "6.0.6",
"com.unity.mathematics": "1.2.6",
"com.unity.modules.animation": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.2d.common": { "com.unity.2d.common": {
"version": "9.0.3", "version": "9.0.4",
"depth": 2, "depth": 1,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
"com.unity.2d.sprite": "1.0.0", "com.unity.2d.sprite": "1.0.0",
@ -40,21 +28,11 @@
}, },
"com.unity.2d.pixel-perfect": { "com.unity.2d.pixel-perfect": {
"version": "5.0.3", "version": "5.0.3",
"depth": 1, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": {}, "dependencies": {},
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.2d.psdimporter": {
"version": "9.0.1",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.2d.common": "9.0.2",
"com.unity.2d.sprite": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.2d.sprite": { "com.unity.2d.sprite": {
"version": "1.0.0", "version": "1.0.0",
"depth": 1, "depth": 1,
@ -62,37 +40,25 @@
"dependencies": {} "dependencies": {}
}, },
"com.unity.2d.spriteshape": { "com.unity.2d.spriteshape": {
"version": "10.0.2", "version": "10.0.3",
"depth": 1, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
"com.unity.mathematics": "1.1.0", "com.unity.mathematics": "1.1.0",
"com.unity.2d.common": "9.0.2", "com.unity.2d.common": "9.0.4",
"com.unity.modules.physics2d": "1.0.0" "com.unity.modules.physics2d": "1.0.0"
}, },
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.2d.tilemap": { "com.unity.2d.tilemap": {
"version": "1.0.0", "version": "1.0.0",
"depth": 1, "depth": 0,
"source": "builtin", "source": "builtin",
"dependencies": { "dependencies": {
"com.unity.modules.tilemap": "1.0.0", "com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.uielements": "1.0.0" "com.unity.modules.uielements": "1.0.0"
} }
}, },
"com.unity.2d.tilemap.extras": {
"version": "4.0.2",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.tilemap": "1.0.0",
"com.unity.2d.tilemap": "1.0.0",
"com.unity.ugui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.ai.navigation": { "com.unity.ai.navigation": {
"version": "2.0.0", "version": "2.0.0",
"depth": 0, "depth": 0,
@ -121,13 +87,6 @@
}, },
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.collab-proxy": {
"version": "2.2.0",
"depth": 0,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.collections": { "com.unity.collections": {
"version": "1.4.0", "version": "1.4.0",
"depth": 3, "depth": 3,
@ -146,30 +105,6 @@
"dependencies": {}, "dependencies": {},
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.feature.2d": {
"version": "2.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.2d.animation": "10.1.0",
"com.unity.2d.pixel-perfect": "5.0.3",
"com.unity.2d.psdimporter": "9.0.1",
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.spriteshape": "10.0.2",
"com.unity.2d.tilemap": "1.0.0",
"com.unity.2d.tilemap.extras": "4.0.2",
"com.unity.2d.aseprite": "1.1.1"
}
},
"com.unity.ide.rider": {
"version": "3.0.27",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ext.nunit": "1.0.6"
},
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": { "com.unity.ide.visualstudio": {
"version": "2.0.22", "version": "2.0.22",
"depth": 0, "depth": 0,
@ -356,16 +291,6 @@
"com.unity.modules.imgui": "1.0.0" "com.unity.modules.imgui": "1.0.0"
} }
}, },
"com.unity.visualscripting": {
"version": "1.9.1",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ugui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.modules.accessibility": { "com.unity.modules.accessibility": {
"version": "1.0.0", "version": "1.0.0",
"depth": 0, "depth": 0,