From dc075d6b05269ade2130c8a416353567195b25c2 Mon Sep 17 00:00:00 2001 From: Aristeas <94058548+Jnick-24@users.noreply.github.com> Date: Fri, 16 Feb 2024 22:12:41 -0600 Subject: [PATCH] netcode update #1230 --- .../Data/Scripts/HeartModule/HeartLoad.cs | 9 ++- .../HeartModule/Projectiles/Projectile.cs | 17 +++- .../Projectiles/ProjectileManager.cs | 4 +- .../ProjectileManager_Networking.cs | 8 +- .../n_SerializableProjectileInfo.cs | 79 +++++++++++++++++++ .../n_SerializableProjectile.cs | 4 +- 6 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileNetworking/n_SerializableProjectileInfo.cs diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/HeartLoad.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/HeartLoad.cs index 47aa006c..eb364373 100644 --- a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/HeartLoad.cs +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/HeartLoad.cs @@ -3,14 +3,17 @@ using Heart_Module.Data.Scripts.HeartModule.ErrorHandler; using Heart_Module.Data.Scripts.HeartModule.ExceptionHandler; using Heart_Module.Data.Scripts.HeartModule.Projectiles; +using Heart_Module.Data.Scripts.HeartModule.Projectiles.ProjectileNetworking; using Heart_Module.Data.Scripts.HeartModule.Utility; using Heart_Module.Data.Scripts.HeartModule.Weapons; +using ProtoBuf; using RichHudFramework.Client; using Sandbox.ModAPI; using System; using VRage.Game.Components; using VRage.Game.ModAPI; using VRage.ModAPI; +using VRageMath; using YourName.ModName.Data.Scripts.HeartModule.Weapons.Setup.Adding; using YourName.ModName.Data.Scripts.HeartModule.Weapons.Setup.Hiding; @@ -68,13 +71,17 @@ public override void LoadData() { CriticalHandle.ThrowCriticalException(ex, typeof(HeartLoad)); } + + HeartData.I.Log.Log("Small: " + MyAPIGateway.Utilities.SerializeToBinary(new n_SerializableProjectileInfo(1, Vector3.One, Vector3.Forward, 3, 235345645)).Length); + HeartData.I.Log.Log("Large: " + MyAPIGateway.Utilities.SerializeToBinary(new n_SerializableProjectileInfo(1, Vector3.One, Vector3.Forward, 3, 235345645, 345345, 3453454, 124334)).Length); + HeartData.I.Log.Log("Event: " + MyAPIGateway.Utilities.SerializeToBinary(new n_SerializableFireEvent(1, 234, Vector3.One, 12434)).Length); } public override void UpdateAfterSimulation() { // This has the power to shut down the server. Afaik the only way to do this is throwing an exception. Yeah. handle.Update(); - + byte[] a = BitConverter.GetBytes(1.2f); try { if (HeartData.I.IsSuspended) diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/Projectile.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/Projectile.cs index 4768d20b..87d445d1 100644 --- a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/Projectile.cs +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/Projectile.cs @@ -279,9 +279,10 @@ public float CheckHits() public void UpdateFromSerializable(n_SerializableProjectile projectile) { - QueuedDispose = !projectile.IsActive; + if (projectile.IsActive.HasValue) + QueuedDispose = !projectile.IsActive.Value; - LastUpdate = projectile.Timestamp; + LastUpdate = DateTime.Now.Date.AddMilliseconds(projectile.TimestampFromMidnight).Ticks; float delta = (DateTime.Now.Ticks - LastUpdate) / (float)TimeSpan.TicksPerSecond; // The following values may be null to save network load @@ -315,14 +316,14 @@ public n_SerializableProjectile AsSerializable(int DetailLevel = 1) { n_SerializableProjectile projectile = new n_SerializableProjectile() { - IsActive = !QueuedDispose, Id = Id, - Timestamp = DateTime.Now.Ticks, + TimestampFromMidnight = (uint) DateTime.Now.TimeOfDay.TotalMilliseconds, // Surely this will not bite me in the ass later }; switch (DetailLevel) { case 0: + projectile.IsActive = !QueuedDispose; projectile.DefinitionId = DefinitionId; projectile.Position = Position; projectile.Direction = Direction; @@ -331,12 +332,20 @@ public n_SerializableProjectile AsSerializable(int DetailLevel = 1) //projectile.Velocity = Velocity; break; case 1: + projectile.IsActive = !QueuedDispose; projectile.Position = Position; if (IsHitscan || Definition.Guidance.Length > 0) projectile.Direction = Direction; if (!IsHitscan && Definition.PhysicalProjectile.Acceleration > 0) projectile.Velocity = Velocity; break; + case 3: + projectile.DefinitionId = DefinitionId; + projectile.Position = Position; + projectile.Direction = Direction; + projectile.InheritedVelocity = InheritedVelocity; + projectile.Firer = Firer; + break; } return projectile; diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager.cs index 43bd98c0..20ce89e3 100644 --- a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager.cs +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager.cs @@ -103,7 +103,7 @@ public void UpdateProjectileSync(n_SerializableProjectile projectile) if (MyAPIGateway.Session.IsServer) return; - if (IsIdAvailable(projectile.Id) && projectile.IsActive && projectile.DefinitionId.HasValue) + if (IsIdAvailable(projectile.Id) && projectile.DefinitionId.HasValue) { if (projectile.Firer != null) { @@ -116,7 +116,7 @@ public void UpdateProjectileSync(n_SerializableProjectile projectile) Projectile p = GetProjectile(projectile.Id); if (p != null) p.UpdateFromSerializable(projectile); - else if (projectile.IsActive) + else if (projectile.IsActive ?? false) HeartData.I.Net.SendToServer(new n_ProjectileRequest(projectile.Id)); } } diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager_Networking.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager_Networking.cs index 8d2ec24a..1e16babd 100644 --- a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager_Networking.cs +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileManager_Networking.cs @@ -11,7 +11,8 @@ namespace Heart_Module.Data.Scripts.HeartModule.Projectiles { partial class ProjectileManager { - const int MaxProjectilesSynced = 50; // This value should result in ~100kB/s up per player. + const int MaxProjectilesSynced = 100; // This value should result in ~100kB/s up per player. + const int NetworkInterval = 2; public Dictionary> SyncStream = new Dictionary>(); @@ -40,9 +41,10 @@ public void QueueSync(Projectile projectile, IMyPlayer Player, int DetailLevel = SyncStream[Player.SteamUserId].AddLast(sP); // Queue other projectile updates last } + int tick = 0; public void UpdateSync() { - if (MyAPIGateway.Session.IsServer && MyAPIGateway.Multiplayer.MultiplayerActive) + if (MyAPIGateway.Session.IsServer && MyAPIGateway.Multiplayer.MultiplayerActive && tick % NetworkInterval == 0) { foreach (var player in HeartData.I.Players) // Ensure that all players are being synced { @@ -71,6 +73,8 @@ public void UpdateSync() } } } + + tick++; } private void SyncPlayerProjectiles(IMyPlayer player) diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileNetworking/n_SerializableProjectileInfo.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileNetworking/n_SerializableProjectileInfo.cs new file mode 100644 index 00000000..09d52bd6 --- /dev/null +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/ProjectileNetworking/n_SerializableProjectileInfo.cs @@ -0,0 +1,79 @@ +using ProtoBuf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Policy; +using System.Text; +using System.Threading.Tasks; +using VRageMath; + +namespace Heart_Module.Data.Scripts.HeartModule.Projectiles.ProjectileNetworking +{ + [ProtoContract] + internal class n_SerializableProjectileInfo + { + public n_SerializableProjectileInfo() { } + + public n_SerializableProjectileInfo(uint uniqueProjectileId, Vector3 positionRelativeToPlayer, Vector3 direction, int definitionId, int msFromMidnight, long? firerEntityId = null, long? targetEntityId = null, uint? projectileAge = null) + { + UniqueProjectileId = uniqueProjectileId; + playerRelativeX = positionRelativeToPlayer.X; + playerRelativeY = positionRelativeToPlayer.Y; + playerRelativeZ = positionRelativeToPlayer.Z; + directionX = direction.X; + directionY = direction.Y; + directionZ = direction.Z; + DefinitionId = definitionId; + MillisecondsFromMidnight = msFromMidnight; + FirerEntityId = firerEntityId; + TargetEntityId = targetEntityId; + ProjectileAge = projectileAge; + } + + [ProtoMember(21)] public uint UniqueProjectileId; + + [ProtoMember(22)] private float playerRelativeX; + [ProtoMember(23)] private float playerRelativeY; + [ProtoMember(24)] private float playerRelativeZ; + public Vector3 PlayerRelativePosition => new Vector3(playerRelativeX, playerRelativeY, playerRelativeZ); // just using a Vector3 adds 2 extra bytes (!!!) + + [ProtoMember(25)] private float directionX; + [ProtoMember(26)] private float directionY; + [ProtoMember(27)] private float directionZ; + public Vector3 Direction => new Vector3(directionX, directionY, directionZ); // just using a Vector3 adds 2 extra bytes (!!!) + + [ProtoMember(28)] public int DefinitionId; + [ProtoMember(29)] public int MillisecondsFromMidnight; + [ProtoMember(30)] public long? FirerEntityId; + + [ProtoMember(31)] public long? TargetEntityId; + [ProtoMember(32)] public uint? ProjectileAge; + } + + [ProtoContract] + internal class n_SerializableFireEvent + { + public n_SerializableFireEvent() { } + + public n_SerializableFireEvent(int firerWeaponId, uint uniqueProjectileId, Vector3 direction, int millisecondsFromMidnight) + { + FirerWeaponId = firerWeaponId; + UniqueProjectileId = uniqueProjectileId; + directionX = direction.X; + directionY = direction.Y; + directionZ = direction.Z; + MillisecondsFromMidnight = millisecondsFromMidnight; + } + + [ProtoMember(21)] int FirerWeaponId; + [ProtoMember(22)] uint UniqueProjectileId; + + [ProtoMember(23)] float directionX; + [ProtoMember(24)] float directionY; + [ProtoMember(25)] float directionZ; + public Vector3 Direction => new Vector3(directionX, directionY, directionZ); // just using a Vector3 adds 2 extra bytes (!!!) + + + [ProtoMember(26)] int MillisecondsFromMidnight; + } +} diff --git a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/StandardClasses/n_SerializableProjectile.cs b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/StandardClasses/n_SerializableProjectile.cs index 6c4ba890..e193e4c1 100644 --- a/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/StandardClasses/n_SerializableProjectile.cs +++ b/Orrery Combat Framework - Heart Module/Data/Scripts/HeartModule/Projectiles/StandardClasses/n_SerializableProjectile.cs @@ -12,9 +12,9 @@ namespace Heart_Module.Data.Scripts.HeartModule.Projectiles.StandardClasses public class n_SerializableProjectile : PacketBase { // ProtoMember IDs are high to avoid collisions - [ProtoMember(22)] public bool IsActive = true; + [ProtoMember(22)] public bool? IsActive = true; [ProtoMember(23)] public uint Id; - [ProtoMember(211)] public long Timestamp; + [ProtoMember(211)] public uint TimestampFromMidnight; // surely this will not bite me in the ass later // All non-required values are nullable [ProtoMember(24)] public int? DefinitionId;