Skip to content

Commit

Permalink
Merge pull request StarCoreSE#15 from Jnick-24/projectile-testing
Browse files Browse the repository at this point in the history
Netcode Updates
  • Loading branch information
ari-steas authored Jan 6, 2024
2 parents f692c76 + 9bd1af5 commit 5b34577
Show file tree
Hide file tree
Showing 19 changed files with 381 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Sandbox.Game;
using Sandbox.Game.Debugging;
using Sandbox.Game.Entities;
using Sandbox.ModAPI;
using System;
using VRage.Utils;

namespace Heart_Module.Data.Scripts.HeartModule.ExceptionHandler
{

public class CriticalHandle
{
const int WarnTimeSeconds = 20;
private static CriticalHandle I;
private long CriticalCloseTime = -1;
private Exception Exception;

public void LoadData()
{
I = this;
}

public void Update()
{
if (CriticalCloseTime == -1)
return;
double secondsRemaining = Math.Round((CriticalCloseTime - DateTime.Now.Ticks) / (double)TimeSpan.TicksPerSecond, 1);

if (secondsRemaining <= 0)
{
CriticalCloseTime = -1;
if (!MyAPIGateway.Utilities.IsDedicated)
MyVisualScriptLogicProvider.SessionClose(1000, false, true);
else
//throw Exception;
MyAPIGateway.Session.Unload();
}

if (!MyAPIGateway.Utilities.IsDedicated)
MyAPIGateway.Utilities.ShowNotification($"HeartMod CRITICAL ERROR - Shutting down in {secondsRemaining}s", 1000 / 60);
}

public void UnloadData()
{
I = null;
}

public static void ThrowCriticalException(Exception ex, Type callingType, ulong callerId = ulong.MaxValue)
{
I?.m_ThrowCriticalException(ex, callingType, callerId);
}

public static void ThrowCriticalException(NetworkedError ex, Type callingType, ulong callerId = ulong.MaxValue)
{
I?.m_ThrowCriticalException(ex, callingType, callerId);
}

private void m_ThrowCriticalException(Exception ex, Type callingType, ulong callerId = ulong.MaxValue)
{
HeartData.I.IsSuspended = true;
HeartData.I.Log.Log("Start Throw Critical Exception " + CriticalCloseTime);
if (CriticalCloseTime != -1)
return;

Exception = ex;
HeartData.I.Log.LogException(ex, callingType, (callerId != ulong.MaxValue ? $"Shared exception from {callerId}: " : "") + "Critical ");
MyAPIGateway.Utilities.ShowMessage("HeartMod", $"CRITICAL ERROR - Shutting down in {WarnTimeSeconds} seconds.");
MyLog.Default.WriteLineAndConsole($"HeartMod: CRITICAL ERROR - Shutting down in {WarnTimeSeconds} seconds.");
CriticalCloseTime = DateTime.Now.Ticks + WarnTimeSeconds * TimeSpan.TicksPerSecond;

if (MyAPIGateway.Session.IsServer)
HeartData.I.Net.SendToEveryone(new NetworkedError(Exception, true));
}

private void m_ThrowCriticalException(NetworkedError ex, Type callingType, ulong callerId = ulong.MaxValue)
{
HeartData.I.IsSuspended = true;
HeartData.I.Log.Log("Start Throw Critical Exception " + CriticalCloseTime);
if (CriticalCloseTime != -1)
return;

Exception = new Exception(ex.ExceptionMessage);
HeartData.I.Log.LogException(ex, callingType, (callerId != ulong.MaxValue ? $"Shared exception from {callerId}: " : "") + "Critical ");
MyAPIGateway.Utilities.ShowMessage("HeartMod", $"CRITICAL ERROR - Shutting down in {WarnTimeSeconds} seconds.");
MyLog.Default.WriteLineAndConsole($"HeartMod: CRITICAL ERROR - Shutting down in {WarnTimeSeconds} seconds.");
CriticalCloseTime = DateTime.Now.Ticks + WarnTimeSeconds * TimeSpan.TicksPerSecond;

if (MyAPIGateway.Session.IsServer)
HeartData.I.Net.SendToEveryone(new NetworkedError(Exception, true));
}
}
}
46 changes: 46 additions & 0 deletions Heart Module/Data/Scripts/HeartModule/ExceptionHandler/HeartLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Sandbox.ModAPI;
using System;
using System.IO;

