NIO networking transition is now functional, has some issues with usernames not syncing properly and some latency issues on real world testing
This commit is contained in:
parent
3e886e5ba8
commit
c9ef43a2a0
23 changed files with 476 additions and 71 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package net.halbear.Executable;
|
||||
|
||||
import com.oracle.svm.core.annotate.Delete;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
|
|
@ -24,6 +25,9 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
public class Server {
|
||||
|
||||
@Deprecated
|
||||
@Delete
|
||||
public static Map<UUID, ServerConnectionThread> ConnectedClients = new ConcurrentHashMap<>();
|
||||
public static Map<UUID, String> ClientNames = new ConcurrentHashMap<>();
|
||||
|
||||
|
|
@ -57,7 +61,11 @@ public class Server {
|
|||
}
|
||||
|
||||
public static void ProcessOutgoingPackets(){
|
||||
|
||||
Packet packet;
|
||||
ClientSession.ProcessOutboundPackets();
|
||||
while((packet = OutGoingPacketQueue.poll()) != null){
|
||||
ClientSession.HandOutPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
@ -94,13 +102,13 @@ public class Server {
|
|||
public static void StartServer(String[] args) throws IOException {
|
||||
|
||||
|
||||
ServerSocket server = new ServerSocket(ServerConnectionThread.ServerPort);
|
||||
Logger.info("\nLaunching New Terrain4J Powered Software!");
|
||||
|
||||
RenderThread.Headless = true;
|
||||
PrimaryRuntime.IsServer = true;
|
||||
|
||||
if(LegacyNetworking){
|
||||
ServerSocket server = new ServerSocket(ServerConnectionThread.ServerPort);
|
||||
Thread acceptThread = new Thread(() -> {
|
||||
while(true) {
|
||||
try {
|
||||
|
|
@ -225,15 +233,24 @@ public class Server {
|
|||
|
||||
AtomicReference<String> PlayerConnections = new AtomicReference<>("");
|
||||
|
||||
Server.ConnectedClients.forEach((uuid, client)->{
|
||||
String Username = "N/A";
|
||||
if(Server.ClientNames.containsKey(uuid)){
|
||||
Username = Server.ClientNames.get(uuid);
|
||||
}
|
||||
PlayerConnections.set(PlayerConnections.get() + "\nConnection UUID: " + uuid.toString() + "\n\tIP address -> " + client.getIP() + "\n\tUsername -> " + Username);
|
||||
});
|
||||
if(LegacyNetworking) {
|
||||
Server.ConnectedClients.forEach((uuid, client) -> {
|
||||
String Username = "N/A";
|
||||
if (Server.ClientNames.containsKey(uuid)) {
|
||||
Username = Server.ClientNames.get(uuid);
|
||||
}
|
||||
PlayerConnections.set(PlayerConnections.get() + "\nConnection UUID: " + uuid.toString() + "\n\tIP address -> " + client.getIP() + "\n\tUsername -> " + Username);
|
||||
});
|
||||
|
||||
PrimaryRuntime.printLog("\nServer Runtime Info:\n\tPlayers Connected: " + Server.ConnectedClients.size() +"\n" + PlayerConnections.get() + "\n\n" + Profiling);
|
||||
PrimaryRuntime.printLog("\nServer Runtime Info:\n\tPlayers Connected: " + Server.ConnectedClients.size() + "\n" + PlayerConnections.get() + "\n\n" + Profiling);
|
||||
} else{
|
||||
ClientSession.GetClientSessionInstances().forEach((uuid, client) -> {
|
||||
String Username = client.GetClientName();
|
||||
PlayerConnections.set(PlayerConnections.get() + "\nConnection Instance UUID: " + uuid.toString() +"\n\tClient UUID: " + client.GetClientUUID() + "\n\tIP address -> " + client.GetIP() + "\n\tUsername -> " + Username);
|
||||
});
|
||||
|
||||
PrimaryRuntime.printLog("\nServer Runtime Info:\n\tPlayers Connected: " + Server.ConnectedClients.size() + "\n" + PlayerConnections.get() + "\n\n" + Profiling);
|
||||
}
|
||||
break;
|
||||
case "stop":
|
||||
case "end":
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.SettingsMenu;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.DeferredSceneRender;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.*;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.*;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.*;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.InstancedPhysicsThread;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
|
|||
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.GUI.GuiTexture;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialData;
|
||||
|
|
@ -479,14 +478,16 @@ public class GameCore implements GameLogic {
|
|||
}
|
||||
}
|
||||
|
||||
private static final boolean UseLegacyNetworking = false;
|
||||
|
||||
@Override
|
||||
public void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
|
||||
float PhysicsFramerate = 24f;
|
||||
float PhysicsFrameTime = 1000f/PhysicsFramerate;
|
||||
float DeltaTime = (float)FrameDiffNanoSeconds/(PhysicsFrameTime*1000000f);
|
||||
if(PrimaryRuntime.IsServer){
|
||||
Server.LegacyCollectIncomingPackets();
|
||||
Server.LegacyProcessIncomingPackets();
|
||||
if(UseLegacyNetworking) Server.LegacyCollectIncomingPackets(); else Server.CollectIncomingPackets();
|
||||
if(UseLegacyNetworking) Server.LegacyProcessIncomingPackets(); else Server.ProcessIncomingPackets();
|
||||
|
||||
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
|
||||
|
||||
|
|
@ -498,9 +499,10 @@ public class GameCore implements GameLogic {
|
|||
}
|
||||
}
|
||||
|
||||
Server.LegacyProcessOutgoingPackets();
|
||||
if(UseLegacyNetworking) Server.LegacyProcessOutgoingPackets(); else Server.ProcessOutgoingPackets();
|
||||
} else {
|
||||
ClientSideNetworkUtils.DecodePackets(engineInstance, this, engineInstance.scene());
|
||||
if(!UseLegacyNetworking) ClientSideNetworkUtils.SendNIOPacketQueue();
|
||||
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene;
|
||||
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.FastTickThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.MainThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.*;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.Console;
|
||||
|
|
@ -51,7 +48,7 @@ public class PrimaryRuntime {
|
|||
public final CPUMonitor cpuProfiler;
|
||||
private static GameLogic gameLogic;
|
||||
|
||||
public static ClientConnectionThread ServerCon;
|
||||
public static ClientConnection ServerCon;
|
||||
public static Thread MultiplayerConnectionThread;
|
||||
public static GameLogic GetGameCore(){return gameLogic;}
|
||||
|
||||
|
|
@ -84,15 +81,22 @@ public class PrimaryRuntime {
|
|||
PrimaryThread = new MainThread(engineInstance, appLogic);
|
||||
FastThread = new FastTickThread(engineInstance, appLogic);
|
||||
if(!IsServer) {
|
||||
ServerCon = new ClientConnectionThread();
|
||||
MultiplayerConnectionThread = new Thread(ServerCon);
|
||||
MultiplayerConnectionThread.start();
|
||||
CreateNewClientConnection();
|
||||
DrawingThread = new RenderThread(engineInstance, initData, appLogic);
|
||||
}
|
||||
cpuProfiler = new CPUMonitor();
|
||||
EngineConfig.getInstance().SetCPU(CPUMonitor.getCpuName(), CPUMonitor.getCoreCount());
|
||||
Thread.currentThread().setName("Terrain4J Primary Runtime Thread");
|
||||
}
|
||||
|
||||
|
||||
private static final boolean UseLegacyNetworking = false;
|
||||
public static void CreateNewClientConnection(){
|
||||
Logger.info("Trying to connect");
|
||||
ServerCon = UseLegacyNetworking ? new ClientConnectionThread() : new NIO_ClientConnectionThread(EngineConfig.getInstance().GetServerIP(), EngineConfig.getInstance().GetServerPort());
|
||||
MultiplayerConnectionThread = ServerCon.GetNetworkedThread();
|
||||
ServerCon.start();
|
||||
}
|
||||
|
||||
public static void RejoinMultiplayer(){
|
||||
MultiplayerConnectionThread.interrupt();
|
||||
|
|
@ -101,9 +105,7 @@ public class PrimaryRuntime {
|
|||
} catch (InterruptedException e){
|
||||
Logger.error("Cant rejoin multiplayer thread: [{}]",e.getMessage());
|
||||
}
|
||||
ServerCon = new ClientConnectionThread();
|
||||
MultiplayerConnectionThread = new Thread(ServerCon);
|
||||
MultiplayerConnectionThread.start();
|
||||
CreateNewClientConnection();
|
||||
}
|
||||
|
||||
public static void StartPingTimer() {
|
||||
|
|
@ -145,9 +147,7 @@ public class PrimaryRuntime {
|
|||
return "Connection Error, IsServer Unreachable";
|
||||
}
|
||||
} else if (!ClientSideNetworkUtils.Connected) {
|
||||
ServerCon = new ClientConnectionThread();
|
||||
MultiplayerConnectionThread = new Thread(ServerCon);
|
||||
MultiplayerConnectionThread.start();
|
||||
CreateNewClientConnection();
|
||||
|
||||
}
|
||||
return "Connecting...";
|
||||
|
|
@ -201,7 +201,7 @@ public class PrimaryRuntime {
|
|||
UpdateTickRateThreshold();
|
||||
|
||||
PrimaryThread.StartThread();
|
||||
DrawingThread.StartThread();
|
||||
if(!IsServer)DrawingThread.StartThread();
|
||||
FastThread.StartThread();
|
||||
|
||||
FrameAccuracy = EngineConfig.getInstance().getAccuracy();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
|
|||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.DeferredSceneRender;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.DeferredSceneRender;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
|
|||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
import org.joml.Vector3f;
|
||||
import org.tinylog.Logger;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.GameChat;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.PerformanceOverlay;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.StartMenu;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DynamicMesh.DynamicTerrainMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Projection.Project3D;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.ActorElement;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.*;
|
||||
|
|
@ -417,7 +417,7 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
|
|||
if(i < Actors.size()) {
|
||||
var Actor = Actors.get(i);
|
||||
if(Actor != null && Actor.GetPosition() != null) {
|
||||
if(Actor instanceof ActorElement &&( !((ActorElement) Actor).RenderOnTopOfPlayer && Objects.equals(((ActorElement) Actor).GetParentID(), ClientConnectionThread.OwnedActorID) || new Vector3f().set(Actor.GetPosition()).sub(instance.scene().GetCamera().GetPosition()).absolute().lengthSquared() < 4f)) continue;
|
||||
if(Actor instanceof ActorElement &&( !((ActorElement) Actor).RenderOnTopOfPlayer && ClientSideNetworkUtils.OwnsActor(((ActorElement) Actor).GetParentID()) || new Vector3f().set(Actor.GetPosition()).sub(instance.scene().GetCamera().GetPosition()).absolute().lengthSquared() < 4f)) continue;
|
||||
else {
|
||||
VulkanModel model = modelsCache.GetModel(Actor.GetModelID());
|
||||
List<VulkanMesh> VkMeshList = model.GetVkMeshList();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.ActorElement;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
|
||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.*;
|
||||
|
|
@ -408,7 +408,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
|
|||
if(i < Actors.size()) {
|
||||
var Actor = Actors.get(i);
|
||||
if(Actor != null) {
|
||||
if(Actor instanceof ActorElement &&( !((ActorElement) Actor).RenderOnTopOfPlayer && Objects.equals(((ActorElement) Actor).GetParentID(), ClientConnectionThread.OwnedActorID) || new Vector3f().set(Actor.GetPosition()).sub(instance.scene().GetCamera().GetPosition()).absolute().lengthSquared() < 4f)) continue;
|
||||
if(Actor instanceof ActorElement &&( !((ActorElement) Actor).RenderOnTopOfPlayer && ClientSideNetworkUtils.OwnsActor(((ActorElement) Actor).GetParentID())|| new Vector3f().set(Actor.GetPosition()).sub(instance.scene().GetCamera().GetPosition()).absolute().lengthSquared() < 4f)) continue;
|
||||
VulkanModel model = modelsCache.GetModel(Actor.GetModelID());
|
||||
List<VulkanMesh> VkMeshList = model.GetVkMeshList();
|
||||
int MeshCount = VkMeshList.size();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.PlayerActor;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.EngineThread;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -16,6 +17,7 @@ import java.nio.channels.Selector;
|
|||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
|
@ -102,9 +104,14 @@ public class ClientSession implements ServerConnection {
|
|||
}
|
||||
}
|
||||
|
||||
public String GetClientName(){return ClientName;}
|
||||
|
||||
public String GetIP(){
|
||||
return IPAddress;
|
||||
}
|
||||
|
||||
public UUID GetInstanceUUID(){return InstanceUUID;}
|
||||
public UUID GetClientUUID(){return InstanceUUID;}
|
||||
public UUID GetClientUUID(){return ClientUUID;}
|
||||
|
||||
public ClientSession(SocketChannel channel, IP_MODIFIER modifier, Selector connectionSelector, SelectionKey selectionKey) {
|
||||
this.Channel = channel;
|
||||
|
|
@ -112,7 +119,19 @@ public class ClientSession implements ServerConnection {
|
|||
this.connectionSelector = connectionSelector;
|
||||
this.selectionKey = selectionKey;
|
||||
this.InstanceUUID = UUID.randomUUID();
|
||||
IPAddress = "COULD_NOT_GET";
|
||||
try {
|
||||
IPAddress = NetworkingUtil.GetIPAddress(channel);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to get IP address for client session with UUID " + InstanceUUID);
|
||||
e.printStackTrace();
|
||||
Logger.error("Failed to get IP address for client session with UUID " + InstanceUUID);
|
||||
}
|
||||
ClientSessionInstances.put(this.InstanceUUID,this);
|
||||
PendingClients.add(this);
|
||||
System.out.println("New Client Session Created with UUID " + InstanceUUID);
|
||||
AddOutgoingPacket(new Packet(Packet.QUERY_MAC_ADDRESS).SetTargetType((byte) 0).SetData(new byte[]{0,0,0,0}).SetID("_"));
|
||||
AddOutgoingPacket(new Packet(Packet.QUERY_CLIENT_UUID).SetTargetType((byte) 0).SetData(new byte[]{0,0,0,0}).SetID("_"));
|
||||
}
|
||||
|
||||
public boolean IsValidated(){
|
||||
|
|
@ -123,7 +142,7 @@ public class ClientSession implements ServerConnection {
|
|||
if(PendingClients.isEmpty()) return;
|
||||
for(int i = 0; i < PendingClients.size(); i++){
|
||||
ClientSession Pending = PendingClients.peek();
|
||||
if(Pending.IsValidated()){
|
||||
if(Pending.IsValidated() && Pending.CheckedUUID_Cache){
|
||||
ClientSession session = PendingClients.poll();
|
||||
if(session == null) continue;
|
||||
session.InitialiseJoinedClient();
|
||||
|
|
@ -151,7 +170,7 @@ public class ClientSession implements ServerConnection {
|
|||
}
|
||||
|
||||
protected void InitialiseJoinedClient(){
|
||||
Packet PlayerCountPacket = CreatePlayerCountPacket(Server.ConnectedClients.size());
|
||||
Packet PlayerCountPacket = CreatePlayerCountPacket(ClientSessions.size());
|
||||
Server.OutGoingPacketQueue.add(PlayerCountPacket);
|
||||
EngineInstance engineInstance = PrimaryRuntime.GetEngineInstance();
|
||||
IScene scene = engineInstance.scene();
|
||||
|
|
@ -178,8 +197,7 @@ public class ClientSession implements ServerConnection {
|
|||
|
||||
BroadcastCreateActorPacket(player);
|
||||
SendPossessActorPacket(player.GetID());
|
||||
Packet UUIDUpdatePacket = CreatePlayerUUIDPacket(ClientUUID,this);
|
||||
Server.OutGoingPacketQueue.add(UUIDUpdatePacket);
|
||||
Server.OutGoingPacketQueue.add(ServerSideNetworkUtils.CreateUsernameUpdatePacket(ClientUUID, ClientName));
|
||||
Logger.debug("Queued possess packet for joining player's actor: " + player.GetID());
|
||||
}
|
||||
|
||||
|
|
@ -194,11 +212,10 @@ public class ClientSession implements ServerConnection {
|
|||
String Data = Packet.DecodeAsString(Inbound.Data);
|
||||
if(ClientMacAddressCache.containsKey(Data)){
|
||||
UUID clientUUID = ClientMacAddressCache.get(Data);
|
||||
ClientSessions.put(clientUUID,PendingClients.poll());
|
||||
ClientUUID = clientUUID;
|
||||
OutboundPacketQueue.add(new Packet(Packet.PACKET_ASSIGN_UUID).SetData(Packet.EncodeString(clientUUID.toString())).SetID(clientUUID.toString()));
|
||||
CheckedUUID_Cache = true;
|
||||
Validated = true;
|
||||
return;
|
||||
ClientSessions.remove(ClientUUID);
|
||||
OutboundPacketQueue.add(new Packet(Packet.QUERY_CLIENT_UUID).SetData(new byte[]{0,0,0,0}).SetID("_"));
|
||||
}
|
||||
CheckedUUID_Cache = true;
|
||||
}
|
||||
|
|
@ -206,11 +223,18 @@ public class ClientSession implements ServerConnection {
|
|||
String Data = Packet.DecodeAsString(Inbound.Data);
|
||||
ClientUUID = null;
|
||||
try{
|
||||
UUID newUUID = UUID.fromString(Data);
|
||||
if(ClientSessions.containsKey(newUUID) || ClientMacAddressCache.containsKey(Data)){
|
||||
String[] Halves = Data.split(":");
|
||||
UUID newUUID = null;
|
||||
if(!Objects.equals(Halves[0], "NULL")) {
|
||||
newUUID = UUID.fromString(Halves[0]);
|
||||
}
|
||||
if(Halves.length > 1) ClientName = Halves[1];
|
||||
else ClientName = newUUID == null ? "NOT_INITIALISED" : "NewPlayer" + newUUID.toString().substring(0,5);
|
||||
if((newUUID == null || ClientSessions.containsKey(newUUID))){
|
||||
Validated = false;
|
||||
UUID AssignUUID = UUID.randomUUID();
|
||||
OutboundPacketQueue.add(new Packet(Packet.PACKET_ASSIGN_UUID).SetData(Packet.EncodeString(AssignUUID.toString())).SetID(AssignUUID.toString()));
|
||||
OutboundPacketQueue.add(CreatePlayerUUIDPacket(AssignUUID, this));
|
||||
OutboundPacketQueue.add(new Packet(Packet.QUERY_CLIENT_UUID).SetData(new byte[]{0,0,0,0}).SetID("_"));
|
||||
} else{
|
||||
Validated = CheckedUUID_Cache;
|
||||
ClientUUID = newUUID;
|
||||
|
|
@ -238,7 +262,7 @@ public class ClientSession implements ServerConnection {
|
|||
|
||||
public void ProcessIncomingPacket() {
|
||||
InBound.flip();
|
||||
while (true) {
|
||||
while (EngineThread.running) {
|
||||
if (InBound.remaining() < 6) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -275,6 +299,8 @@ public class ClientSession implements ServerConnection {
|
|||
InBound.get(idData);
|
||||
String id = new String(idData, StandardCharsets.UTF_8);
|
||||
newIncomingPacket.SetID(id);
|
||||
newIncomingPacket.SessionUUID = InstanceUUID;
|
||||
newIncomingPacket.ClientUUID = ClientUUID;
|
||||
InboundPacketQueue.add(newIncomingPacket);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package net.halbear.Terrain4J.EngineCore.ServerNetworking;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.Strictness;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import net.halbear.Executable.Server;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
|
|
@ -11,14 +14,17 @@ import net.halbear.Terrain4J.EngineCore.Main.GameCore;
|
|||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.*;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.NIO_ClientConnectionThread;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
|
@ -30,17 +36,86 @@ public class ClientSideNetworkUtils {
|
|||
public static final Queue<Packet> OutGoingPacketQueue = new ConcurrentLinkedQueue<>();
|
||||
public static final Queue<Packet> IncomingPacketQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private static final Map<String, UUID> ServerClientUUIDs = new ConcurrentHashMap<>();
|
||||
private static final String CachePath = "resources/ProgramResources/ServerCache/UUIDs.json";
|
||||
private static final Queue<UUIDCache> UUIDCacheQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public static void CacheUUID(UUID uuid, String ServerIP){
|
||||
UUIDCacheQueue.add(new UUIDCache(ServerIP, uuid.toString()));
|
||||
ServerClientUUIDs.put(ServerIP, uuid);
|
||||
}
|
||||
|
||||
public static void SendNIOPacketQueue(){
|
||||
while(!OutGoingPacketQueue.isEmpty()){
|
||||
Packet packet = OutGoingPacketQueue.poll();
|
||||
NIO_ClientConnectionThread Connection = NIO_ClientConnectionThread.GetInstance();
|
||||
if(packet != null) {
|
||||
Connection.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static{
|
||||
if(Files.exists(Path.of(CachePath))) {
|
||||
String FileContents = "NOT_READ";
|
||||
try{
|
||||
FileContents = Files.readString(Path.of(CachePath), StandardCharsets.UTF_8);
|
||||
} catch (IOException e){
|
||||
Logger.error("Error reading UUID cache file: [{}]", e.getMessage());
|
||||
}
|
||||
if(!FileContents.equals("NOT_READ")) {
|
||||
Gson parser = new Gson();
|
||||
try (JsonReader reader = new JsonReader(new StringReader(FileContents))) {
|
||||
reader.setStrictness(Strictness.LENIENT);
|
||||
|
||||
while (reader.hasNext()) {
|
||||
UUIDCache user = parser.fromJson(reader, UUIDCache.class);
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(user.getClientUUID());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Logger.error("Invalid UUID in cache file: [{}]", user.getClientUUID());
|
||||
}
|
||||
if(uuid != null) {
|
||||
ServerClientUUIDs.put(user.getServerIP(), uuid);
|
||||
UUIDCacheQueue.add(user);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.error("Error parsing UUID cache file: [{}]", e.getMessage());
|
||||
}
|
||||
}
|
||||
} else{
|
||||
try {
|
||||
Files.createFile(Path.of(CachePath));
|
||||
} catch (IOException e) {
|
||||
Logger.error("Could not create UUID cache file: [{}]", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveUUIDCache(){
|
||||
try (FileWriter writer = new FileWriter(CachePath)) {
|
||||
Gson gson = new Gson();
|
||||
gson.toJson(UUIDCacheQueue, writer);
|
||||
} catch (IOException e) {
|
||||
Logger.error("Error saving UUID cache file: [{}]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean Connected = false;
|
||||
public static boolean pinging = false;
|
||||
public static String ServerIP = "localhost";
|
||||
public static String ServerMessage = "Offline";
|
||||
public static String clientUUID = null;
|
||||
public static UUID ClientUUID = null;
|
||||
private static final Map<String, Actor> NetworkOwnedActors = new ConcurrentHashMap<>();
|
||||
private static String PlayerControlledActorID = null;
|
||||
@Deprecated
|
||||
public static String OwnedActorID = "NULL";
|
||||
public static String PendingPossessActorID = "NULL";
|
||||
public static int PlayersOnline = 0;
|
||||
public static String MacAddress = null;
|
||||
|
||||
public static boolean IsPlayerControlledActor(String actorID){
|
||||
return PlayerControlledActorID.equals(actorID);
|
||||
|
|
@ -106,6 +181,43 @@ public class ClientSideNetworkUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
static{
|
||||
FetchMacAddress();
|
||||
}
|
||||
|
||||
private static void FetchMacAddress(){
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
|
||||
for (NetworkInterface netInterface : Collections.list(interfaces)) {
|
||||
if (netInterface.isLoopback() || !netInterface.isUp()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] MacAddress = netInterface.getHardwareAddress();
|
||||
if (MacAddress != null) {
|
||||
ClientSideNetworkUtils.MacAddress = FormatMacAddress(MacAddress);
|
||||
Logger.info("Interface: %-10s | MAC: %s%n",
|
||||
netInterface.getDisplayName(),
|
||||
FormatMacAddress(MacAddress));
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
Logger.error("Error retrieving network interfaces: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static String FormatMacAddress(byte[] mac) {
|
||||
StringBuilder StringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
StringBuilder.append(String.format("%02X", mac[i]));
|
||||
if (i < mac.length - 1) {
|
||||
StringBuilder.append("-");
|
||||
}
|
||||
}
|
||||
return StringBuilder.toString();
|
||||
}
|
||||
|
||||
public static final Map<Byte, Boolean> BypassNullTargets = new HashMap<>();
|
||||
|
||||
static{
|
||||
|
|
@ -118,6 +230,8 @@ public class ClientSideNetworkUtils {
|
|||
BypassNullTargets.put(Packet.PACKET_FIRE_RESULT, true);
|
||||
BypassNullTargets.put(Packet.GAME_CHAT_DATA_PACKET, true);
|
||||
BypassNullTargets.put(Packet.PACKET_UPDATE_PLAYER_DISPLAY_NAME, true);
|
||||
BypassNullTargets.put(Packet.QUERY_MAC_ADDRESS, true);
|
||||
BypassNullTargets.put(Packet.QUERY_CLIENT_UUID, true);
|
||||
}
|
||||
|
||||
public static void DecodePackets(EngineInstance engineInstance, GameCore gameCore, IScene scene){
|
||||
|
|
@ -285,6 +399,16 @@ public class ClientSideNetworkUtils {
|
|||
if(PlayerNameCached) PlayerName = Server.ClientNames.get(chat.clientFrom());
|
||||
GameChats.put(chat,PlayerName);
|
||||
break;
|
||||
case Packet.QUERY_CLIENT_UUID:
|
||||
Logger.info("Querying UUID");
|
||||
CreateUUIDQueryPacket();
|
||||
break;
|
||||
case Packet.QUERY_MAC_ADDRESS:
|
||||
Logger.info("Querying MAC Address");
|
||||
if(MacAddress == null) FetchMacAddress();
|
||||
if(MacAddress == null) break;
|
||||
CreateMacAddressPacket(MacAddress);
|
||||
break;
|
||||
case Packet.PACKET_DESTROY_ACTOR:
|
||||
GameChats.put(new GameChat(true, UUID.randomUUID(),"Destroying Actor " + packet.TargetID, Date.from(Instant.now())),"Server");
|
||||
Logger.debug("Destroying Actor [{}]", packet.TargetID);
|
||||
|
|
@ -311,6 +435,14 @@ public class ClientSideNetworkUtils {
|
|||
case Packet.PACKET_ASSIGN_UUID:
|
||||
Logger.debug("decoding UUID packet");
|
||||
clientUUID = Packet.DecodeAsString(packet.Data);
|
||||
UUID uuidOfClient = null;
|
||||
try{
|
||||
uuidOfClient = UUID.fromString(clientUUID);
|
||||
} catch (Exception e){}
|
||||
if(uuidOfClient != null) {
|
||||
CacheUUID(uuidOfClient, ServerIP);
|
||||
ClientUUID = uuidOfClient;
|
||||
}
|
||||
break;
|
||||
case Packet.PACKET_FIRE_RESULT:
|
||||
//Logger.debug("Fire Packet Recieved" );//
|
||||
|
|
@ -332,6 +464,16 @@ public class ClientSideNetworkUtils {
|
|||
|
||||
public static int ServerPort = 25565;
|
||||
|
||||
public static void SetServerIP(String ServerIP, Thread serverThread){
|
||||
if(Connected){
|
||||
Connected = false;
|
||||
serverThread.interrupt();
|
||||
ClientSideNetworkUtils.ServerIP = ServerIP;
|
||||
PrimaryRuntime.CreateNewClientConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public static void LegacySetServerIP(String ServerIP, Thread serverThread){
|
||||
if(Connected){
|
||||
|
|
@ -352,6 +494,22 @@ public class ClientSideNetworkUtils {
|
|||
OutGoingPacketQueue.add(packet);
|
||||
}
|
||||
|
||||
public static void CreateUUIDQueryPacket(){
|
||||
Packet packet = new Packet(Packet.QUERY_CLIENT_UUID);
|
||||
packet.SetTargetType((byte) 0);
|
||||
packet.SetData(Packet.EncodeString( (ClientUUID == null ? "NULL" : ClientUUID.toString()) + ":" + EngineConfig.getInstance().GetUserDisplayName()));
|
||||
packet.SetID("NULL");
|
||||
OutGoingPacketQueue.add(packet);
|
||||
}
|
||||
|
||||
public static void CreateMacAddressPacket(String Address){
|
||||
Packet packet = new Packet(Packet.QUERY_MAC_ADDRESS);
|
||||
packet.SetTargetType((byte) 0);
|
||||
packet.SetData(Packet.EncodeString(Address));
|
||||
packet.SetID("NULL");
|
||||
OutGoingPacketQueue.add(packet);
|
||||
}
|
||||
|
||||
public static void CreateGameChatPacket(String chatMessage){
|
||||
Packet packet = new Packet(Packet.GAME_CHAT_DATA_PACKET);
|
||||
packet.SetTargetType((byte) 0);
|
||||
|
|
@ -439,6 +597,16 @@ public class ClientSideNetworkUtils {
|
|||
private static final boolean UseLegacyConnection = false;
|
||||
|
||||
public static synchronized void Reconnect() {
|
||||
Logger.debug("Reconnecting");
|
||||
Reconnect = true;
|
||||
NIO_ClientConnectionThread.GetInstance().Disconnect();
|
||||
Connected = false;
|
||||
PrimaryRuntime.RejoinMultiplayer();
|
||||
PrimaryRuntime.GetEngineInstance().scene().Reset();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static synchronized void LegacyReconnect() {
|
||||
Logger.debug("Reconnecting");
|
||||
Reconnect = true;
|
||||
if(UseLegacyConnection) {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public class ServerSideNetworkUtils {
|
|||
//to be implemented later
|
||||
break;
|
||||
case Packet.PACKET_UPDATE_MODEL_ID:
|
||||
if(!packet.TargetID.equals(ConnectedClients.get(packet.SessionUUID).OwnedActorID)) {
|
||||
if(!(sender.OwnsActor(packet.TargetID))) {
|
||||
return;
|
||||
}
|
||||
Packet ReboundPacket = CreateUpdateModelIDPacket(packet.TargetID, Packet.DecodeAsString(packet.Data));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package net.halbear.Terrain4J.EngineCore.ServerNetworking;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class UUIDCache {
|
||||
@SerializedName("server_ip")
|
||||
private String ServerIP;
|
||||
@SerializedName("client_uuid")
|
||||
private String ClientUUID;
|
||||
|
||||
public UUIDCache(String serverIP, String clientUUID) {
|
||||
this.ServerIP = serverIP;
|
||||
this.ClientUUID = clientUUID;
|
||||
}
|
||||
|
||||
public String getServerIP() {
|
||||
return ServerIP;
|
||||
}
|
||||
|
||||
public String getClientUUID() {
|
||||
return ClientUUID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Threads;
|
||||
|
||||
public interface ClientConnection extends Runnable{
|
||||
public void start();
|
||||
public Thread GetNetworkedThread();
|
||||
}
|
||||
|
|
@ -29,22 +29,36 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
import static net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils.*;
|
||||
|
||||
@Deprecated
|
||||
public class ClientConnectionThread implements Runnable{
|
||||
@Delete
|
||||
public class ClientConnectionThread implements ClientConnection{
|
||||
|
||||
public static Socket SocketToServer;
|
||||
public static DataOutputStream outToServer;
|
||||
public static DataInputStream in;
|
||||
private final Thread NetworkThread;
|
||||
|
||||
public ClientConnectionThread(){
|
||||
Connected = true;
|
||||
NetworkThread = new Thread(this);
|
||||
NetworkThread.setName("Terrain4J Legacy Client Network Thread");
|
||||
NetworkThread.setDaemon(true);
|
||||
try {
|
||||
SocketToServer = new Socket(ServerIP, ServerPort);
|
||||
SocketToServer.setSoTimeout(5);
|
||||
|
||||
} catch (IOException e) {
|
||||
Connected = false;
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void start() {
|
||||
NetworkThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread GetNetworkedThread() {
|
||||
return NetworkThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,28 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Threads;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.Packet;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class NIO_ClientConnectionThread implements Runnable {
|
||||
import static net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils.SaveUUIDCache;
|
||||
|
||||
public class NIO_ClientConnectionThread implements ClientConnection {
|
||||
|
||||
public static NIO_ClientConnectionThread Instance;
|
||||
|
||||
public static NIO_ClientConnectionThread GetInstance(){ return Instance;}
|
||||
|
||||
private final ByteBuffer InBound = ByteBuffer.allocateDirect(4096);
|
||||
private final Queue<ByteBuffer> OutBoundQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
|
|
@ -16,14 +31,14 @@ public class NIO_ClientConnectionThread implements Runnable {
|
|||
|
||||
private final Thread NetworkThread;
|
||||
|
||||
private Selector Selector;
|
||||
private Selector NetworkSelector;
|
||||
private SocketChannel ClientChannel;
|
||||
private SelectionKey ChannelKey;
|
||||
|
||||
public NIO_ClientConnectionThread(String ServerAddress, int ServerPort) {
|
||||
this.ServerIP = ServerAddress;
|
||||
this.ServerPort = ServerPort;
|
||||
|
||||
NIO_ClientConnectionThread.Instance = this;
|
||||
NetworkThread = new Thread(this);
|
||||
NetworkThread.setName("Terrain4J Client Network Thread");
|
||||
NetworkThread.setDaemon(true);
|
||||
|
|
@ -34,7 +49,142 @@ public class NIO_ClientConnectionThread implements Runnable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public Thread GetNetworkedThread() {
|
||||
return NetworkThread;
|
||||
}
|
||||
|
||||
private void ConnectToServer(SelectionKey key) throws IOException {
|
||||
if (ClientChannel.isConnectionPending()) {
|
||||
if (ClientChannel.finishConnect()) {
|
||||
ClientSideNetworkUtils.Connected = true;
|
||||
this.ChannelKey = key;
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
} else {
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
NetworkSelector = Selector.open();
|
||||
ClientChannel = SocketChannel.open();
|
||||
ClientChannel.configureBlocking(false);
|
||||
|
||||
ClientChannel.connect(new InetSocketAddress(ServerIP, ServerPort));
|
||||
|
||||
ClientChannel.register(NetworkSelector, SelectionKey.OP_CONNECT);
|
||||
|
||||
while (ClientChannel.isOpen() && EngineThread.running) {
|
||||
NetworkSelector.select();
|
||||
|
||||
Iterator<SelectionKey> it = NetworkSelector.selectedKeys().iterator();
|
||||
while (it.hasNext()) {
|
||||
SelectionKey key = it.next();
|
||||
it.remove();
|
||||
|
||||
if (!key.isValid()) continue;
|
||||
|
||||
if (key.isConnectable()) {
|
||||
ConnectToServer(key);
|
||||
}
|
||||
|
||||
if (key.isReadable()) {
|
||||
HandleRead();
|
||||
}
|
||||
|
||||
if (key.isWritable()) {
|
||||
HandleWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Network client error: " + e.getMessage());
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleWrite() throws IOException {
|
||||
while (!OutBoundQueue.isEmpty()) {
|
||||
ByteBuffer buffer = OutBoundQueue.peek();
|
||||
ClientChannel.write(buffer);
|
||||
|
||||
if (buffer.hasRemaining()) {
|
||||
return;
|
||||
}
|
||||
OutBoundQueue.poll();
|
||||
}
|
||||
ChannelKey.interestOps(ChannelKey.interestOps() & ~SelectionKey.OP_WRITE);
|
||||
}
|
||||
|
||||
public void SendPacket(Packet outPacket) {
|
||||
byte[] dataToSend = Packet.GetOutgoingData(outPacket);
|
||||
OutBoundQueue.add(ByteBuffer.wrap(dataToSend));
|
||||
|
||||
if (ChannelKey != null && NetworkSelector != null) {
|
||||
ChannelKey.interestOps(ChannelKey.interestOps() | SelectionKey.OP_WRITE);
|
||||
NetworkSelector.wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect() {
|
||||
SaveUUIDCache();
|
||||
try {
|
||||
if (ClientChannel != null) ClientChannel.close();
|
||||
if (NetworkSelector != null) NetworkSelector.close();
|
||||
Logger.info("Client network loop cleanly shut down.");
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
private void HandleRead() throws IOException {
|
||||
int bytesRead = ClientChannel.read(InBound);
|
||||
if (bytesRead == -1) {
|
||||
System.out.println("Disconnected by remote server.");
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
InBound.flip();
|
||||
while (EngineThread.running) {
|
||||
if (InBound.remaining() < 6) break;
|
||||
|
||||
InBound.mark();
|
||||
byte packetTypeByte = InBound.get();
|
||||
byte targetType = InBound.get();
|
||||
int dataLength = InBound.getInt();
|
||||
|
||||
if (InBound.remaining() < dataLength + 4) {
|
||||
InBound.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
int currentPos = InBound.position();
|
||||
InBound.position(currentPos + dataLength);
|
||||
int idLength = InBound.getInt();
|
||||
InBound.position(currentPos);
|
||||
|
||||
if (InBound.remaining() < dataLength + 4 + idLength) {
|
||||
InBound.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
Packet serverPacket = new Packet(packetTypeByte);
|
||||
serverPacket.SetTargetType(targetType);
|
||||
|
||||
byte[] incomingData = new byte[dataLength];
|
||||
InBound.get(incomingData);
|
||||
serverPacket.Data = incomingData;
|
||||
|
||||
InBound.getInt();
|
||||
|
||||
byte[] idData = new byte[idLength];
|
||||
InBound.get(idData);
|
||||
serverPacket.SetID(new String(idData, StandardCharsets.UTF_8));
|
||||
|
||||
ClientSideNetworkUtils.IncomingPacketQueue.add(serverPacket);
|
||||
}
|
||||
InBound.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Threads;
|
||||
|
||||
import com.oracle.svm.core.annotate.Delete;
|
||||
import net.halbear.Executable.Server;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
|
||||
|
|
@ -22,6 +23,7 @@ import static net.halbear.Executable.Server.LegacyRemoveClient;
|
|||
import static net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils.*;
|
||||
|
||||
@Deprecated
|
||||
@Delete
|
||||
public class ServerConnectionThread implements Runnable, ServerConnection {
|
||||
public String OwnedActorID;
|
||||
private final Socket clientSocket;
|
||||
|
|
|
|||
|
|
@ -37,9 +37,12 @@ public class ServerMultiClientConnectionThread implements Runnable {
|
|||
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();
|
||||
private Thread ConnectionThread;
|
||||
|
||||
static int ThreadNumbers =0;
|
||||
|
||||
public ServerMultiClientConnectionThread() throws IOException {
|
||||
this.selector = Selector.open();
|
||||
ConnectionThread = new Thread(this);
|
||||
ConnectionThread.setName("Server NIO Connection Manager [" + ThreadNumbers++ + "]");
|
||||
ConnectionThread.setDaemon(true);
|
||||
}
|
||||
|
||||
|
|
@ -56,11 +59,13 @@ public class ServerMultiClientConnectionThread implements Runnable {
|
|||
}
|
||||
IP_MODIFIER modifier = IP_STATUS_REGISTRY.getOrDefault(IPAddress, IP_MODIFIER.User);
|
||||
if (IP_STATUS_ALLOW_CONNECTION.containsKey(modifier) && IP_STATUS_ALLOW_CONNECTION.get(modifier)) {
|
||||
String IP = IPAddress;
|
||||
taskQueue.add(() -> {
|
||||
try {
|
||||
channel.configureBlocking(false);
|
||||
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
|
||||
key.attach(new ClientSession(channel, modifier, selector, key));
|
||||
System.out.println("Accepted new connection from " + IP);
|
||||
} catch (IOException e) {
|
||||
CloseChannel(channel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public class ServerSelectorMasterThread implements Runnable {
|
|||
|
||||
int index = Math.abs(ManagerIterator.getAndIncrement() % CONNECTION_MANAGER_COUNT);
|
||||
ServerMultiClientConnectionThread targetWorker = ConnectionManagers[index];
|
||||
|
||||
System.out.println("Delegating new Connection [ " + clientChannel.socket().getInetAddress().getHostAddress() + "] to Connection Manager " + index);
|
||||
targetWorker.acceptNewChannel(clientChannel);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ public class ServerSelectorMasterThread implements Runnable {
|
|||
serverChannel.bind(new InetSocketAddress(PORT));
|
||||
serverChannel.configureBlocking(false);
|
||||
serverChannel.register(MasterSelector, SelectionKey.OP_ACCEPT);
|
||||
System.out.println("Boss started on port " + PORT + ". 7 Workers ready to scale to 128+ connections.");
|
||||
System.out.println("Server Master Thread started on port " + PORT + " with " + CONNECTION_MANAGER_COUNT + " connection managers.");
|
||||
|
||||
ManagerIterator = new AtomicInteger(0);
|
||||
acceptThread.start();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue