Skip to content

Commit

Permalink
initial switch to Telepathy networking
Browse files Browse the repository at this point in the history
TODO: implement disconnect packet with reason
  • Loading branch information
PhantomGamers committed Sep 7, 2021
1 parent 9a362da commit b32753d
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 198 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "websocket-sharp"]
path = dep/websocket-sharp
url = https://github.com/PhantomGamers/websocket-sharp
[submodule "dep/Telepathy"]
path = dep/Telepathy
url = https://github.com/vis2k/Telepathy.git
26 changes: 13 additions & 13 deletions Nebula.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30225.117
# Visual Studio Version 17
VisualStudioVersion = 17.0.31612.314
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaPatcher", "NebulaPatcher\NebulaPatcher.csproj", "{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}"
EndProject
Expand All @@ -19,18 +19,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaWorld", "NebulaWorld\NebulaWorld.csproj", "{28AEA139-FB22-4672-AF51-28B728CF2978}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "dep\websocket-sharp\websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaNetwork", "NebulaNetwork\NebulaNetwork.csproj", "{36A3D8AE-2A0A-4A1F-8A65-4FB61B01F779}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NebulaAPI", "NebulaAPI\NebulaAPI.csproj", "{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaAPI", "NebulaAPI\NebulaAPI.csproj", "{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Telepathy", "dep\Telepathy\Telepathy\Telepathy.csproj", "{48F09257-A406-4729-88E4-FC1379BBFF4A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Release|Any CPU.Build.0 = Release|Any CPU
{C6237195-F77C-40C0-B06A-4AD51CAD314D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6237195-F77C-40C0-B06A-4AD51CAD314D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6237195-F77C-40C0-B06A-4AD51CAD314D}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -39,22 +43,18 @@ Global
{28AEA139-FB22-4672-AF51-28B728CF2978}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28AEA139-FB22-4672-AF51-28B728CF2978}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28AEA139-FB22-4672-AF51-28B728CF2978}.Release|Any CPU.Build.0 = Release|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.Build.0 = Release|Any CPU
{36A3D8AE-2A0A-4A1F-8A65-4FB61B01F779}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36A3D8AE-2A0A-4A1F-8A65-4FB61B01F779}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36A3D8AE-2A0A-4A1F-8A65-4FB61B01F779}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36A3D8AE-2A0A-4A1F-8A65-4FB61B01F779}.Release|Any CPU.Build.0 = Release|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47B9362C-E91B-4AE4-979B-7D811AB4D1EA}.Release|Any CPU.Build.0 = Release|Any CPU
{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B59DB3BB-DBA2-42AF-B4F1-32A9A6A273D2}.Release|Any CPU.Build.0 = Release|Any CPU
{48F09257-A406-4729-88E4-FC1379BBFF4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48F09257-A406-4729-88E4-FC1379BBFF4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48F09257-A406-4729-88E4-FC1379BBFF4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48F09257-A406-4729-88E4-FC1379BBFF4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion NebulaModel/NebulaModel.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\dep\websocket-sharp\websocket-sharp\websocket-sharp.csproj" />
<ProjectReference Include="..\dep\Telepathy\Telepathy\Telepathy.csproj" />
<ProjectReference Include="..\NebulaAPI\NebulaAPI.csproj" Private="false" />
</ItemGroup>

Expand Down
74 changes: 42 additions & 32 deletions NebulaModel/Networking/NebulaConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,77 @@
using NebulaModel.Logger;
using NebulaModel.Networking.Serialization;
using System;
using System.Net;
using WebSocketSharp;

namespace NebulaModel.Networking
{
public class NebulaConnection : INebulaConnection
{
private readonly EndPoint peerEndpoint;
private readonly WebSocket peerSocket;
private readonly Telepathy.Client client;
private readonly Telepathy.Server server;
private readonly NetPacketProcessor packetProcessor;
private readonly int connectionId;
private readonly string peerAddress;

public bool IsAlive => peerSocket?.IsAlive ?? false;

public NebulaConnection(WebSocket peerSocket, EndPoint peerEndpoint, NetPacketProcessor packetProcessor)
public NebulaConnection(Telepathy.Client client, Telepathy.Server server, NetPacketProcessor packetProcessor, int connectionId = -1)
{
this.peerEndpoint = peerEndpoint;
this.peerSocket = peerSocket;
this.client = client;
this.server = server;
this.packetProcessor = packetProcessor;
this.connectionId = connectionId;
peerAddress = server?.GetClientAddress(connectionId) ?? "localhost";
}

public void SendPacket<T>(T packet) where T : class, new()
{
if (peerSocket.ReadyState == WebSocketState.Open)
if (client?.Connected ?? false)
{
client.Send(new ArraySegment<byte>(packetProcessor.Write(packet)));
}
else if (server?.Active ?? false)
{
peerSocket.Send(packetProcessor.Write(packet));
server.Send(connectionId, new ArraySegment<byte>(packetProcessor.Write(packet)));
}
else
{
Log.Warn($"Cannot send packet {packet?.GetType()} to a closed connection {peerEndpoint}");
Log.Warn($"Cannot send packet {packet?.GetType()} to closed connection {(connectionId != -1 ? connectionId.ToString() : string.Empty)}");
}
}

public void SendRawPacket(byte[] rawData)
{
if (peerSocket.ReadyState == WebSocketState.Open)
if (client?.Connected ?? false)
{
peerSocket.Send(rawData);
client.Send(new ArraySegment<byte>(rawData));
}
else if (server?.Active ?? false)
{
server.Send(connectionId, new ArraySegment<byte>(rawData));
}
else
{
Log.Warn($"Cannot send raw packet to a closed connection {peerSocket?.Url}");
Log.Warn($"Cannot send raw packet to closed connection {(connectionId != -1 ? connectionId.ToString() : string.Empty)}");
}
}

public void Disconnect(DisconnectionReason reason = DisconnectionReason.Normal, string reasonString = null)
{
if (string.IsNullOrEmpty(reasonString))
{
peerSocket.Close((ushort)reason);
}
else
{
if (System.Text.Encoding.UTF8.GetBytes(reasonString).Length <= 123)
{
peerSocket.Close((ushort)reason, reasonString);
}
else
{
throw new ArgumentException("Reason string cannot take up more than 123 bytes");
}
}
//if (string.IsNullOrEmpty(reasonString))
//{
// peerSocket.Close((ushort)reason);
//}
//else
//{
// if (System.Text.Encoding.UTF8.GetBytes(reasonString).Length <= 123)
// {
// peerSocket.Close((ushort)reason, reasonString);
// }
// else
// {
// throw new ArgumentException("Reason string cannot take up more than 123 bytes");
// }
//}

server.Disconnect(connectionId);
}

public static bool operator ==(NebulaConnection left, NebulaConnection right)
Expand All @@ -89,12 +99,12 @@ public override bool Equals(object obj)
{
return false;
}
return (obj as NebulaConnection).peerEndpoint.Equals(this.peerEndpoint);
return (obj as NebulaConnection).peerAddress.Equals(peerAddress);
}

public override int GetHashCode()
{
return peerEndpoint?.GetHashCode() ?? 0;
return peerAddress?.GetHashCode() ?? 0;
}
}
}
112 changes: 54 additions & 58 deletions NebulaNetwork/Client.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using HarmonyLib;
using NebulaAPI;
using NebulaAPI;
using NebulaModel;
using NebulaModel.Logger;
using NebulaModel.Networking;
Expand All @@ -8,20 +7,19 @@
using NebulaModel.Packets.Session;
using NebulaModel.Utils;
using NebulaWorld;
using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using UnityEngine;
using WebSocketSharp;

