diff --git a/src/main/java/net/halbear/Executable/Server.java b/src/main/java/net/halbear/Executable/Server.java index 189d986..743d751 100644 --- a/src/main/java/net/halbear/Executable/Server.java +++ b/src/main/java/net/halbear/Executable/Server.java @@ -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 ConnectedClients = new ConcurrentHashMap<>(); public static Map 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 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": diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java index 85f064d..cbe5310 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java @@ -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.*; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidPhysicsController.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidPhysicsController.java index aa5f351..70e99bb 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidPhysicsController.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidPhysicsController.java @@ -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.*; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java index 6ae7513..9b85a63 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java index 18e951b..db2a961 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -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); } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java index 7df6914..ddf2a87 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java @@ -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(); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/GameChat.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/GameChat.java index 839b4e1..ac799e2 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/GameChat.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/GameChat.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/SettingsMenu.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/SettingsMenu.java index fa043ff..0de0775 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/SettingsMenu.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/GUIs/SettingsMenu.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/PlayerActor.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/PlayerActor.java index 13cc160..ab0286c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/PlayerActor.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/PlayerActor.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java index 9013e11..101a29d 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java index c338a6b..b2d4795 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java @@ -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 VkMeshList = model.GetVkMeshList(); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java index 22bd847..c157bee 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java @@ -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 VkMeshList = model.GetVkMeshList(); int MeshCount = VkMeshList.size(); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSession.java b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSession.java index 1a39d7b..eb138a8 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSession.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSession.java @@ -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); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSideNetworkUtils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSideNetworkUtils.java index a832ac2..cdb5b3b 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSideNetworkUtils.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ClientSideNetworkUtils.java @@ -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 OutGoingPacketQueue = new ConcurrentLinkedQueue<>(); public static final Queue IncomingPacketQueue = new ConcurrentLinkedQueue<>(); + private static final Map ServerClientUUIDs = new ConcurrentHashMap<>(); + private static final String CachePath = "resources/ProgramResources/ServerCache/UUIDs.json"; + private static final Queue 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 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 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 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) { diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ServerSideNetworkUtils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ServerSideNetworkUtils.java index e3360d8..cd5ea75 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ServerSideNetworkUtils.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/ServerSideNetworkUtils.java @@ -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)); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/UUIDCache.java b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/UUIDCache.java new file mode 100644 index 0000000..f1c3d6f --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/ServerNetworking/UUIDCache.java @@ -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; + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnection.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnection.java new file mode 100644 index 0000000..4466e0d --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnection.java @@ -0,0 +1,6 @@ +package net.halbear.Terrain4J.EngineCore.Threads; + +public interface ClientConnection extends Runnable{ + public void start(); + public Thread GetNetworkedThread(); +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnectionThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnectionThread.java index 9c770a2..6b782ad 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnectionThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ClientConnectionThread.java @@ -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() { diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/NIO_ClientConnectionThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/NIO_ClientConnectionThread.java index c3e9157..ebc37b6 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/NIO_ClientConnectionThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/NIO_ClientConnectionThread.java @@ -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 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 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(); } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerConnectionThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerConnectionThread.java index 8d7a24b..34b6741 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerConnectionThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerConnectionThread.java @@ -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; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerMultiClientConnectionThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerMultiClientConnectionThread.java index c1fe25a..cace199 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerMultiClientConnectionThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerMultiClientConnectionThread.java @@ -37,9 +37,12 @@ public class ServerMultiClientConnectionThread implements Runnable { private final Queue 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); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerSelectorMasterThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerSelectorMasterThread.java index e2de8a4..e80d171 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerSelectorMasterThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/ServerSelectorMasterThread.java @@ -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(); diff --git a/terrain4j.properties b/terrain4j.properties index 4224823..a5286f7 100644 --- a/terrain4j.properties +++ b/terrain4j.properties @@ -1,5 +1,5 @@ #created new properties file -#Tue Aug 18 20:22:42 BST 2026 +#Fri Aug 21 19:04:58 BST 2026 AlphaToCoverage=false Debug_Shaders=false DefaultTexturePath=resources/EngineResources/Texture/NoTexture.png @@ -28,11 +28,11 @@ frame_accuracy=0 main_thread_tickrate=120 master_tick_rate=240 server=false -server_port=25565 -server_ip=localhost +server_ip=gameserver.halbear.net +server_port=25566 throttle_accuracy=4000000 throttle_on_unfocus=false -user_display_name=halbear +user_display_name=The sigmarest of sigmas vkValidated=true vsync=false z_far_plane=0.1f