namespace Heart_Module.Data.Scripts.HeartModule.ExceptionHandler
{
public class HeartLog
{
TextWriter writer;

public HeartLog()
{
writer = MyAPIGateway.Utilities.WriteFileInLocalStorage("debug.log", typeof(HeartLog));
writer.WriteLine("LogStart");
writer.Flush();
}

public void Log(string message)
{
writer.WriteLine($"{DateTime.Now:HH:mm:ss}: {message}");
writer.Flush();
}

public void LogException(Exception ex, Type callingType, string prefix = "")
{
if (ex == null)
{
Log("Null exception! CallingType: " + callingType.FullName);
return;
}

Log(prefix + $"Exception in {callingType.FullName}! {ex.Message}\n{ex.StackTrace}");
}

public void LogException(NetworkedError ex, Type callingType, string prefix = "")
{
if (ex == null)
{
Log("Null exception! CallingType: " + callingType.FullName);
return;
}

Log(prefix + $"Exception in {callingType.FullName}! {ex.ExceptionMessage}\n{ex.ExceptionStackTrace}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Heart_Module.Data.Scripts.HeartModule.ErrorHandler;
using Heart_Module.Data.Scripts.HeartModule.Network;
using ProtoBuf;
using System;

namespace Heart_Module.Data.Scripts.HeartModule.ExceptionHandler
{
[ProtoContract]
public class NetworkedError : PacketBase
{
[ProtoMember(21)] public string ExceptionMessage;
[ProtoMember(22)] public string ExceptionStackTrace;
[ProtoMember(23)] public bool IsCritical;

public NetworkedError() { }
public NetworkedError(Exception e, bool IsCritical)
{
ExceptionMessage = e.Message;
ExceptionStackTrace = e.StackTrace;
this.IsCritical = IsCritical;
}

public override void Received(ulong SenderSteamId)
{
if (IsCritical)
CriticalHandle.ThrowCriticalException(this, typeof(NetworkedError), SenderSteamId);
else
SoftHandle.RaiseException(this, callerId: SenderSteamId);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
using Sandbox.ModAPI;
using Heart_Module.Data.Scripts.HeartModule.ExceptionHandler;
using Sandbox.ModAPI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VRage.Utils;

namespace Heart_Module.Data.Scripts.HeartModule.ErrorHandler
{
public class SoftHandle
{
public static void RaiseException(string message)
public static void RaiseException(string message, Type callingType = null, ulong callerId = ulong.MaxValue)
{
MyAPIGateway.Utilities.ShowNotification(message);
MyLog.Default.WriteLineAndConsole(message);
MyAPIGateway.Utilities.ShowNotification("Minor Exception: " + message);
Exception soft = new Exception(message);
HeartData.I.Log.LogException(soft, callingType ?? typeof(SoftHandle), callerId != ulong.MaxValue ? $"Shared exception from {callerId}: " : "");
if (MyAPIGateway.Session.IsServer)
HeartData.I.Net.SendToEveryone(new NetworkedError(soft, false));
}

public static void RaiseException(Exception exception, Type callingType = null, ulong callerId = ulong.MaxValue)
{
if (exception == null)
return;

MyAPIGateway.Utilities.ShowNotification("Minor Exception: " + exception.Message);
HeartData.I.Log.LogException(exception, callingType ?? typeof(SoftHandle), callerId != ulong.MaxValue ? $"Shared exception from {callerId}: " : "");
}

public static void RaiseException(NetworkedError exception, Type callingType = null, ulong callerId = ulong.MaxValue)
{
if (exception == null)
return;

MyAPIGateway.Utilities.ShowNotification("Minor Exception: " + exception.ExceptionMessage);
HeartData.I.Log.LogException(exception, callingType ?? typeof(SoftHandle), callerId != ulong.MaxValue ? $"Shared exception from {callerId}: " : "");
}

public static void RaiseSyncException(string message)
{
RaiseException("Client is out of sync!\n"+message);
RaiseException("Client is out of sync!\n" + message);
}
}
}
15 changes: 15 additions & 0 deletions Heart Module/Data/Scripts/HeartModule/HeartData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Heart_Module.Data.Scripts.HeartModule.ExceptionHandler;
using Heart_Module.Data.Scripts.HeartModule.Network;

namespace Heart_Module.Data.Scripts.HeartModule
{
internal class HeartData
{
public static HeartData I;
public const ushort HeartNetworkId = (ushort)(65198749845 % ushort.MaxValue);

public bool IsSuspended = false;
public HeartNetwork Net = new HeartNetwork();
public HeartLog Log = new HeartLog();
}
}
51 changes: 51 additions & 0 deletions Heart Module/Data/Scripts/HeartModule/HeartLoad.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Heart_Module.Data.Scripts.HeartModule.ErrorHandler;
using Heart_Module.Data.Scripts.HeartModule.ExceptionHandler;
using System;
using VRage.Game.Components;

namespace Heart_Module.Data.Scripts.HeartModule
{
[MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)]
internal class HeartLoad : MySessionComponentBase
{
CriticalHandle handle;


public override void LoadData()
{
HeartData.I = new HeartData();
HeartData.I.Log.Log($"Start loading core...");

handle = new CriticalHandle();
handle.LoadData();
HeartData.I.Net.LoadData();

HeartData.I.IsSuspended = false;
HeartData.I.Log.Log($"Finished loading core.");
}

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();

try
{
if (HeartData.I.IsSuspended)
return;
}
catch (Exception ex)
{
SoftHandle.RaiseException(ex);
}
}

protected override void UnloadData()
{
handle.UnloadData();
HeartData.I.Net.UnloadData();
HeartData.I.Log.Log($"Closing core, log finishes here.");
HeartData.I = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
using Sandbox.ModAPI;
using Heart_Module.Data.Scripts.HeartModule.ErrorHandler;
using Sandbox.ModAPI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VRage.Game.Components;
using VRage.Game.ModAPI;
using VRage.Utils;

namespace Heart_Module.Data.Scripts.HeartModule.Network
{
[MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)]
public class HeartNetwork_Session : MySessionComponentBase
public class HeartNetwork
{
public const ushort HeartNetworkId = (ushort)(65198749845 % ushort.MaxValue);

public static HeartNetwork_Session Net;

public override void LoadData()
public void LoadData()
{
Net = this;
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(HeartNetworkId, ReceivedPacket);
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(HeartData.HeartNetworkId, ReceivedPacket);
}

protected override void UnloadData()
public void UnloadData()
{
Net = null;
MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(HeartNetworkId, ReceivedPacket);
MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(HeartData.HeartNetworkId, ReceivedPacket);
}

void ReceivedPacket(ushort channelId, byte[] serialized, ulong senderSteamId, bool isSenderServer)
Expand All @@ -38,7 +27,7 @@ void ReceivedPacket(ushort channelId, byte[] serialized, ulong senderSteamId, bo
}
catch (Exception ex)
{
MyLog.Default.WriteLineAndConsole($"Exception in network deserialize: {ex.Message}\n{ex.StackTrace}");
SoftHandle.RaiseException(ex, typeof(HeartNetwork));
}
}

Expand All @@ -65,7 +54,7 @@ void RelayToClients(PacketBase packet, ulong senderSteamId = 0, byte[] serialize
if (serialized == null) // only serialize if necessary, and only once.
serialized = MyAPIGateway.Utilities.SerializeToBinary(packet);

MyAPIGateway.Multiplayer.SendMessageTo(HeartNetworkId, serialized, p.SteamUserId);
MyAPIGateway.Multiplayer.SendMessageTo(HeartData.HeartNetworkId, serialized, p.SteamUserId);
}

TempPlayers.Clear();
Expand Down
6 changes: 1 addition & 5 deletions Heart Module/Data/Scripts/HeartModule/Network/PacketBase.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
using Heart_Module.Data.Scripts.HeartModule.Projectiles.StandardClasses;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Heart_Module.Data.Scripts.HeartModule.Network
{
[ProtoInclude(1, typeof(SerializableProjectile))]
[ProtoInclude(2, typeof(ExceptionHandler.NetworkedError))]
[ProtoContract(UseProtoMembersOnly = true)]
public abstract partial class PacketBase
{
Expand Down
Loading

0 comments on commit 5b34577

Please sign in to comment.