Multiplayer networking + broke a bunch of things, we'll need to redo gun switching

This commit is contained in:
Halbear 2026-07-09 00:18:29 +01:00
parent c270a049b5
commit f3c83bea80
23 changed files with 23298 additions and 1071 deletions

View file

@ -4,10 +4,12 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import org.tinylog.Logger;
import org.tinylog.configuration.Configuration;
//Halbear was here
public class Init {
public static void main(String[] args){
Configuration.set("writer.file", "ClientLog.t4jlog");
Logger.info("\nLaunching New Terrain4J Powered Software!");
var GameEngine = new PrimaryRuntime(EngineConfig.getInstance().GetSoftwareName(), new GameCore());
Logger.info("Launched Terrain4J Engine");

View file

@ -0,0 +1,82 @@
package net.halbear.Executable;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.Packet;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import net.halbear.Terrain4J.EngineCore.Threads.ServerConnectionThread;
import org.tinylog.Logger;
import org.tinylog.configuration.Configuration;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Server {
public static Map<UUID, ServerConnectionThread> ConnectedClients = new ConcurrentHashMap<>();
public static final Queue<Packet> OutGoingPacketQueue = new ConcurrentLinkedQueue<>();
public static final Queue<Packet> IncomingPacketQueue = new ConcurrentLinkedQueue<>();
public static void CollectIncomingPackets(){
ConnectedClients.forEach((uuid,client)->{
client.CollectIncomingPackets(IncomingPacketQueue);
});
}
public static void ProcessIncomingPackets(){
Packet packet;
while((packet = IncomingPacketQueue.poll()) != null){
ServerConnectionThread.ProcessClientPacket(packet);
}
}
public static void ProcessOutgoingPackets(){
Packet packet;
while((packet = OutGoingPacketQueue.poll()) != null){
Packet packetToSend = packet;
ConnectedClients.forEach((uuid,client)->{
client.AddOutgoingPacket(packetToSend);
});
}
}
public static void RemoveClient(UUID clientID){
ServerConnectionThread connection = ConnectedClients.remove(clientID);
if(connection != null){
connection.DestroyOwnedActor();
}
}
public static void main(String[] args) throws IOException {
Configuration.set("writer.file", "ServerLog.t4jlog");
ServerSocket server = new ServerSocket(25565);
Logger.info("\nLaunching New Terrain4J Powered Software!");
RenderThread.Headless = true;
PrimaryRuntime.Server = true;
Thread acceptThread = new Thread(() -> {
while(true) {
try {
Socket clientSocket = server.accept();
new Thread(new ServerConnectionThread(clientSocket)).start();
} catch (IOException e) {
Logger.error(e, "Failed to accept client connection");
}
}
}, "Terrain4J Server Accept Thread");
acceptThread.start();
var GameEngine = new PrimaryRuntime(EngineConfig.getInstance().GetSoftwareName(), new GameCore());
Logger.info("Launched Terrain4J Engine");
GameEngine.run();
}
}

View file

@ -25,6 +25,7 @@ public class Window {
private boolean displayFPS = false;
public Window(String title){
if (!glfwInit()) {
throw new RuntimeException("Unable to initialize GLFW");
}

View file

@ -27,6 +27,7 @@ public class ConvexMesh {
public final Vector3f Position = new Vector3f();
public final Quaternionf Orientation = new Quaternionf();
public Vector3f hxhyhz = new Vector3f();
public Vector3f WorldVertex(int i) {
Vector3f vertex = new Vector3f(LocalVertices.get(i));
@ -81,6 +82,7 @@ public class ConvexMesh {
//Creates a basic AABB, that said, its not really axis aligned so idk why im referring to is as one
public static ConvexMesh Box(float hx, float hy, float hz) {
ConvexMesh mesh = new ConvexMesh();
mesh.hxhyhz.set(hx,hy,hz);
mesh.LocalVertices.add(new Vector3f(-hx, -hy, -hz)); // 0
mesh.LocalVertices.add(new Vector3f( hx, -hy, -hz)); // 1
mesh.LocalVertices.add(new Vector3f( hx, hy, -hz)); // 2

View file

@ -3,7 +3,9 @@ package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
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.Threads.ClientConnectionThread;
import org.joml.Vector2f;
import org.joml.Vector3f;
@ -101,8 +103,18 @@ public class RigidPhysicsController implements IPhysicsController {
@Override
public void PhysicsTick(float DeltaTime, float TargetFrameRate) {
Actor actor = Actor.Actors.get(ActorID);
if(!PrimaryRuntime.Server
&& ClientConnectionThread.Connected
&& actor != null
&& actor.IsServerSynced()
&& !ActorID.equals(ClientConnectionThread.OwnedActorID)) {
return;
}
DeltaTime/=10f;
// if(DeltaTime >0.1f) DeltaTime = 0.1f;
// if(DeltaTime >0.1f) DeltaTime = 0.1f;
if(RigidBodyID != null && RigidBodyRegister.get(RigidBodyID) != null && ActorID != "NULL") {
RigidBody rigidBody = RigidBodyRegister.get(RigidBodyID);

View file

@ -1,11 +1,11 @@
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidCollision;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.SeparatingAxisTheoremTester;
import net.halbear.Terrain4J.EngineCore.Threads.PhysicsThread;
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.Threads.ClientConnectionThread;
import net.halbear.Terrain4J.EngineCore.Threads.InstancedPhysicsThread;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.primitives.AABBf;
@ -28,7 +28,7 @@ public class WorldPhysicsManager {
public static int MaxSubStepsPerFrame = 8;
private static float Accumulator = 0f;
private static boolean SingleThread = false;
private static List<PhysicsThread> physicsThreads = new ArrayList<>();
private static List<InstancedPhysicsThread> physicsThreads = new ArrayList<>();
public static void SteppedPhysicsTick(float DeltaTime, float TargetFrameTime){
int ThreadsNeeded = (int)Math.floor(ActiveControllers.size()/100f);
@ -99,6 +99,7 @@ public class WorldPhysicsManager {
for (int i = 0; i < ids.size(); i++) {
RigidBody body = RigidBody.RigidBodyRegister.get(ids.get(i));
if (body == null) continue;
if(IsClientRemoteNetworkBody(body)) continue;
AABBf bounds = body.shape.GetWorldAABB();
worldBounds.put(body.RigidBodyID, bounds);
@ -133,6 +134,37 @@ public class WorldPhysicsManager {
}
}
private static boolean IsClientRemoteNetworkBody(RigidBody body) {
if (PrimaryRuntime.Server || !ClientConnectionThread.Connected || body == null) {
return false;
}
if(body.IsStatic) {
return false;
}
Actor actor = GetActorForRigidBody(body);
return actor != null
&& actor.IsServerSynced()
&& !actor.GetID().equals(ClientConnectionThread.OwnedActorID);
}
private static Actor GetActorForRigidBody(RigidBody body) {
for (Actor actor : Actor.Actors.values()) {
if (!(actor.GetPhysicsController() instanceof RigidPhysicsController rigidPhysicsController)) {
continue;
}
if (rigidPhysicsController.RigidBodyID.equals(body.RigidBodyID)) {
return actor;
}
}
return null;
}
private static void TryResolve(RigidBody a, RigidBody b, Map<String, AABBf> worldBounds, Set<String> testedPairs) {
String key = a.RigidBodyID.compareTo(b.RigidBodyID) < 0
? a.RigidBodyID + "|" + b.RigidBodyID
@ -151,14 +183,48 @@ public class WorldPhysicsManager {
DeltaTime *= EngineConfig.getInstance().PhysicsSpeed();
if(EngineConfig.getInstance().IsEngineThrottled()) return;
PhysicsTick++;
for (int i = 0; i < ActiveControllers.size(); i++) {
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(DeltaTime, TargetFrameTime);
IPhysicsController controller = PhysicsObjects.get(ActiveControllers.get(i));
if(controller != null) {
controller.PhysicsTick(DeltaTime, TargetFrameTime);
}
}
SweepForTunneling();
ResetGroundedFlags();
ResolveAllCollisions();
SyncRigidBodiesToActors();
for (int i = 0; i < ActiveControllers.size(); i++) {
PhysicsObjects.get(ActiveControllers.get(i)).Collisions().clear();
IPhysicsController controller = PhysicsObjects.get(ActiveControllers.get(i));
if(controller != null) {
controller.Collisions().clear();
}
}
}
private static void SyncRigidBodiesToActors(){
for (int i = 0; i < ActiveControllers.size(); i++) {
IPhysicsController controller = PhysicsObjects.get(ActiveControllers.get(i));
if(!(controller instanceof RigidPhysicsController rigidPhysicsController)) continue;
Actor actor = Actor.Actors.get(rigidPhysicsController.ActorID);
RigidBody body = RigidBody.RigidBodyRegister.get(rigidPhysicsController.RigidBodyID);
if(actor == null || body == null) continue;
if(!PrimaryRuntime.Server
&& ClientConnectionThread.Connected
&& actor.IsServerSynced()
&& !actor.GetID().equals(ClientConnectionThread.OwnedActorID)) {
continue;
}
actor.SetPosition(new Vector3f(body.Position));
if(rigidPhysicsController.ApplyRotation) {
actor.SetRotation(body.Rotation);
}
}
}

View file

@ -5,6 +5,7 @@ import imgui.ImGuiIO;
import imgui.ImGuiViewport;
import imgui.flag.ImGuiCond;
import imgui.flag.ImGuiWindowFlags;
import net.halbear.Executable.Server;
import net.halbear.Terrain4J.EngineCore.Audio.AudioManager;
import net.halbear.Terrain4J.EngineCore.Audio.SoundListener;
import net.halbear.Terrain4J.EngineCore.Display.Window;
@ -26,6 +27,9 @@ import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.LoadingScreen;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import net.halbear.Terrain4J.EngineCore.Threads.ServerConnectionThread;
import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MaterialData;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
@ -39,6 +43,7 @@ import org.tinylog.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.lwjgl.glfw.GLFW.*;
@ -48,9 +53,7 @@ public class GameCore implements GameLogic {
private static final float MOVEMENT_SPEED = 0.01f;
public static boolean LoadingLevel = false;
public List<Actor> CubeActors = new ArrayList<>();
private Vector2f LastMousePos = new Vector2f(0,0);
private int GUI_MODE = 0;
private GuiTexture guiTexture;
public List<String[]> PerformanceMetrics = new ArrayList<>();
public List<String[]> SettingPerformanceMetrics = new ArrayList<>();
@ -59,13 +62,13 @@ public class GameCore implements GameLogic {
public int NextAAMode = -1;
public long LastFrameTime = 0;
public long CoolDown = 1000;
public ModelData MusicParticle;
public ModelData radio;
public ModelData MelonaData;
private String CubeModelID = "Cube";
private ModelData MusketData;
private ModelData RevolverData;
public ILight SkyLight;
private LoadingScreen loadingScreen;
public List<IMoveableActorComponent> ActorEditorComponents = new ArrayList<>();
private Gimbal gimbal;
private Vector2f DeltaPos = new Vector2f(0,0);
private String PlayerActorID = "NULL";
@ -81,47 +84,41 @@ public class GameCore implements GameLogic {
List<ModelData> models = new ArrayList<>();
MelonaData = ModelLoader.LoadModel("resources/models/cube/Cube.json");
CubeModelID = MelonaData.ID();
List<MaterialData> MelonaMat = ModelLoader.LoadMaterials("resources/models/cube/Cube_mat.json");
CollisionMesh mesh = new CollisionMesh("Super Collision Mesh","NULL");
mesh.AddNewCollisionPoly(new Vector3f(-100,-5,100),new Vector3f(-100,-5.5f,-100),new Vector3f(100,-6,-100));
mesh.AddNewCollisionPoly(new Vector3f(100,-5.5f,100),new Vector3f(100,-6,-100),new Vector3f(-100,-5,100));
ModelData MusketData = ModelLoader.LoadModel("resources/models/musket/musket.json");
List<MaterialData> MusketMat = ModelLoader.LoadMaterials("resources/models/musket/musket_mat.json");
var Musket = new PlayerActor("DebugCamera","Player_Musket", MusketData.ID(), new Vector3f(0,5f,-5f)).SetCameraOffset(new Vector3f(0,1.0f,0));
Musket.SetPositionOffset(new Vector3f(0.5f,1.0f,-1.25f));
Musket.SetRotation(0,(float)Math.toRadians(180),0);
Musket.CreatePhysicsController( ConvexMesh.Box(0.5f,0.75f,0.5f),200f);
PlayerActorID = "Player_Musket";
scene.Musket = Musket;
scene.CreatePlayerController(scene.Musket);
RigidPhysicsController physicsController = (RigidPhysicsController) Musket.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
ModelData RevolverData = ModelLoader.LoadModel("resources/models/Revolver/Revolver.json");
List<MaterialData> RevolverMat = ModelLoader.LoadMaterials("resources/models/Revolver/Revolver_mat.json");
var Revolver = new PlayerActor("NULL","Player_Revolver", RevolverData.ID(), new Vector3f(0,5f,-5f)).SetCameraOffset(new Vector3f(0,1.0f,0));
Revolver.SetPositionOffset(new Vector3f(0.5f,1.0f,-1.25f));
Revolver.SetRotation(0,(float)Math.toRadians(180),0);
Revolver.CreatePhysicsController( ConvexMesh.Box(0.5f,0.75f,0.5f),200f);
scene.Revolver = Revolver;
PlayerActorID = "Player_Revolver";
physicsController = (RigidPhysicsController) Revolver.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
// if I put PlayerActorID = "Player_Revolver" it just crashes
mesh.RegisterMesh();
scene.AddActor(Musket);
scene.AddActor(Revolver);
CubeActors.forEach(scene::AddActor);
List<MaterialData> materials = new ArrayList<>();
MusketData = ModelLoader.LoadModel("resources/models/musket/musket.json");
List<MaterialData> MusketMat = ModelLoader.LoadMaterials("resources/models/musket/musket_mat.json");
RevolverData = ModelLoader.LoadModel("resources/models/Revolver/Revolver.json");
List<MaterialData> RevolverMat = ModelLoader.LoadMaterials("resources/models/Revolver/Revolver_mat.json");
boolean createOfflinePlayer = !PrimaryRuntime.Server && !ClientConnectionThread.Connected;
if(createOfflinePlayer) {
var Musket = new PlayerActor("DebugCamera","Player_Musket", MusketData.ID(), new Vector3f(0,5f,-5f)).SetCameraOffset(new Vector3f(0,1.0f,0));
Musket.SetPositionOffset(new Vector3f(0.5f,1.0f,-1.25f));
Musket.SetRotation(0,(float)Math.toRadians(180),0);
Musket.CreatePhysicsController( ConvexMesh.Box(0.5f,0.75f,0.5f),200f);
PlayerActorID = "Player_Musket";
scene.Musket = Musket;
scene.CreatePlayerController(scene.Musket);
RigidPhysicsController physicsController = (RigidPhysicsController) Musket.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
var Revolver = new PlayerActor("NULL","Player_Revolver", RevolverData.ID(), new Vector3f(0,5f,-5f)).SetCameraOffset(new Vector3f(0,1.0f,0));
Revolver.SetPositionOffset(new Vector3f(0.5f,1.0f,-1.25f));
Revolver.SetRotation(0,(float)Math.toRadians(180),0);
Revolver.CreatePhysicsController( ConvexMesh.Box(0.5f,0.75f,0.5f),200f);
scene.Revolver = Revolver;
PlayerActorID = "Player_Revolver";
physicsController = (RigidPhysicsController) Revolver.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
scene.AddActor(Musket);
scene.AddActor(Revolver);
materials.addAll(RevolverMat);
}
materials.addAll(MelonaMat);
materials.addAll(MusketMat);
materials.addAll(RevolverMat);
materials.addAll(MelonaMat);
models.add(MelonaData);
models.add(MusketData);
models.add(RevolverData);
@ -129,18 +126,22 @@ public class GameCore implements GameLogic {
camera.SetPosition(0,0,0);
camera.SetRotation(0,0,0);
var LoadingScreenTexture = new GuiTexture(EngineConfig.getInstance().GetLoadingScreenImageLocation());
loadingScreen = new LoadingScreen(LoadingScreenTexture);
guiTexture = new GuiTexture("resources/EngineResources/Texture/Billy.png");
List<GuiTexture> guiTextures = new ArrayList<>();
guiTextures.add(LoadingScreenTexture);
guiTextures.add(guiTexture);
scene.GetLightingManager().GetAmbientLightColour().set(1.0f, 0.9f, 0.75f);
scene.GetLightingManager().SetAmbientLightIntensity(0.4f);
SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.3f), true, 10.00f);
if(!PrimaryRuntime.Server && !RenderThread.Headless) {
var LoadingScreenTexture = new GuiTexture(EngineConfig.getInstance().GetLoadingScreenImageLocation());
loadingScreen = new LoadingScreen(LoadingScreenTexture);
guiTexture = new GuiTexture("resources/EngineResources/Texture/Billy.png");
guiTextures.add(LoadingScreenTexture);
guiTextures.add(guiTexture);
}
scene.GetLightingManager().GetAmbientLightColour().set(1.0f, 0.9f, 0.75f);
scene.GetLightingManager().SetAmbientLightIntensity(0.6f);
SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.3f), true, 2.00f);
List<ILight> lights = new ArrayList<>();
@ -154,9 +155,11 @@ public class GameCore implements GameLogic {
for(int i = 0; i < ActorEditorComponents.size(); i++){
ActorEditorComponents.get(i).UpdateAll();
}
for(int x = -5; x < 6; x++){
for(int y = -5; y < 6; y++){
SpawnNewStaticActor(engineInstance, new Vector3f(x * 4f, -4 *(float)Math.random(), y * 4f), new Vector3f(0,0,0),new Vector3f(1,1,1));
if(PrimaryRuntime.Server) {
for (int x = -5; x < 6; x++) {
for (int y = -5; y < 6; y++) {
SpawnNewStaticActor(engineInstance, new Vector3f(x * 4f, -4 * (float) Math.random(), y * 4f), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
}
}
}
return new InitData(models,materials,guiTextures);
@ -180,9 +183,19 @@ public class GameCore implements GameLogic {
SpawnDirection.set(new Vector3f(Direction));
rotationMatrix.positiveZ(SpawnDirection).negate().mul(5);
SpawnPosition.add(SpawnDirection);
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(SpawnPosition));
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), CubeModelID, new Vector3f(SpawnPosition));
Logger.info("Spawning static cube actor [{}] with model ID [{}], with cached ID of [{}]", Melona.GetID(), Melona.GetModelID(),CubeModelID);
Melona.SetScale(4f);
Melona.CreatePhysicsController( ConvexMesh.Box(2.0f,2.0f,2.0f),0);
Melona.SetServerSynced(false);
scene.AddActor(Melona);
if(PrimaryRuntime.Server) {
ServerConnectionThread.BroadcastCreateActorPacket(Melona);
}
RigidPhysicsController physicsController = (RigidPhysicsController) Melona.GetPhysicsController();
//RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(0,0,-20f -(40f * (float)Math.random()));
scene.AddActor(Melona);
@ -190,6 +203,30 @@ public class GameCore implements GameLogic {
public void SetPlayerActorID(String id) {
this.PlayerActorID = id;
}
public PlayerActor SpawnNetworkPlayer(EngineInstance engineInstance, UUID clientID){
var scene = engineInstance.scene();
String actorID = "Player_" + clientID;
PlayerActor player = new PlayerActor(
"NULL",
actorID,
MusketData.ID(),
new Vector3f(0, 8f, 0)
).SetCameraOffset(new Vector3f(0, 1.0f, 0));
player.SetPositionOffset(new Vector3f(0.5f, 1.0f, -1.25f));
player.SetRotation(0, (float)Math.toRadians(180), 0);
player.CreatePhysicsController(ConvexMesh.Box(0.5f, 0.75f, 0.5f), 200f);
player.SetServerSynced(true);
RigidPhysicsController physicsController = (RigidPhysicsController) player.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
scene.AddActor(player);
return player;
}
public void SpawnNewActor(EngineInstance engineInstance, Vector3f Position, Vector3f Rotation, Vector3f Direction){
var scene = engineInstance.scene();
Camera camera = scene.GetCamera();
@ -198,9 +235,15 @@ public class GameCore implements GameLogic {
SpawnDirection.set(new Vector3f(Direction));
rotationMatrix.positiveZ(SpawnDirection).negate().mul(5);
SpawnPosition.add(SpawnDirection);
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(SpawnPosition));
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), CubeModelID, new Vector3f(SpawnPosition));
Melona.CreatePhysicsController( ConvexMesh.Box(0.5f,0.5f,0.5f),20);
Melona.SetServerSynced(true);
if(PrimaryRuntime.Server) {
ServerConnectionThread.BroadcastCreateActorPacket(Melona);
}
RigidPhysicsController physicsController = (RigidPhysicsController) Melona.GetPhysicsController();
//RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(0,0,-20f -(40f * (float)Math.random()));
scene.AddActor(Melona);
@ -214,7 +257,7 @@ public class GameCore implements GameLogic {
SpawnDirection.set(new Vector3f(Direction));
rotationMatrix.positiveZ(SpawnDirection).negate().mul(5);
SpawnPosition.add(SpawnDirection);
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(SpawnPosition));
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), CubeModelID, new Vector3f(SpawnPosition));
Melona.CreatePhysicsController( ConvexMesh.Box(0.75f,1.2f,0.5f),20);
scene.AddActor(Melona);
@ -222,6 +265,7 @@ public class GameCore implements GameLogic {
}
private void InitiateAudio(EngineInstance engineInstance){
if(RenderThread.Headless || PrimaryRuntime.Server) return;
AudioManager audioManager = engineInstance.audioManager();
Camera camera = engineInstance.scene().GetCamera();
audioManager.SetAttenuationModel(AL11.AL_EXPONENT_DISTANCE);
@ -231,6 +275,10 @@ public class GameCore implements GameLogic {
@Override
public void CameraInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
if(PrimaryRuntime.Server || RenderThread.Headless || engineInstance.window() == null) {
return;
}
float Multiplier = MOUSE_SENSITIVITY;
IScene scene = engineInstance.scene();
Camera camera = scene.GetCamera();
@ -257,10 +305,25 @@ public class GameCore implements GameLogic {
@Override
public void RenderThreadInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
if(ClientConnectionThread.Connected && !"NULL".equals(ClientConnectionThread.OwnedActorID)) {
PlayerActorID = ClientConnectionThread.OwnedActorID;
}
Actor player = Actor.Actors.get(PlayerActorID);
if(player != null){
player.TickUpdate();
}
for(Actor actor : engineInstance.scene().GetActors()) {
if(actor != null
&& actor.IsServerSynced()
&& !actor.IsStaticRigidBody()
&& !actor.GetID().equals(ClientConnectionThread.OwnedActorID)) {
actor.InterpolateNetworkTarget(0.12f);
}
}
if(PrimaryRuntime.Server || RenderThread.Headless) return;
engineInstance.scene().CameraTick(FrameDiffNanoSeconds);
if(ChangeGraphicsSettings){
if(NextAAMode != -1){
@ -279,14 +342,47 @@ public class GameCore implements GameLogic {
@Override
public void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
IScene scene = engineInstance.scene();
Window window = engineInstance.window();
PlayerActor playerActor = (PlayerActor) Actor.Actors.get(PlayerActorID);
scene.Input(engineInstance,FrameDiffNanoSeconds, playerActor, MOVEMENT_SPEED,this);
if(PrimaryRuntime.Server || RenderThread.Headless) return;
IScene scene = engineInstance.scene();
if(ClientConnectionThread.Connected) {
if("NULL".equals(ClientConnectionThread.OwnedActorID)) {
return;
}
Actor ownedActor = Actor.Actors.get(ClientConnectionThread.OwnedActorID);
if(!(ownedActor instanceof PlayerActor networkPlayer)) {
return;
}
if(scene instanceof Scene concreteScene) {
if(networkPlayer.GetPlayerCamera() == null) {
networkPlayer.AttachCamera(concreteScene.GetCamera().GetID());
concreteScene.SetNetworkControlledPlayer(networkPlayer);
}
}
PlayerActorID = ClientConnectionThread.OwnedActorID;
Logger.trace(
"Input using network player [{}], camera [{}]",
networkPlayer.GetID(),
networkPlayer.AttachedCameraID
);
scene.Input(engineInstance, FrameDiffNanoSeconds, networkPlayer, MOVEMENT_SPEED, this);
return;
}
Actor localActor = Actor.Actors.get(PlayerActorID);
if(!(localActor instanceof PlayerActor playerActor)) {
return;
}
scene.Input(engineInstance,FrameDiffNanoSeconds, playerActor, MOVEMENT_SPEED,this);
}
private boolean HandleGui(EngineInstance engineInstance, long frameTimeNS){
if(PrimaryRuntime.Server || RenderThread.Headless) return false;
FetchingMetrics = true;
ImGuiIO imGuiIO = ImGui.getIO();
MouseListener mouseListener = engineInstance.window().getMouseInput();
@ -332,14 +428,30 @@ public class GameCore implements GameLogic {
float PhysicsFramerate = 24f;
float PhysicsFrameTime = 1000f/PhysicsFramerate;
float DeltaTime = (float)FrameDiffNanoSeconds/(PhysicsFrameTime*1000000f);
if(PrimaryRuntime.GetFastThread().Ticks(20)==0){
//CollisionManager.UpdateCollisionChunks();
if(PrimaryRuntime.Server){
Server.CollectIncomingPackets();
Server.ProcessIncomingPackets();
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
if(PrimaryRuntime.GetFastThread().Ticks(6) == 0) {
for(Actor actor : engineInstance.scene().GetActors()) {
if(actor.IsServerSynced() && !actor.IsStaticRigidBody()) {
ServerConnectionThread.SendEntityUpdatePacket(actor);
}
}
}
Server.ProcessOutgoingPackets();
} else {
ClientConnectionThread.DecodePackets(engineInstance, this, engineInstance.scene());
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
}
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
}
@Override
public void SecondUpdate(EngineInstance engineInstance) {
if(PrimaryRuntime.Server || RenderThread.Headless) return;
SettingPerformanceMetrics.clear();
List<String[]> Metrics = new ArrayList<>();
String[] ISceneDetails = new String[8];

View file

@ -9,17 +9,24 @@ import net.halbear.Terrain4J.EngineCore.Logic.InitData;
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.Threads.ClientConnectionThread;
import net.halbear.Terrain4J.EngineCore.Threads.FastTickThread;
import net.halbear.Terrain4J.EngineCore.Threads.MainThread;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import org.tinylog.Logger;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Timer;
import java.util.TimerTask;
public class PrimaryRuntime {
public static boolean Server = false;
private int Frames = 0;
private int TickFrames = 0;
private double TickRate = 0;
@ -38,6 +45,8 @@ public class PrimaryRuntime {
public final CPUMonitor cpuProfiler;
private static GameLogic gameLogic;
public static ClientConnectionThread ServerCon;
public static Thread ServerThread;
public static GameLogic GetGameCore(){return gameLogic;}
public PrimaryRuntime(String windowTitle, GameLogic appLogic) {
@ -55,17 +64,74 @@ public class PrimaryRuntime {
}
}
}
window = new Window(windowTitle);
gameLogic = appLogic;
engineInstance = new EngineInstance(window, new Scene(window),this, new AudioManager());
if (Server) {
window = null;
gameLogic = appLogic;
engineInstance = new EngineInstance(null, new Scene(null), this, null);
} else {
window = new Window(windowTitle);
gameLogic = appLogic;
engineInstance = new EngineInstance(window, new Scene(window), this, new AudioManager());
}
InitData initData = appLogic.Initialise(engineInstance);
PrimaryThread = new MainThread(engineInstance, appLogic);
FastThread = new FastTickThread(engineInstance, appLogic);
DrawingThread = new RenderThread(window, engineInstance, initData, appLogic);
cpuProfiler = new CPUMonitor();
if(!Server) {
ServerCon = new ClientConnectionThread();
ServerThread = new Thread(ServerCon);
ServerThread.start();
}
EngineConfig.getInstance().SetCPU(CPUMonitor.getCpuName(), CPUMonitor.getCoreCount());
Thread.currentThread().setName("Terrain4J Primary Runtime Thread");
}
public static void StartPingTimer() {
Timer timer = new Timer();
ClientConnectionThread.pinging = true;
timer.scheduleAtFixedRate(new TimerTask() {;
@Override
public void run() {
String text = "Halbear.Net Launcher : " + PingServer(ClientConnectionThread.ServerIP, false);
if (ClientConnectionThread.Connected){
ClientConnectionThread.pinging = false;
this.cancel();
}
}
}, 0, 2000);
}
public static String PingServer(String ipAddress, boolean DomainOnly) {
if (DomainOnly) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(ipAddress).openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(1000);
int responseCode = connection.getResponseCode();
if (responseCode >= 300 && responseCode < 400) {
return "Connected to server with problems";
}
if (responseCode >= 400 && responseCode < 500) {
return "Client Problem, Check Internet Connection";
}
if (responseCode >= 500) {
return "Server Problem, Unable To Connect";
} else return "Online";
} catch ( MalformedURLException e) {
//System.out.println(e);
return "Bad URL";
} catch ( IOException e ) {
//System.out.println(e);
return "Connection Error, Server Unreachable";
}
} else if (!ClientConnectionThread.Connected) {
ServerCon = new ClientConnectionThread();
ServerThread = new Thread(ServerCon);
ServerThread.start();
}
return "Connecting...";
}
public static MainThread GetMainThread(){return PrimaryThread;}
public static RenderThread GetRenderThread(){return DrawingThread;}
public static FastTickThread GetFastThread(){return FastThread;}
@ -91,24 +157,52 @@ public class PrimaryRuntime {
}
public void PrimaryRuntimeInputUpdate(long nsTimeDiff){
gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
gameLogic.CameraInput(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
try {
gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
gameLogic.CameraInput(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
} catch (Exception e) {
Logger.error(e, "Primary runtime input update failed");
}
}
public void run(){
UpdateTickRateThreshold();
PrimaryThread.StartThread();
DrawingThread.StartThread();
FastThread.StartThread();
FrameAccuracy = EngineConfig.getInstance().getAccuracy();
OriginalFrameAccuracy = FrameAccuracy;
Logger.debug("Primary Thread Started");
if(Server) {
Logger.info("Terrain4J dedicated server running without GLFW/Vulkan/OpenAL");
while(running) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
ShutDownStart = System.nanoTime();
Logger.debug("Closing dedicated server [{}]", EngineConfig.getInstance().GetSoftwareName());
FastThread.KillThread();
PrimaryThread.KillThread();
DrawingThread.KillThread();
cleanup();
return;
}
long InitialTime = System.nanoTime();
long updateTime = InitialTime;
double FrameDiff =0;
double TickDiff =0;
double SecondCounter =0;
double cycleDiff = 0;
PrimaryThread.StartThread();
DrawingThread.StartThread();
FastThread.StartThread();
FrameAccuracy = EngineConfig.getInstance().getAccuracy();
OriginalFrameAccuracy = FrameAccuracy;
Logger.debug("Primary Thread Started");
while (!window.shouldClose() && running){
long now = System.nanoTime();
cycleDiff = now - InitialTime;
@ -138,6 +232,11 @@ public class PrimaryRuntime {
}
InitialTime = now;
}
ClientConnectionThread.Connected = false;
if(ServerThread != null) {
ServerThread.interrupt();
}
ShutDownStart = System.nanoTime();
Logger.debug("Closing Software of name [{}]",EngineConfig.getInstance().GetSoftwareName());
FastThread.KillThread();
@ -155,7 +254,7 @@ public class PrimaryRuntime {
}
private void cleanup() {
engineInstance.cleanup();
window.cleanup();
Logger.debug("Process still running: [{}]",Thread.getAllStackTraces().keySet().toString());
if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) {
Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen);

View file

@ -4,6 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionM
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidCollision;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
@ -38,6 +39,10 @@ public class Actor{
protected final Vector3f PivotOffset;
protected final Vector3f AdditionalPivotOffset;
protected final Vector3f TemporaryVector;
protected boolean ServerSynced = false;
protected boolean HasNetworkTarget = false;
protected final Vector3f NetworkTargetPosition = new Vector3f();
protected final Quaternionf NetworkTargetRotation = new Quaternionf();
public PhysicsControllerType PhysicsType = PhysicsControllerType.RigidBodySeparatingAxisTheory;
public void SetPhysicsType(PhysicsControllerType type){
@ -64,10 +69,6 @@ public class Actor{
Actors.put(ID,this);
}
public Vector3f GetPositionOffset(){
return PositionOffset;
}
public Actor SetPositionOffset(Vector3f PositionOffset){
this.PositionOffset.set(PositionOffset);
return this;
@ -95,6 +96,47 @@ public class Actor{
public void TickUpdate() {
}
public Actor SetServerSynced(boolean synced){
this.ServerSynced = synced;
return this;
}
public boolean IsServerSynced(){
return ServerSynced;
}
public boolean IsStaticRigidBody(){
RigidBody rigidBody = GetRigidBody();
return rigidBody != null && rigidBody.IsStatic;
}
public void SetNetworkTarget(Vector3f position, Quaternionf rotation){
NetworkTargetPosition.set(position);
NetworkTargetRotation.set(rotation);
HasNetworkTarget = true;
}
public void InterpolateNetworkTarget(float alpha){
if(!HasNetworkTarget) return;
Position.lerp(NetworkTargetPosition, alpha);
Rotation.slerp(NetworkTargetRotation, alpha);
UpdateModelMatrix();
RigidBody rigidBody = GetRigidBody();
if(rigidBody != null) {
rigidBody.Position.set(Position);
rigidBody.Rotation.set(Rotation);
}
}
public Vector3f GetPositionOffset(){
return PositionOffset;
}
public Vector3f GetAdditionalPivotOffset(){
return AdditionalPivotOffset;
}
public IPhysicsController GetPhysicsController(){return physicsController;}
@ -142,6 +184,7 @@ public class Actor{
return this;
}
public Actor SetRotation(float x, float y, float z){
Rotation.identity();
Rotation.rotateX(x);
Rotation.rotateY(y);
Rotation.rotateZ(z);
@ -165,6 +208,54 @@ public class Actor{
return this;
}
public void SetNewAngularVelocity(Vector3f Velocity){
RigidBody rigidBody = GetRigidBody();
if (rigidBody == null) return;
rigidBody.AngularVelocity.set(Velocity);
}
public void SetNewVelocity(Vector3f Velocity){
RigidBody rigidBody = GetRigidBody();
if (rigidBody == null) return;
rigidBody.LinearVelocity.set(Velocity);
}
public void SetNewRotation(Quaternionf Rotation){
RigidBody rigidBody = GetRigidBody();
if (rigidBody == null) return;
rigidBody.Rotation.set(Rotation);
this.Rotation.set(Rotation);
UpdateModelMatrix();
}
public void SetNewPosition(Vector3f Position){
RigidBody rigidBody = GetRigidBody();
if (rigidBody == null) {
SetPosition(Position);
return;
}
rigidBody.Position.set(Position);
this.Position.set(Position);
UpdateModelMatrix();
if(collisionMesh != null) collisionMesh.SetWorldPosition(this.Position);
}
private RigidBody GetRigidBody() {
if (PhysicsType != PhysicsControllerType.RigidBodySeparatingAxisTheory) return null;
if (!(GetPhysicsController() instanceof RigidPhysicsController rigidPhysicsController)) return null;
return RigidBody.RigidBodyRegister.get(rigidPhysicsController.RigidBodyID);
}
public Actor SetScale(Vector3f Scale){
this.Scale = new Vector3f(Scale);
UpdateModelMatrix();
return this;
}
public Actor SetScale(float Scale){
this.Scale = new Vector3f(Scale,Scale,Scale);

View file

@ -26,36 +26,82 @@ import static org.lwjgl.glfw.GLFW.GLFW_KEY_TAB;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_W;
public class PhysicsPlayerController implements IPlayerInputEvents {
public PhysicsPlayerController(){
}
@Override
public void Input(KeyboardInput input, long FrameDiffNanoSeconds, PlayerActor playerActor, float MOVEMENT_SPEED, GameCore GameCore, IScene ParentScene) {
Scene scene = (Scene)ParentScene;
float MovementDist = (float)(FrameDiffNanoSeconds / 1000000L) * MOVEMENT_SPEED;
public void Input(
KeyboardInput input,
long frameDiffNanoseconds,
PlayerActor playerActor,
float movementSpeed,
GameCore gameCore,
IScene parentScene
) {
if (input == null || playerActor == null || !(parentScene instanceof Scene scene)) {
return;
}
Camera camera = scene.GetCamera();
if(playerActor!= null)camera = Camera.GetCamera(playerActor.AttachedCameraID);
if(input.keyPressed(GLFW_KEY_W)){
playerActor.Move(new Vector3f(MovementDist* (float)Math.sin((camera.GetRotation().y)),0,-MovementDist* (float)Math.cos((camera.GetRotation().y))));
Camera attachedCamera = Camera.GetCamera(playerActor.AttachedCameraID);
if (attachedCamera != null) {
camera = attachedCamera;
}
if(input.keyPressed(GLFW_KEY_S)){
playerActor.Move(new Vector3f(-MovementDist* (float)Math.sin((camera.GetRotation().y)),0,MovementDist * (float)Math.cos((camera.GetRotation().y))));
if (camera == null) {
return;
}
if(input.keyPressed(GLFW_KEY_A)){
playerActor.Move(new Vector3f(-MovementDist * (float)Math.cos((camera.GetRotation().y)),0,-MovementDist * (float)Math.sin((camera.GetRotation().y))));
float deltaMilliseconds = frameDiffNanoseconds / 1_000_000.0f;
float movementDist = deltaMilliseconds * movementSpeed;
float yaw = camera.GetRotation().y;
float sinYaw = (float) Math.sin(yaw);
float cosYaw = (float) Math.cos(yaw);
Vector3f movement = new Vector3f();
if (input.keyPressed(GLFW_KEY_W)) {
movement.add(sinYaw, 0, -cosYaw);
}
if(input.keyPressed(GLFW_KEY_D)){
playerActor.Move(new Vector3f(MovementDist * (float)Math.cos((camera.GetRotation().y)),0,MovementDist * (float)Math.sin((camera.GetRotation().y))));
if (input.keyPressed(GLFW_KEY_S)) {
movement.add(-sinYaw, 0, cosYaw);
}
if (input.keyPressed(GLFW_KEY_A)) {
movement.add(-cosYaw, 0, -sinYaw);
}
if (input.keyPressed(GLFW_KEY_D)) {
movement.add(cosYaw, 0, sinYaw);
}
if (movement.lengthSquared() > 0.0f) {
movement.normalize().mul(movementDist);
playerActor.Move(movement);
}
if (playerActor != null) {
RigidPhysicsController physicsController = (RigidPhysicsController) playerActor.GetPhysicsController();
RigidBody body = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if (body != null && body.Grounded) {
scene.Jumps = 0;
scene.GroundedGraceTicks = scene.MaxGroundedGraceTicks;
} else if(scene.GroundedGraceTicks > 0) {
scene.GroundedGraceTicks--;
}
}
if (input.keySinglePress(GLFW_KEY_SPACE)) {
if (scene.Jumps < scene.MaxJumps) {
if (playerActor != null) playerActor.Move(new Vector3f(0, 5f, 0));
boolean canUseGroundJump = scene.GroundedGraceTicks > 0 && scene.Jumps == 0;
if (canUseGroundJump || scene.Jumps < scene.MaxJumps) {
if (playerActor != null) playerActor.Jump(5.0f);
scene.Jumps++;
scene.GroundedGraceTicks = 0;
}
}
}
}

View file

@ -4,6 +4,8 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
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.Threads.ClientConnectionThread;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.tinylog.Logger;
@ -32,37 +34,23 @@ public class PlayerActor extends Actor{
return PlayerCam;
}
public PlayerActor SetCameraOffset(Vector3f Offset){
CameraOffset.set(Offset);
public PlayerActor AttachCamera(String cameraID){
Camera camera = Camera.CameraRegistry.get(cameraID);
if(camera == null) {
Logger.warn("Could not attach camera [{}] to player actor [{}]", cameraID, GetID());
return this;
}
AttachedCameraID = cameraID;
PlayerCam = camera;
Logger.info("Attached camera [{}] to player actor [{}]", cameraID, GetID());
return this;
}
public void SetNewAngularVelocity(Vector3f Velocity){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).AngularVelocity.set(Velocity);
}
}
public void SetNewVelocity(Vector3f Velocity){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(Velocity);
}
}
public void SetNewRotation(Quaternionf Rotation){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).Rotation.set(Rotation);
}
}
public void SetNewPosition(Vector3f Position){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).Position.set(Position);
}
public PlayerActor SetCameraOffset(Vector3f Offset){
CameraOffset.set(Offset);
return this;
}
@Override
@ -72,22 +60,58 @@ public class PlayerActor extends Actor{
PlayerCam = Camera.CameraRegistry.get(AttachedCameraID);
if(PlayerCam == null) return;
}
Vector3f Rotation = PlayerCam.GetRotation();
Vector3f Position = new Vector3f(GetPosition());
GetRotation().identity().rotateYXZ(-Rotation.y, -Rotation.x, Rotation.z);
GetRotation().identity().rotateYXZ(-Rotation.y, -Rotation.x, Rotation.z);
SetNewRotation(GetRotation());
UpdateModelMatrix();
if(Position == null || CameraOffset == null) return;
Position.add(CameraOffset);
PlayerCam.SetPosition(Position.x, Position.y, Position.z);
if(!PrimaryRuntime.Server
&& ClientConnectionThread.Connected
&& GetID().equals(ClientConnectionThread.OwnedActorID)) {
ClientConnectionThread.SendEntityUpdatePacket(this);
}
}
public void Move(Vector3f Velocity){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.add(Velocity);
RigidBody body = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if(body == null) return;
body.LinearVelocity.add(Velocity);
float maxHorizontalSpeed = 8.0f;
float horizontalSpeedSquared =
body.LinearVelocity.x * body.LinearVelocity.x +
body.LinearVelocity.z * body.LinearVelocity.z;
if(horizontalSpeedSquared > maxHorizontalSpeed * maxHorizontalSpeed) {
float horizontalSpeed = (float)Math.sqrt(horizontalSpeedSquared);
float scale = maxHorizontalSpeed / horizontalSpeed;
body.LinearVelocity.x *= scale;
body.LinearVelocity.z *= scale;
}
}
}
public void Jump(float jumpVelocity){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody body = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if(body == null) return;
body.LinearVelocity.y = jumpVelocity;
body.Grounded = false;
}
}
/* @Override
public void UpdateModelMatrix(){
if(PlayerCam != null){

View file

@ -23,13 +23,27 @@ public class PlayerController implements IPlayerController{
public PlayerController(PlayerActor Player, String ContollerID){
this.playerActor = Player;
PlayerCamera = Player.PlayerCam.GetID();
if(Player.PlayerCam != null) {
PlayerCamera = Player.PlayerCam.GetID();
} else if(Player.AttachedCameraID != null) {
PlayerCamera = Player.AttachedCameraID;
} else {
PlayerCamera = "DebugCamera";
}
ID = ContollerID;
ControllerRegistry.put(ContollerID,this);
}
public void SwitchActor(PlayerActor newActor){
if(newActor == null) return;
if(newActor.PlayerCam == null && newActor.AttachedCameraID != null) {
newActor.AttachCamera(newActor.AttachedCameraID);
}
if(newActor.PlayerCam == null) return;
if(playerActor.PhysicsType == Actor.PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) playerActor.GetPhysicsController();
newActor.SetNewPosition(RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).Position);
@ -37,6 +51,7 @@ public class PlayerController implements IPlayerController{
newActor.SetNewVelocity(RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity);
newActor.SetNewAngularVelocity(RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).AngularVelocity);
}
playerActor = newActor;
PlayerCamera = newActor.PlayerCam.GetID();
}

View file

@ -14,6 +14,8 @@ import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.PerformanceOverlay;
import net.halbear.Terrain4J.EngineCore.Threads.ClientConnectionThread;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh.DynamicTerrainMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Projection.Project3D;
import org.joml.Vector2f;
@ -54,6 +56,8 @@ public class Scene implements IScene {
public int Jumps = 0;
public final int MaxJumps = 2;
public int GroundedGraceTicks = 0;
public final int MaxGroundedGraceTicks = 8;
public PlayerActor CurrentWeapon;
public PlayerActor Musket;
public PlayerActor Revolver;
@ -84,7 +88,7 @@ public class Scene implements IScene {
public SkyBox GetSkyBox(){return skyBox;}
public Scene(Window window) {
// CreateTerrainMesh();
// CreateTerrainMesh();
lightingManager = new SceneLightingManager(1000,new Vector3f(1f,1f,1f), 0.5f);
Actors = new HashMap<>();
audioInstances = new HashMap<>();
@ -93,12 +97,18 @@ public class Scene implements IScene {
var EngConfig = EngineConfig.getInstance();
camera = new Camera("DebugCamera");
LastCameraFrame = new CameraFrame(camera.GetPosition(),camera.GetRotation(),camera.GetFOV(), "NO_FRAME");
Projection = new Project3D(camera.GetFOV(),EngConfig.GetZNearPlane(), EngConfig.GetZFarPlane(),
window.getWidth(), window.getHeight());
GUIReg.put("PerformanceOverlay",new PerformanceOverlay());
ActiveGUIs.add("PerformanceOverlay");
}
int projectionWidth = window != null ? window.getWidth() : EngConfig.getWidth();
int projectionHeight = window != null ? window.getHeight() : EngConfig.getHeight();
Projection = new Project3D(camera.GetFOV(),EngConfig.GetZNearPlane(), EngConfig.GetZFarPlane(),
projectionWidth, projectionHeight);
if(!PrimaryRuntime.Server && !RenderThread.Headless) {
GUIReg.put("PerformanceOverlay",new PerformanceOverlay());
ActiveGUIs.add("PerformanceOverlay");
}
}
public ISceneLightingManager GetLightingManager(){return lightingManager;}
public void CameraTick(long FrameDiffNanoSeconds){
@ -143,11 +153,6 @@ public class Scene implements IScene {
}
}
public void CreatePlayerController(PlayerActor CurrentActor){
CurrentWeapon = CurrentActor;
playerController = new PlayerController(CurrentWeapon, "PLAYERCONTROLLER");
}
public Map<String, CameraFrame> GetCameraFrameReg(){return CameraFrames;}
public CameraFrame GetCameraFrame(String Name){return CameraFrames.get(Name);}
public Scene AddCameraFrame(String Name, CameraFrame frame){
@ -165,6 +170,7 @@ public class Scene implements IScene {
@Override
public void SetUpAudio(EngineInstance engineInstance, AudioManager manager) {
if(RenderThread.Headless || PrimaryRuntime.Server) return;
AudioInstance newInstance = new AudioInstance("resources/EngineResources/audio/music/MENUMUSIC_RetroFutureClean.ogg","BGM",manager,true);
newInstance.Play();
audioInstances.put("BGM",newInstance);
@ -172,8 +178,13 @@ public class Scene implements IScene {
public Camera GetCamera(){return camera;}
public void AddActor(Actor NewActor){
if(NewActor == null) return;
Actors.put(NewActor.GetID(), NewActor);
ActiveActors.add(NewActor.GetID());
if(!ActiveActors.contains(NewActor.GetID())) {
ActiveActors.add(NewActor.GetID());
}
}
public List<Actor> GetActors(){
List<Actor> actors = new ArrayList<>();
@ -184,7 +195,44 @@ public class Scene implements IScene {
}
public Project3D GetProjection(){return Projection;}
public void RemoveAllActors(){Actors.clear();}
public Actor RemoveActor(Actor actor){return Actors.remove(actor.GetID());}
public Actor RemoveActor(Actor actor){
if(actor == null) return null;
ActiveActors.remove(actor.GetID());
Actor.Actors.remove(actor.GetID());
Actor.ActorNames.remove(actor.GetID());
return Actors.remove(actor.GetID());
}
public void CreatePlayerController(PlayerActor CurrentActor){
CurrentWeapon = CurrentActor;
playerController = new PlayerController(CurrentWeapon, "PLAYERCONTROLLER");
}
public void SetNetworkControlledPlayer(PlayerActor networkPlayer){
if(networkPlayer == null) return;
if(Musket != null && Musket != networkPlayer) {
Musket.AttachedCameraID = "NULL";
}
if(Revolver != null && Revolver != networkPlayer) {
Revolver.AttachedCameraID = "NULL";
}
Camera camera = GetCamera();
if(camera == null) return;
networkPlayer.AttachCamera(camera.GetID());
networkPlayer.SetCameraOffset(new Vector3f(0, 1.0f, 0));
CurrentWeapon = networkPlayer;
Musket = networkPlayer;
Revolver = networkPlayer;
playerController = new PlayerController(networkPlayer, "PLAYERCONTROLLER");
playerController.SetPlayerCamera(camera.GetID());
}
public void SetCurrentWeapon(PlayerActor Weapon) {this.CurrentWeapon = Weapon; }
@ -205,28 +253,31 @@ public class Scene implements IScene {
if(input.keyPressed(GLFW_KEY_ENTER)) {
parent.SpawnNewActor(engineInstance, new Vector3f( (float)(5 * Math.random()),20 + (float)(10 * Math.random()), (float)(5 * Math.random())),new Vector3f(-1f + (float)(2 * Math.random()),-1f + (float)(2 * Math.random()),-1f + (float)(2 * Math.random())),new Vector3f((float)Math.random(),(float)Math.random(),(float)Math.random()));
}
if (input.keySinglePress(GLFW_KEY_R) && CurrentWeapon != Revolver) {
scene.RemoveActor(Musket);
scene.AddActor(Revolver);
playerController.SwitchActor(Revolver);
CurrentWeapon = Revolver;
playerActor = Revolver;
parent.SetPlayerActorID(Revolver.GetID());
Musket.AttachedCameraID = "NULL";
Revolver.AttachedCameraID = "DebugCamera";
if(!ClientConnectionThread.Connected) {
if (input.keySinglePress(GLFW_KEY_R) && CurrentWeapon != Revolver) {
scene.RemoveActor(Musket);
scene.AddActor(Revolver);
playerController.SwitchActor(Revolver);
CurrentWeapon = Revolver;
playerActor = Revolver;
parent.SetPlayerActorID(Revolver.GetID());
Musket.AttachedCameraID = "NULL";
Revolver.AttachedCameraID = "DebugCamera";
}
if (input.keySinglePress(GLFW_KEY_M) && CurrentWeapon != Musket) {
scene.RemoveActor(Revolver);
scene.AddActor(Musket);
playerController.SwitchActor(Musket);
CurrentWeapon = Musket;
playerActor = Musket;
parent.SetPlayerActorID(Musket.GetID());
Musket.AttachedCameraID = "DebugCamera";
Revolver.AttachedCameraID = "NULL";
}
if (input.keySinglePress(GLFW_KEY_M) && CurrentWeapon != Musket) {
scene.RemoveActor(Revolver);
scene.AddActor(Musket);
playerController.SwitchActor(Musket);
CurrentWeapon = Musket;
playerActor = Musket;
parent.SetPlayerActorID(Musket.GetID());
Musket.AttachedCameraID = "DebugCamera";
Revolver.AttachedCameraID = "NULL";
}
}
if(input.keyPressed(GLFW_KEY_1)) {
Gimbal.universalType = Gimbal.GimbalType.Move;
}
@ -244,6 +295,11 @@ public class Scene implements IScene {
if(input.keySinglePress(GLFW_KEY_F2)) {
EngineConfig.getInstance().SetRenderCollisionMesh(!EngineConfig.getInstance().RenderCollisionMeshes());
}
if(playerActor == null || CurrentWeapon == null || playerController == null) {
return;
}
playerController.GetControls().Input(input, FrameDiffNanoSeconds, CurrentWeapon, MOVEMENT_SPEED, parent, this);
if(GUI_MODE == 0 && !ActiveGUIs.contains("PerformanceOverlay")) ActiveGUIs.add("PerformanceOverlay");
else if (GUI_MODE != 0) ActiveGUIs.remove("PerformanceOverlay");

View file

@ -0,0 +1,145 @@
package net.halbear.Terrain4J.EngineCore.ServerNetworking;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public class Packet {
public static final byte PACKET_UPDATE_LOCATION = 0;
public static final byte PACKET_UPDATE_ROTATION = 1;
public static final byte PACKET_UPDATE_LINEAR_VELOCITY =2;
public static final byte PACKET_UPDATE_ANGULAR_VELOCITY =3;
public static final byte PACKET_CREATE_ACTOR = 4;
public static final byte PACKET_PING = 5;
public static final byte PACKET_MOVEMENT_UPDATE = 6;
public static final byte PACKET_ASSIGN_UUID = 7;
public static final byte PACKET_POSSESS_ACTOR = 8;
public static final byte PACKET_DESTROY_ACTOR = 9;
public static final byte PACKET_CLIENT_INPUT = 10;
public byte PacketTypeByte; //0 Location 1 Rotation 2 LinearVelocity 3 AngularVelocity 4 CombinedActorDownload 5 Ping 6 PosRotVelAngularVel 7 AssignUUID
public byte TargetType; //0 Actor
public byte[] Data;
public String TargetID;
public UUID ClientID;
public Packet(byte Type){
PacketTypeByte = Type;
TargetType = 0;
Data = new byte[0];
TargetID = "";
}
public Packet SetTargetType(byte TargetType){
this.TargetType = TargetType;
return this;
}
public Packet SetData(byte[] Data){
this.Data = Data;
return this;
}
public Packet SetID(String TargetID){
this.TargetID = TargetID;
return this;
}
public int GetByteSize(){
byte[] idBytes = TargetID.getBytes(StandardCharsets.UTF_8);
return 2 + 4 + Data.length + 4 + idBytes.length;
}
public static byte[] GetOutgoingData(Packet packet){
int ByteSize = packet.GetByteSize();
byte[] Data = new byte[ByteSize];
int Offset = 0;
Data[Offset] = packet.PacketTypeByte;
Offset++;
Data[Offset] = packet.TargetType;
Offset++;
byte[] dataLengthBytes = ByteBuffer.allocate(4).putInt(packet.Data.length).array();
for(int i = 0; i < dataLengthBytes.length; i++){
Data[Offset] = dataLengthBytes[i];
Offset++;
}
for(int i = 0; i < packet.Data.length; i++){
Data[Offset] = packet.Data[i];
Offset++;
}
byte[] IDBytes = packet.TargetID.getBytes(StandardCharsets.UTF_8);
byte[] idLengthBytes = ByteBuffer.allocate(4).putInt(IDBytes.length).array();
for(int i = 0; i < idLengthBytes.length; i++){
Data[Offset] = idLengthBytes[i];
Offset++;
}
for(int i = 0; i < IDBytes.length; i++){
Data[Offset] = IDBytes[i];
Offset++;
}
return Data;
}
public static byte[] EncodeMovementData(Vector3f Position,Quaternionf Rotation,Vector3f LinearVelocity,Vector3f AngularVelocity){
float[] floats = new float[]{Position.x,Position.y,Position.z,Rotation.x,Rotation.y,Rotation.z,Rotation.w,LinearVelocity.x,LinearVelocity.y,LinearVelocity.z,AngularVelocity.x,AngularVelocity.y,AngularVelocity.z};
byte[] Data = new byte[floats.length* VulkanUtils.FLOAT_SIZE];
int Offset = 0;
for(int i = 0; i < floats.length; i++) {
byte[] SizeBytes = ByteBuffer.allocate(4).putFloat(floats[i]).array();
for(int j = 0; j < SizeBytes.length; j++){
Data[Offset] = SizeBytes[j];
Offset++;
}
}
return Data;
}
public static Quaternionf DecodeAsQuaternation(byte[] DataIn){
Quaternionf newVector = new Quaternionf();
ByteBuffer buffer = ByteBuffer.wrap(DataIn);
newVector.set(buffer.getFloat(),buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
return newVector;
}
public static DecodedMovementPacket DecodeAsMovementUpdate(byte[] DataIn){
DecodedMovementPacket Packet = new DecodedMovementPacket();
Vector3f newVector = new Vector3f();
ByteBuffer buffer = ByteBuffer.wrap(DataIn);
newVector.set(buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
Packet.Position = new Vector3f(newVector);
Packet.Rotation = new Quaternionf(buffer.getFloat(),buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
newVector.set(buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
Packet.LinearVelocity = new Vector3f(newVector);
newVector.set(buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
Packet.AngularVelocity = new Vector3f(newVector);
return Packet;
}
public static Vector3f DecodeAsVector3f(byte[] DataIn){
Vector3f newVector = new Vector3f();
ByteBuffer buffer = ByteBuffer.wrap(DataIn);
newVector.set(buffer.getFloat(),buffer.getFloat(),buffer.getFloat());
return newVector;
}
public static String DecodeAsString(byte[] DataIn){
return new String(DataIn, StandardCharsets.UTF_8);
}
public static class DecodedMovementPacket{
public Vector3f Position;
public Vector3f LinearVelocity;
public Vector3f AngularVelocity;
public Quaternionf Rotation;
public DecodedMovementPacket(){
}
}
}

View file

@ -0,0 +1,358 @@
package net.halbear.Terrain4J.EngineCore.Threads;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
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.ServerNetworking.Packet;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.tinylog.Logger;
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ClientConnectionThread implements Runnable{
public static boolean Connected = false;
public static boolean pinging = false;
public static String ServerIP = "localhost";
public static String ServerMessage = "Offline";
public static Socket SocketToServer;
public static final Queue<Packet> OutGoingPacketQueue = new ConcurrentLinkedQueue<>();
public static final Queue<Packet> IncomingPacketQueue = new ConcurrentLinkedQueue<>();
public static DataOutputStream outToServer;
public static DataInputStream in;
public static long UUID;
public static String OwnedActorID = "NULL";
public static String PendingPossessActorID = "NULL";
private static boolean TryPossessActor(String actorID, GameCore gameCore, IScene scene){
Actor actor = Actor.Actors.get(actorID);
if(!(actor instanceof PlayerActor playerActor)) {
PendingPossessActorID = actorID;
Logger.info("Possess actor [{}] is not created yet. Deferring possession.", actorID);
return false;
}
if(!(scene instanceof Scene concreteScene)) {
PendingPossessActorID = actorID;
Logger.warn("Cannot possess actor [{}] because scene is not a Scene instance", actorID);
return false;
}
Camera debugCamera = concreteScene.GetCamera();
if(debugCamera == null) {
PendingPossessActorID = actorID;
Logger.warn("Cannot possess actor [{}] because DebugCamera is missing", actorID);
return false;
}
OwnedActorID = actorID;
PendingPossessActorID = "NULL";
playerActor.AttachCamera(debugCamera.GetID());
concreteScene.SetNetworkControlledPlayer(playerActor);
gameCore.SetPlayerActorID(actorID);
Logger.info(
"Client now controls server actor [{}], attached camera [{}]",
actorID,
debugCamera.GetID()
);
return true;
}
public static void DecodePackets(EngineInstance engineInstance, GameCore gameCore, IScene scene){
if(!IncomingPacketQueue.isEmpty()){
Packet packet;
while((packet = IncomingPacketQueue.poll()) != null){
System.out.println("Packet: " + packet.PacketTypeByte);
Actor Target = Actor.Actors.get(packet.TargetID);
Vector3f vector3f = new Vector3f();
String stringdata = "";
Quaternionf quaternionfdata = new Quaternionf();
Packet.DecodedMovementPacket MovementUpdate;
if(packet.PacketTypeByte >= 0 && packet.PacketTypeByte < 4 && packet.PacketTypeByte != 1){
vector3f = Packet.DecodeAsVector3f(packet.Data);
}
if(Target == null
&& packet.PacketTypeByte != Packet.PACKET_CREATE_ACTOR
&& packet.PacketTypeByte != Packet.PACKET_PING
&& packet.PacketTypeByte != Packet.PACKET_POSSESS_ACTOR
&& packet.PacketTypeByte != Packet.PACKET_DESTROY_ACTOR) {
continue;
}
switch (packet.PacketTypeByte) {
case 0:
Target.SetNewPosition(vector3f);
break;
case 1:
quaternionfdata = Packet.DecodeAsQuaternation(packet.Data);
Target.SetNewRotation(quaternionfdata);
break;
case 2:
Target.SetNewVelocity(vector3f);
break;
case 3:
Target.SetNewAngularVelocity(vector3f);
break;
case 4: //"ACtorType:ModelID:x:y:z:rx:ry:rz:sx:sy:sz:hx:hy:hz:MassKG:vx:vy:vz:avx:avy:avz:posOffx:posOffy:posOffz:camOffx:camOffy:camOffz"
try {
stringdata = Packet.DecodeAsString(packet.Data);
String[] Split = stringdata.split(":");
if(Split.length < 22) {
Logger.error("Create actor packet [{}] has too few fields: [{}] data=[{}]", packet.TargetID, Split.length, stringdata);
break;
}
Vector3f Position = new Vector3f(
Float.parseFloat(Split[2]),
Float.parseFloat(Split[3]),
Float.parseFloat(Split[4])
);
Quaternionf Rotation = new Quaternionf(
Float.parseFloat(Split[5]),
Float.parseFloat(Split[6]),
Float.parseFloat(Split[7]),
Float.parseFloat(Split[8])
);
Vector3f Scale = new Vector3f(
Float.parseFloat(Split[9]),
Float.parseFloat(Split[10]),
Float.parseFloat(Split[11])
);
Vector3f CollisionBox = new Vector3f(
Float.parseFloat(Split[12]),
Float.parseFloat(Split[13]),
Float.parseFloat(Split[14])
);
float MassKG = Float.parseFloat(Split[15]);
Vector3f Velocity = new Vector3f(
Float.parseFloat(Split[16]),
Float.parseFloat(Split[17]),
Float.parseFloat(Split[18])
);
Vector3f AngularVelocity = new Vector3f(
Float.parseFloat(Split[19]),
Float.parseFloat(Split[20]),
Float.parseFloat(Split[21])
);
Vector3f PositionOffset = new Vector3f();
if(Split.length >= 25) {
PositionOffset.set(
Float.parseFloat(Split[22]),
Float.parseFloat(Split[23]),
Float.parseFloat(Split[24])
);
}
Vector3f CameraOffset = new Vector3f(0, 1.0f, 0);
if(Split.length >= 28) {
CameraOffset.set(
Float.parseFloat(Split[25]),
Float.parseFloat(Split[26]),
Float.parseFloat(Split[27])
);
}
String actorType = Split[0];
String modelID = Split[1];
Logger.info("Received create actor packet: actorID=[{}], type=[{}], modelID=[{}]", packet.TargetID, actorType, modelID);
if (actorType.equals("PlayerActor")) {
Target = new PlayerActor("NULL", packet.TargetID, modelID, Position).SetCameraOffset(CameraOffset);
Target.SetPositionOffset(PositionOffset);
} else {
Target = new Actor(packet.TargetID, modelID, Position);
}
Target.SetScale(Scale);
Target.CreatePhysicsController(ConvexMesh.Box(CollisionBox.x, CollisionBox.y, CollisionBox.z), MassKG);
Target.SetServerSynced(MassKG > 0.0f || actorType.equals("PlayerActor"));
Target.SetNewRotation(Rotation);
RigidPhysicsController physicsController = (RigidPhysicsController) Target.GetPhysicsController();
RigidBody rigidBody = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if (rigidBody != null) {
rigidBody.LinearVelocity.set(Velocity);
rigidBody.AngularVelocity.set(AngularVelocity);
if(actorType.equals("PlayerActor")){
rigidBody.LockRotation();
}
}
scene.AddActor(Target);
Logger.info("Created network actor [{}] of type [{}]", packet.TargetID, actorType);
if(packet.TargetID.equals(PendingPossessActorID)) {
TryPossessActor(packet.TargetID, gameCore, scene);
}
} catch (Exception e) {
Logger.error(e, "Failed to decode create actor packet for actor [{}]", packet.TargetID);
}
break;
case 6:
MovementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
if(packet.TargetID.equals(OwnedActorID)) {
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
break;
}
Target.SetNetworkTarget(MovementUpdate.Position, MovementUpdate.Rotation);
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
break;
case 8:
Logger.info("Received possess packet for actor [{}]", packet.TargetID);
TryPossessActor(packet.TargetID, gameCore, scene);
break;
case 9:
Actor actorToDestroy = Actor.Actors.get(packet.TargetID);
if(actorToDestroy != null) {
scene.RemoveActor(actorToDestroy);
}
break;
}
}
}
}
public ClientConnectionThread(){
Connected = true;
try {
SocketToServer = new Socket(ServerIP, 25565);
SocketToServer.setSoTimeout(5);
} catch (IOException e) {
Connected = false;
//e.printStackTrace();
}
}
public static void SetServerIP(String ServerIP, Thread serverThread){
if(Connected){
Connected = false;
serverThread.interrupt();
ClientConnectionThread.ServerIP = ServerIP;
PrimaryRuntime.ServerCon = new ClientConnectionThread();
serverThread = new Thread(PrimaryRuntime.ServerCon);
serverThread.start();
}
}
public static void SendEntityUpdatePacket(Actor actor){
Packet newOutgoingPacket = new Packet((byte)6);
newOutgoingPacket.SetTargetType((byte) 0);
RigidPhysicsController physicsController = (RigidPhysicsController) actor.GetPhysicsController();
if(physicsController == null) return;
RigidBody rigidBody = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if(rigidBody == null) return;
newOutgoingPacket.SetData(Packet.EncodeMovementData(rigidBody.Position,rigidBody.Rotation,rigidBody.LinearVelocity,rigidBody.AngularVelocity));
newOutgoingPacket.SetID(actor.GetID());
OutGoingPacketQueue.add(newOutgoingPacket);
}
public static int readPacket(DataInputStream in) throws IOException {
if(in == null) return 0;
Packet newIncomingPacket = new Packet(in.readByte());
if(newIncomingPacket.PacketTypeByte == 5) {
return 5;
}
newIncomingPacket.SetTargetType(in.readByte());
int DataLength = in.readInt();
byte[] IncomingData = new byte[DataLength];
in.readFully(IncomingData);
newIncomingPacket.Data = IncomingData;
int IDLength = in.readInt();
byte[] IDData = new byte[IDLength];
in.readFully(IDData);
String ID = new String(IDData, StandardCharsets.UTF_8);
newIncomingPacket.SetID(ID);
IncomingPacketQueue.add(newIncomingPacket);
return 0;
}
public static void WritePacket(Packet outPacket, DataOutputStream Outgoing) throws IOException {
if(Outgoing == null ) return;
byte[] DataToSend = Packet.GetOutgoingData(outPacket);
Outgoing.write(DataToSend);
}
@Override
public void run() {
try {
outToServer = new DataOutputStream(SocketToServer.getOutputStream());
in = new DataInputStream(SocketToServer.getInputStream());
Connected = true;
while(Connected) {
int PacketRead = 0;
try {
PacketRead = readPacket(in);
} catch (SocketTimeoutException ignored) {
// No incoming packet this moment. Continue so outgoing packets can still flush.
}
if(PacketRead == Packet.PACKET_PING){
WritePacket(new Packet(Packet.PACKET_PING),outToServer);
}
if(PacketRead == -1) break;
if(!OutGoingPacketQueue.isEmpty()){
Packet outgoingPacket;
while((outgoingPacket = OutGoingPacketQueue.poll()) != null){
WritePacket(outgoingPacket,outToServer);
}
}
}
System.out.println("Connection closed");
Connected = false;
if(!EngineThread.running) return;
if (!pinging) {
PrimaryRuntime.StartPingTimer();
}
SocketToServer.close();
} catch (Exception e) {
//e.printStackTrace();
Connected = false;
ServerMessage = "Offline";
if(!EngineThread.running) return;
if (!pinging) {
PrimaryRuntime.StartPingTimer();
}
}
}
}

View file

@ -1,16 +1,11 @@
package net.halbear.Terrain4J.EngineCore.Threads;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import org.tinylog.Logger;
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager.ActiveControllers;
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager.PhysicsObjects;
public class PhysicsThread implements Runnable{
public class InstancedPhysicsThread implements Runnable{
public static boolean running = true;
public final Thread EngineThread;
public static float FixedTimeStep = 1f / 60f;
@ -27,12 +22,12 @@ public class PhysicsThread implements Runnable{
return EngineThread;
}
public PhysicsThread StartThread(){
public InstancedPhysicsThread StartThread(){
EngineThread.start();
return this;
}
public PhysicsThread(String ThreadName, int Index, int TotalCount){
public InstancedPhysicsThread(String ThreadName, int Index, int TotalCount){
this.ThreadName = ThreadName;
Logger.debug("Starting {} Thread",ThreadName);
EngineThread = new Thread(this);

View file

@ -16,16 +16,19 @@ public class RenderThread extends EngineThread {
private Window window;
private final InitData initData;
public static int VulkanCrashCount = 0;
public static boolean Headless = false;
public RenderThread(Window window, EngineInstance engineInstance, InitData initData, GameLogic appLogic) {
//this.window = window;
render = new Render(engineInstance);
if(!Headless)render = new Render(engineInstance);
super(engineInstance,appLogic,"Render");
this.initData = initData;
if(Headless) return;
render.Initialise(initData);
}
public void RestartCrashedRenderer(){
if(Headless) return;
if(VulkanCrashCount < EngineConfig.getInstance().GetMaxVulkanCrashes()){
RefreshRenderer();
VulkanCrashCount++;
@ -44,6 +47,7 @@ public class RenderThread extends EngineThread {
@Override
public void FrameEvent(long now, long InitialTime){
gameLogic.RenderThreadInput(PrimaryRuntime.GetEngineInstance(), (now-InitialTime));
if(Headless) return;
render.render(PrimaryRuntime.GetEngineInstance());
}
@Override
@ -52,6 +56,7 @@ public class RenderThread extends EngineThread {
}
public void RefreshRenderer(){
if(Headless) return;
Logger.debug("REFRESHING RENDERER");
render.cleanup();
render = new Render(PrimaryRuntime.GetEngineInstance());
@ -60,11 +65,12 @@ public class RenderThread extends EngineThread {
@Override
public void SecondEvent(){
EngineConfig.FrameRate_RENDERTHREAD = Frames;
EngineConfig.TPS_RENDERTHREAD = TickFrames;
if(Headless) return;
EngineConfig.LAST_AVERAGE_GPU_TIME = DeferredSceneRender.GetGPUTimeNS();
List<String[]> Profiling =GPUProfiler.GetVramUsage(render.GetVulkanContext().GetPhysicalDevice().GetPhysicalDevice());
EngineConfig.getInstance().SetMemoryProfiling(Profiling);
EngineConfig.FrameRate_RENDERTHREAD = Frames;
EngineConfig.TPS_RENDERTHREAD = TickFrames;
if(render.GetCurrentAAMode() != EngineConfig.getInstance().RenderAAType() || render.GetDeferred() != EngineConfig.getInstance().DeferredRendering()){
RefreshRenderer();
}
@ -73,9 +79,12 @@ public class RenderThread extends EngineThread {
@Override
public void cleanup() {
render.cleanup();
if(render != null)render.cleanup();
PrimaryRuntime.ThreadsOpen--;
Logger.debug("Closing Render Thread, Thread: [{}]",Thread.currentThread().toString());
if (PrimaryRuntime.ThreadsOpen <= 0 && VulkanContext.VulkanLayersOpen < 0) PrimaryRuntime.CanClose = true;
if (Headless || (PrimaryRuntime.ThreadsOpen <= 0 && VulkanContext.VulkanLayersOpen < 0)) {
PrimaryRuntime.CanClose = true;
}
}
}

View file

@ -0,0 +1,459 @@
package net.halbear.Terrain4J.EngineCore.Threads;
import net.halbear.Executable.Server;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
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.ServerNetworking.Packet;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import static net.halbear.Executable.Server.ConnectedClients;
public class ServerConnectionThread implements Runnable{
private String OwnedActorID;
private final Socket clientSocket;
private final UUID ClientID;
public final Queue<Packet> IncomingPacketQueue = new ConcurrentLinkedQueue<>();
public final Queue<Packet> OutgoingPacketQueue = new ConcurrentLinkedQueue<>();
public UUID GetClientID(){
return ClientID;
}
public String GetOwnedActorID(){
return OwnedActorID;
}
public void SetOwnedActorID(String ownedActorID){
this.OwnedActorID = ownedActorID;
}
public ServerConnectionThread(Socket clientSocket) {
UUID uuid = UUID.randomUUID();
ClientID = uuid;
this.clientSocket = clientSocket;
try {
this.clientSocket.setSoTimeout(5);
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println("Connected to client: " + clientSocket.getInetAddress().getHostName());
ConnectedClients.put(uuid, this);
}
public void SendPossessActorPacket(String actorID) {
Packet packet = new Packet((byte) 8);
packet.SetTargetType((byte) 0);
packet.SetData(new byte[0]);
packet.SetID(actorID);
AddOutgoingPacket(packet);
}
public void CollectIncomingPackets(Queue<Packet> ReferenceList){
Packet packet;
while((packet = IncomingPacketQueue.poll()) != null) {
ReferenceList.add(packet);
}
}
public void AddOutgoingPacket(Packet outgoingPacket){
OutgoingPacketQueue.add(outgoingPacket);
}
private void InitialiseJoinedClient(){
EngineInstance engineInstance = PrimaryRuntime.GetEngineInstance();
IScene scene = engineInstance.scene();
for(Actor actor : scene.GetActors()) {
Packet actorPacket = CreateActorPacket(actor);
if(actorPacket != null) {
AddOutgoingPacket(actorPacket);
}
}
GameCore gameCore = (GameCore) PrimaryRuntime.GetGameCore();
PlayerActor player = gameCore.SpawnNetworkPlayer(engineInstance, ClientID);
SetOwnedActorID(player.GetID());
Packet playerCreatePacket = CreateActorPacket(player);
if(playerCreatePacket != null) {
AddOutgoingPacket(playerCreatePacket);
System.out.println("Queued direct create packet for joining player's actor: " + player.GetID());
}
BroadcastCreateActorPacket(player);
SendPossessActorPacket(player.GetID());
System.out.println("Queued possess packet for joining player's actor: " + player.GetID());
}
@Override
public void run() {
try {
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
OutputStream toClient = clientSocket.getOutputStream();
DataOutputStream out = new DataOutputStream(toClient);
boolean Connected = true;
InitialiseJoinedClient();
while(Connected) {
int PacketRead = 0;
try {
PacketRead = readPacket(in);
} catch (SocketTimeoutException ignored) {
// No incoming packet this moment. Continue so outgoing packets can still flush.
}
if(PacketRead == Packet.PACKET_PING){
WritePacket(new Packet(Packet.PACKET_PING),out);
}
if(PacketRead == -1) break;
if(!OutgoingPacketQueue.isEmpty()){
Packet packet;
while((packet = OutgoingPacketQueue.poll()) != null) {
WritePacket(packet,out);
}
}
}
System.out.println("Connection Closing: " + Thread.currentThread() + "\n");
} catch (Exception e) {
System.out.println("Connection Closing: " + Thread.currentThread() + "\n");
//throw new RuntimeException(e);
}
}
public static void ProcessClientPacket(Packet packet){
ServerConnectionThread sender = ConnectedClients.get(packet.ClientID);
if(sender == null) return;
System.out.println("Packet: " + packet.PacketTypeByte);
Actor Target = Actor.Actors.get(packet.TargetID);
if(Target == null
&& packet.PacketTypeByte != Packet.PACKET_CREATE_ACTOR
&& packet.PacketTypeByte != Packet.PACKET_PING) {
return;
}
switch (packet.PacketTypeByte){
case Packet.PACKET_UPDATE_LOCATION:
if(!sender.OwnsActor(packet.TargetID)) return;
Target.SetNewPosition(Packet.DecodeAsVector3f(packet.Data));
break;
case Packet.PACKET_UPDATE_ROTATION:
if(!sender.OwnsActor(packet.TargetID)) return;
Target.SetNewRotation(Packet.DecodeAsQuaternation(packet.Data));
break;
case Packet.PACKET_UPDATE_LINEAR_VELOCITY:
if(!sender.OwnsActor(packet.TargetID)) return;
Target.SetNewVelocity(Packet.DecodeAsVector3f(packet.Data));
break;
case Packet.PACKET_UPDATE_ANGULAR_VELOCITY:
if(!sender.OwnsActor(packet.TargetID)) return;
Target.SetNewAngularVelocity(Packet.DecodeAsVector3f(packet.Data));
break;
case Packet.PACKET_MOVEMENT_UPDATE:
if(!sender.OwnsActor(packet.TargetID)) return;
Packet.DecodedMovementPacket movementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
Target.SetNewRotation(movementUpdate.Rotation);
Target.SetNewPosition(movementUpdate.Position);
Target.SetNewVelocity(movementUpdate.LinearVelocity);
Target.SetNewAngularVelocity(movementUpdate.AngularVelocity);
break;
case Packet.PACKET_CLIENT_INPUT:
if(!sender.OwnsActor(packet.TargetID)) return;
// Later: decode input commands here instead of trusting full transforms.
// Example future data:
// forward/back/left/right/jump/yaw/pitch/sequenceNumber
break;
}
}
public boolean OwnsActor(String actorID){
return OwnedActorID != null && OwnedActorID.equals(actorID);
}
public static void DecodePackets(EngineInstance engineInstance, GameCore gameCore, IScene scene,List<Packet> IncomingPacketQueue){
if(!IncomingPacketQueue.isEmpty()){
ListIterator<Packet> iter = IncomingPacketQueue.listIterator();
while(iter.hasNext()){
Packet packet = iter.next();
Actor Target = Actor.Actors.get(packet.TargetID);
Vector3f vector3f = new Vector3f();
String stringdata = "";
Quaternionf quaternionfdata = new Quaternionf();
Packet.DecodedMovementPacket MovementUpdate;
if(packet.PacketTypeByte >= 0 && packet.PacketTypeByte < 4 && packet.PacketTypeByte != 1){
vector3f = Packet.DecodeAsVector3f(packet.Data);
}
if(Target == null
&& packet.PacketTypeByte != Packet.PACKET_CREATE_ACTOR
&& packet.PacketTypeByte != Packet.PACKET_PING
&& packet.PacketTypeByte != Packet.PACKET_POSSESS_ACTOR) {
iter.remove();
continue;
}
switch (packet.PacketTypeByte){
case 0:
Target.SetNewPosition(vector3f);
break;
case 1:
quaternionfdata = Packet.DecodeAsQuaternation(packet.Data);
Target.SetNewRotation(quaternionfdata);
break;
case 2:
Target.SetNewVelocity(vector3f);
break;
case 3:
Target.SetNewAngularVelocity(vector3f);
break;
case 4: //"ACtorType:ModelID:x:y:z:rx:ry:rz:sx:sy:sz:hx:hy:hz:MassKG:vx:vy:vz:avx:avy:avz:posOffx:posOffy:posOffz:camOffx:camOffy:camOffz"
stringdata = Packet.DecodeAsString(packet.Data);
String[] Split = stringdata.split(":");
Vector3f Position = new Vector3f(
Float.parseFloat(Split[2]),
Float.parseFloat(Split[3]),
Float.parseFloat(Split[4])
);
Quaternionf Rotation = new Quaternionf(
Float.parseFloat(Split[5]),
Float.parseFloat(Split[6]),
Float.parseFloat(Split[7]),
Float.parseFloat(Split[8])
);
Vector3f Scale = new Vector3f(
Float.parseFloat(Split[9]),
Float.parseFloat(Split[10]),
Float.parseFloat(Split[11])
);
Vector3f CollisionBox = new Vector3f(
Float.parseFloat(Split[12]),
Float.parseFloat(Split[13]),
Float.parseFloat(Split[14])
);
float MassKG = Float.parseFloat(Split[15]);
Vector3f Velocity = new Vector3f(
Float.parseFloat(Split[16]),
Float.parseFloat(Split[17]),
Float.parseFloat(Split[18])
);
Vector3f AngularVelocity = new Vector3f(
Float.parseFloat(Split[19]),
Float.parseFloat(Split[20]),
Float.parseFloat(Split[21])
);
Vector3f PositionOffset = new Vector3f(
Float.parseFloat(Split[22]),
Float.parseFloat(Split[23]),
Float.parseFloat(Split[24])
);
Vector3f CameraOffset = new Vector3f(
Float.parseFloat(Split[25]),
Float.parseFloat(Split[26]),
Float.parseFloat(Split[27])
);
String actorType = Split[0];
String modelID = Split[1];
if(actorType.equals("PlayerActor")) {
Target = new PlayerActor("NULL", packet.TargetID, modelID, Position).SetCameraOffset(CameraOffset);
Target.SetPositionOffset(PositionOffset);
} else {
Target = new Actor(packet.TargetID, modelID, Position);
}
Target.SetNewRotation(Rotation);
Target.SetScale(Scale);
Target.CreatePhysicsController(ConvexMesh.Box(CollisionBox.x, CollisionBox.y, CollisionBox.z), MassKG);
Target.SetServerSynced(MassKG > 0.0f || actorType.equals("PlayerActor"));
Target.SetNewRotation(Rotation);
RigidPhysicsController physicsController = (RigidPhysicsController) Target.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(Velocity);
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).AngularVelocity.set(AngularVelocity);
if(actorType.equals("PlayerActor")){
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
}
scene.AddActor(Target);
break;
case 6:
if(!packet.TargetID.equals(ConnectedClients.get(packet.ClientID).OwnedActorID)) {
return;
}
MovementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
Target.SetNewRotation(MovementUpdate.Rotation);
Target.SetNewPosition(MovementUpdate.Position);
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
break;
}
iter.remove();
}
}
}
public static Packet CreateActorPacket(Actor actor){
Packet newOutgoingPacket = new Packet(Packet.PACKET_CREATE_ACTOR);
newOutgoingPacket.SetTargetType((byte) 0);
RigidPhysicsController physicsController = (RigidPhysicsController) actor.GetPhysicsController();
if(physicsController == null) return null;
RigidBody rigidBody = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if(rigidBody == null) return null;
String actorType = actor instanceof PlayerActor ? "PlayerActor" : "Actor";
StringBuilder OutgoingData = new StringBuilder(actorType)
.append(":")
.append(actor.GetModelID());
System.out.println("Creating actor packet: actorID=" + actor.GetID() + " modelID=" + actor.GetModelID() + " type=" + actorType);
Vector3f Position = rigidBody.Position;
Quaternionf Rotation = rigidBody.Rotation;
Vector3f Scale = actor.GetScale();
Vector3f ColliderBox = rigidBody.shape.hxhyhz;
float MassKG = rigidBody.MassKG;
Vector3f LinearVelocity = rigidBody.LinearVelocity;
Vector3f AngularVelocity = rigidBody.AngularVelocity;
Vector3f PositionOffset = actor.GetPositionOffset();
Vector3f CameraOffset = new Vector3f();
if(actor instanceof PlayerActor playerActor) {
CameraOffset.set(playerActor.CameraOffset);
}
float[] floats = new float[]{
Position.x, Position.y, Position.z,
Rotation.x, Rotation.y, Rotation.z, Rotation.w,
Scale.x, Scale.y, Scale.z,
ColliderBox.x, ColliderBox.y, ColliderBox.z,
MassKG,
LinearVelocity.x, LinearVelocity.y, LinearVelocity.z,
AngularVelocity.x, AngularVelocity.y, AngularVelocity.z,
PositionOffset.x, PositionOffset.y, PositionOffset.z,
CameraOffset.x, CameraOffset.y, CameraOffset.z
};
for(int i = 0; i < floats.length; i++){
OutgoingData.append(":").append(floats[i]);
}
newOutgoingPacket.SetData(OutgoingData.toString().getBytes(StandardCharsets.UTF_8));
newOutgoingPacket.SetID(actor.GetID());
return newOutgoingPacket;
}
public static void BroadcastCreateActorPacket(Actor actor) {
Packet newOutgoingPacket = CreateActorPacket(actor);
if(newOutgoingPacket != null)Server.OutGoingPacketQueue.add(newOutgoingPacket);
}
public static Packet CreateDestroyActorPacket(String actorID){
Packet packet = new Packet(Packet.PACKET_DESTROY_ACTOR);
packet.SetTargetType((byte) 0);
packet.SetData(new byte[0]);
packet.SetID(actorID);
return packet;
}
public static void BroadcastDestroyActorPacket(String actorID){
Server.OutGoingPacketQueue.add(CreateDestroyActorPacket(actorID));
}
public void DestroyOwnedActor(){
if(OwnedActorID == null) return;
Actor actor = Actor.Actors.get(OwnedActorID);
if(actor != null){
PrimaryRuntime.GetEngineInstance().scene().RemoveActor(actor);
BroadcastDestroyActorPacket(OwnedActorID);
}
OwnedActorID = null;
}
public static void SendEntityUpdatePacket(Actor actor){
Packet newOutgoingPacket = new Packet((byte)6);
newOutgoingPacket.SetTargetType((byte) 0);
RigidPhysicsController physicsController = (RigidPhysicsController) actor.GetPhysicsController();
if(physicsController == null) return;
RigidBody rigidBody = RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID);
if(rigidBody == null) return;
newOutgoingPacket.SetData(Packet.EncodeMovementData(rigidBody.Position,rigidBody.Rotation,rigidBody.LinearVelocity,rigidBody.AngularVelocity));
newOutgoingPacket.SetID(actor.GetID());
Server.OutGoingPacketQueue.add(newOutgoingPacket);
}
public int readPacket(DataInputStream in) throws IOException {
if(in == null) return 0;
Packet newIncomingPacket = new Packet(in.readByte());
if(newIncomingPacket.PacketTypeByte == 5) {
return 5;
}
newIncomingPacket.SetTargetType(in.readByte());
int DataLength = in.readInt();
byte[] IncomingData = new byte[DataLength];
in.readFully(IncomingData);
newIncomingPacket.Data = IncomingData;
int IDLength = in.readInt();
byte[] IDData = new byte[IDLength];
in.readFully(IDData);
String ID = new String(IDData, StandardCharsets.UTF_8);
newIncomingPacket.SetID(ID);
newIncomingPacket.ClientID = ClientID;
IncomingPacketQueue.add(newIncomingPacket);
return 0;
}
public static void WritePacket(Packet outPacket, DataOutputStream Outgoing) throws IOException {
if(Outgoing == null ) return;
byte[] DataToSend = Packet.GetOutgoingData(outPacket);
Outgoing.write(DataToSend);
}
}

View file

@ -1,5 +1,4 @@
writer = file
writer.file = LastSession.t4jlog
writer.format = {date: DD:MM:YYYY} {date: HH:mm:ss.SSS} {level}: {message}
writer.level = trace
writingthread = true