namespace NebulaNetwork
{
public class Client : NetworkProvider
{
private Telepathy.Client client;
private const int MECHA_SYNCHONIZATION_INTERVAL = 5;

private readonly IPEndPoint serverEndpoint;
private WebSocket clientSocket;
private NebulaConnection serverConnection;

private float mechaSynchonizationTimer = 0f;
Expand Down Expand Up @@ -55,12 +53,16 @@ public override void Start()
PacketProcessor.SimulateLatency = true;
#endif

clientSocket = new WebSocket($"ws://{serverEndpoint}/socket");
clientSocket.OnOpen += ClientSocket_OnOpen;
clientSocket.OnClose += ClientSocket_OnClose;
clientSocket.OnMessage += ClientSocket_OnMessage;
client = new Telepathy.Client(50 * 1024 * 1024)
{
OnConnected = OnConnected,
OnData = OnMessage,
OnDisconnected = OnDisconnected,
ReceiveTimeout = 30000,
SendTimeout = 30000
};

clientSocket.Connect();
client.Connect(serverEndpoint.Address.ToString(), serverEndpoint.Port);

((LocalPlayer)Multiplayer.Session.LocalPlayer).IsHost = false;

Expand All @@ -76,7 +78,8 @@ public override void Start()

public override void Stop()
{
clientSocket?.Close((ushort)DisconnectionReason.ClientRequestedDisconnect, "Player left the game");
//clientSocket?.Close((ushort)DisconnectionReason.ClientRequestedDisconnect, "Player left the game");
client?.Disconnect();

NebulaModAPI.OnMultiplayerGameEnded?.Invoke();
}
Expand Down Expand Up @@ -121,6 +124,8 @@ public override void SendPacketToStarExclude<T>(T packet, int starId, INebulaCon

public override void Update()
{
client.Tick(1000);

PacketProcessor.ProcessPacketQueue();

if (Multiplayer.Session.IsGameLoaded)
Expand All @@ -140,21 +145,10 @@ public override void Update()
}
}
}

private void ClientSocket_OnMessage(object sender, MessageEventArgs e)
{
if (!Multiplayer.IsLeavingGame)
{
PacketProcessor.EnqueuePacketForProcessing(e.RawData, new NebulaConnection(clientSocket, serverEndpoint, PacketProcessor));
}
}

private void ClientSocket_OnOpen(object sender, System.EventArgs e)
private void OnConnected()
{
DisableNagleAlgorithm(clientSocket);

Log.Info($"Server connection established");
serverConnection = new NebulaConnection(clientSocket, serverEndpoint, PacketProcessor);
serverConnection = new NebulaConnection(client, null, PacketProcessor);

//TODO: Maybe some challenge-response authentication mechanism?

Expand All @@ -164,49 +158,59 @@ private void ClientSocket_OnOpen(object sender, System.EventArgs e)
new Float3(Config.Options.MechaColorR / 255, Config.Options.MechaColorG / 255, Config.Options.MechaColorB / 255)));
}

private void ClientSocket_OnClose(object sender, CloseEventArgs e)
private void OnMessage(ArraySegment<byte> obj)
{
if (!Multiplayer.IsLeavingGame)
{
PacketProcessor.EnqueuePacketForProcessing(obj.Array, new NebulaConnection(client, null, PacketProcessor));
}
}

private void OnDisconnected()
{
serverConnection = null;

UnityDispatchQueue.RunOnMainThread(() =>
{
// If the client is Quitting by himself, we don't have to inform him of his disconnection.
if (e.Code == (ushort)DisconnectionReason.ClientRequestedDisconnect)
return;
//// If the client is Quitting by himself, we don't have to inform him of his disconnection.
//if (e.Code == (ushort)DisconnectionReason.ClientRequestedDisconnect)
//{
// return;
//}
// Opens the pause menu on disconnection to prevent NRE when leaving the game
if (Multiplayer.Session?.IsGameLoaded ?? false)
{
GameMain.instance._paused = true;
}
if (e.Code == (ushort)DisconnectionReason.ModVersionMismatch)
{
string[] versions = e.Reason.Split(';');
InGamePopup.ShowWarning(
"Mod Version Mismatch",
$"Your Nebula Multiplayer Mod is not the same as the Host version.\nYou:{versions[0]} - Remote:{versions[1]}",
"OK",
Multiplayer.LeaveGame);
return;
}
if (e.Code == (ushort)DisconnectionReason.GameVersionMismatch)
{
string[] versions = e.Reason.Split(';');
InGamePopup.ShowWarning(
"Game Version Mismatch",
$"Your version of the game is not the same as the one used by the Host.\nYou:{versions[0]} - Remote:{versions[1]}",
"OK",
Multiplayer.LeaveGame);
return;
}
//if (e.Code == (ushort)DisconnectionReason.ModVersionMismatch)
//{
// string[] versions = e.Reason.Split(';');
// InGamePopup.ShowWarning(
// "Mod Version Mismatch",
// $"Your Nebula Multiplayer Mod is not the same as the Host version.\nYou:{versions[0]} - Remote:{versions[1]}",
// "OK",
// Multiplayer.LeaveGame);
// return;
//}
//if (e.Code == (ushort)DisconnectionReason.GameVersionMismatch)
//{
// string[] versions = e.Reason.Split(';');
// InGamePopup.ShowWarning(
// "Game Version Mismatch",
// $"Your version of the game is not the same as the one used by the Host.\nYou:{versions[0]} - Remote:{versions[1]}",
// "OK",
// Multiplayer.LeaveGame);
// return;
//}
if (Multiplayer.Session.IsGameLoaded)
{
InGamePopup.ShowWarning(
"Connection Lost",
$"You have been disconnected from the server.\n{e.Reason}",
$"You have been disconnected from the server.\n",
"Quit",
Multiplayer.LeaveGame);
}
Expand All @@ -220,13 +224,5 @@ private void ClientSocket_OnClose(object sender, CloseEventArgs e)
}
});
}



static void DisableNagleAlgorithm(WebSocket socket)
{
var tcpClient = AccessTools.FieldRefAccess<WebSocket, TcpClient>("_tcpClient")(socket);
tcpClient.NoDelay = true;
}
}
}

0 comments on commit b32753d

Please sign in to comment.