This commit is contained in:
Halbear 2026-07-11 15:27:06 +01:00
parent 0d8f23cb1f
commit bf11da6799
10 changed files with 343 additions and 163 deletions

View file

@ -150,7 +150,7 @@ public class WorldPhysicsManager {
}
private static Actor GetActorForRigidBody(RigidBody body) {
public static Actor GetActorForRigidBody(RigidBody body) {
for (Actor actor : Actor.Actors.values()) {
if (!(actor.GetPhysicsController() instanceof RigidPhysicsController rigidPhysicsController)) {
continue;

View file

@ -106,9 +106,9 @@ public class GameCore implements GameLogic {
List<MaterialData> RevolverMat = ModelLoader.LoadMaterials("resources/models/Revolver/Revolver_mat.json");
FlintlockData = ModelLoader.LoadModel("resources/models/Flintlock/Flintlock.json");
List<MaterialData> FlintlockMat = ModelLoader.LoadMaterials("resources/models/Flintlock/Flintlock_mat.json");
Item MusketItem = new Item(MusketData.ID(), 1.0f, 1, 10.0f);
Item RevolverItem = new Item(RevolverData.ID(), 4.0f, 6, 10.0f);
Item FlintLock = new Item(FlintlockData.ID(), 1.0f, 2, 10.0f);
Item MusketItem = new Item(MusketData.ID(), 1.0f, 1, 100.0f);
Item RevolverItem = new Item(RevolverData.ID(), 4.0f, 6, 100.0f);
Item FlintLock = new Item(FlintlockData.ID(), 1.0f, 2, 100.0f);
scene.MusketItem = MusketItem;
scene.RevolverItem = RevolverItem;
scene.FlintLockItem = FlintLock;

View file

@ -314,8 +314,8 @@ public class Scene implements IScene {
float FireRate = 1000f/CurrentItem.FireRate();
if (NewTime - LastGunFire > 1_000_000f * FireRate ){
LastGunFire = NewTime;
ClientConnectionThread.FireWeapon(playerActor.ID, CurrentItem.Damage());
MusketFireSFX.Play();
ClientConnectionThread.FireWeapon(playerActor.PositionOffset, CurrentItem.Damage(), 100, camera, playerActor.ID);
// MusketFireSFX.Play();
}
}
}

View file

@ -0,0 +1,62 @@
package net.halbear.Terrain4J.EngineCore.Main.Util.Maths;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import org.joml.Quaternionf;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.primitives.AABBf;
import org.joml.primitives.Intersectionf;
public class T4Raycast {
public static class Hit {
public final RigidBody Body;
public final Vector3f Point;
public final float Distance;
public Hit(RigidBody body, Vector3f point, float distance){
Body = body;
Point = point;
Distance = distance;
}
}
public static Hit Nearest(Vector3f origin, Vector3f direction, float maxRange, String excludeRigidBodyID){
Vector3f dir = new Vector3f(direction).normalize();
Vector3f scaledDir = new Vector3f(dir).mul(maxRange);
RigidBody bestBody = null;
float bestT = 1f;
for (String id : RigidBody.RigidBodies) {
if (excludeRigidBodyID != null && id.equals(excludeRigidBodyID)) continue;
RigidBody body = RigidBody.RigidBodyRegister.get(id);
if (body == null) continue;
AABBf worldBounds = body.shape.GetWorldAABB();
Vector2f coarse = new Vector2f();
boolean coarseHit = Intersectionf.intersectRayAab(origin, scaledDir,
new Vector3f(worldBounds.minX, worldBounds.minY, worldBounds.minZ),
new Vector3f(worldBounds.maxX, worldBounds.maxY, worldBounds.maxZ),
coarse);
if (!coarseHit || coarse.x > bestT) continue;
Vector3f localOrigin = new Vector3f(origin).sub(body.Position);
Vector3f localDir = new Vector3f(scaledDir);
Quaternionf inverseOrientation = body.shape.Orientation.conjugate(new Quaternionf());
inverseOrientation.transform(localOrigin);
inverseOrientation.transform(localDir);
Vector2f localT = new Vector2f();
boolean hit = Intersectionf.intersectRayAab(localOrigin, localDir, body.shape.BottomLeftBack, body.shape.TopRightForward, localT);
if (!hit || localT.x < 0f || localT.x > 1f) continue;
if (localT.x < bestT) {
bestT = localT.x;
bestBody = body;
}
}
if (bestBody == null) return null;
Vector3f hitPoint = new Vector3f(origin).add(new Vector3f(scaledDir).mul(bestT));
return new Hit(bestBody, hitPoint, bestT * maxRange);
}
}

View file

@ -25,6 +25,7 @@ public class Packet {
public static final byte PACKET_FIRE_WEAPON = 12;
public static final byte PACKET_SEND_PLAYER_COUNT = 13;
public static final byte PACKET_UPDATE_PLAYER_DISPLAY_NAME = 14;
public static final byte PACKET_FIRE_RESULT = 15;
public byte PacketTypeByte;
public byte TargetType; //0 Actor
@ -106,6 +107,59 @@ public class Packet {
return Data;
}
public static byte[] EncodeFireRequest(Vector3f origin, Vector3f direction, float damage, float maxRange){
return EncodeFloats(new float[]{origin.x,origin.y,origin.z,direction.x,direction.y,direction.z,damage,maxRange});
}
public static DecodedFireRequest DecodeAsFireRequest(byte[] DataIn){
ByteBuffer buffer = ByteBuffer.wrap(DataIn);
DecodedFireRequest request = new DecodedFireRequest();
request.Origin = new Vector3f(buffer.getFloat(), buffer.getFloat(), buffer.getFloat());
request.Direction = new Vector3f(buffer.getFloat(), buffer.getFloat(), buffer.getFloat());
request.Damage = buffer.getFloat();
request.MaxRange = buffer.getFloat();
return request;
}
public static byte[] EncodeFireResult(Vector3f origin, Vector3f hitPoint, boolean hit){
return EncodeFloats(new float[]{origin.x,origin.y,origin.z,hitPoint.x,hitPoint.y,hitPoint.z, hit ? 1f : 0f});
}
public static DecodedFireResult DecodeAsFireResult(byte[] DataIn){
ByteBuffer buffer = ByteBuffer.wrap(DataIn);
DecodedFireResult result = new DecodedFireResult();
result.Origin = new Vector3f(buffer.getFloat(), buffer.getFloat(), buffer.getFloat());
result.HitPoint = new Vector3f(buffer.getFloat(), buffer.getFloat(), buffer.getFloat());
result.Hit = buffer.getFloat() > 0.5f;
return result;
}
public static class DecodedFireRequest {
public Vector3f Origin;
public Vector3f Direction;
public float Damage;
public float MaxRange;
}
public static class DecodedFireResult {
public Vector3f Origin;
public Vector3f HitPoint;
public boolean Hit;
}
private static byte[] EncodeFloats(float[] floats){
byte[] Data = new byte[floats.length * VulkanUtils.FLOAT_SIZE];
int Offset = 0;
for(float value : floats){
byte[] bytes = ByteBuffer.allocate(4).putFloat(value).array();
for(byte b : bytes){
Data[Offset] = b;
Offset++;
}
}
return Data;
}
public static Quaternionf DecodeAsQuaternation(byte[] DataIn){
Quaternionf newVector = new Quaternionf();
ByteBuffer buffer = ByteBuffer.wrap(DataIn);

View file

@ -1,10 +1,12 @@
package net.halbear.Terrain4J.EngineCore.Threads;
import net.halbear.Executable.Server;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
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.AudioInstance;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.*;
@ -254,6 +256,19 @@ public class ClientConnectionThread implements Runnable{
System.out.println("decoding UUID packet");
clientUUID = Packet.DecodeAsString(packet.Data);
break;
case Packet.PACKET_FIRE_RESULT:
System.out.println("Fire Packet Recieved" );
Packet.DecodedFireResult fireResult = Packet.DecodeAsFireResult(packet.Data);
AudioInstance FireInstance = new AudioInstance("resources/EngineResources/audio/sounds/MusketFire.ogg","GunFireInstance" + packet.TargetID, engineInstance.audioManager(),fireResult.Origin.x, fireResult.Origin.y, fireResult.Origin.z, false);
FireInstance.SetAudioType(AudioInstance.AudioType.WEAPONS);
FireInstance.SetVolume(EngineConfig.getInstance().WeaponVolume);
FireInstance.Play();
double Rnd = Math.random();
AudioInstance HitInstance = new AudioInstance(Rnd < 0.5 ? "resources/EngineResources/audio/sounds/BulletHit1.ogg" : "resources/EngineResources/audio/sounds/BulletHit2.ogg","GunHitInstance" + packet.TargetID, engineInstance.audioManager(),fireResult.HitPoint.x, fireResult.HitPoint.y, fireResult.HitPoint.z, false);
HitInstance.SetAudioType(AudioInstance.AudioType.WEAPONS);
HitInstance.SetVolume(EngineConfig.getInstance().WeaponVolume * 10f);
HitInstance.Play();
break;
}
}
}
@ -354,6 +369,20 @@ public class ClientConnectionThread implements Runnable{
Outgoing.write(DataToSend);
}
public static void FireWeapon(Vector3f barrelLocalOffset, float damage, float maxRange, Camera camera, String ShooterID){
Vector3f camRotation = camera.GetRotation();
Quaternionf aimRotation = new Quaternionf().rotateYXZ(-camRotation.y, -camRotation.x, camRotation.z);
Vector3f direction = aimRotation.transform(new Vector3f(0, 0, -1));
Vector3f origin = new Vector3f(camera.GetPosition());
/// .add(aimRotation.transform(new Vector3f(barrelLocalOffset), new Vector3f()));
System.out.println("Fire Packet being sent" );
Packet packet = new Packet(Packet.PACKET_FIRE_WEAPON);
packet.SetID(ShooterID);
packet.SetData(Packet.EncodeFireRequest(origin, direction, damage, maxRange));
ClientConnectionThread.OutGoingPacketQueue.add(packet);
}
@Override
public void run() {
try {

View file

@ -10,6 +10,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.Main.Util.Maths.T4Raycast;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.Packet;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@ -22,6 +23,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import static net.halbear.Executable.Server.ConnectedClients;
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager.GetActorForRigidBody;
public class ServerConnectionThread implements Runnable{
private String OwnedActorID;
@ -217,9 +219,42 @@ public class ServerConnectionThread implements Runnable{
return;
}
break;
case Packet.PACKET_FIRE_WEAPON:
HandleFireWeapon(packet);
break;
}
}
private static void HandleFireWeapon(Packet packet){
Packet.DecodedFireRequest request = Packet.DecodeAsFireRequest(packet.Data);
Actor shooter = Actor.Actors.get(packet.TargetID);
String excludeBodyID = null;
if (shooter != null && shooter.GetPhysicsController() instanceof RigidPhysicsController rpc) {
excludeBodyID = rpc.RigidBodyID;
}
T4Raycast.Hit hit = T4Raycast.Nearest(request.Origin, request.Direction, request.MaxRange, excludeBodyID);
boolean didHit = hit != null;
String hitActorID = "";
Vector3f resultPoint;
if (didHit) {
resultPoint = hit.Point;
Vector3f impulse = new Vector3f(request.Direction).normalize().mul(request.Damage);
hit.Body.ApplyImpulse(impulse, hit.Point);
Actor hitActor = GetActorForRigidBody(hit.Body);
if (hitActor != null) hitActorID = hitActor.GetID();
} else {
resultPoint = new Vector3f(request.Direction).normalize().mul(request.MaxRange).add(request.Origin);
}
Packet result = new Packet(Packet.PACKET_FIRE_RESULT);
result.SetID(hitActorID);
result.SetData(Packet.EncodeFireResult(request.Origin, resultPoint, didHit));
Server.OutGoingPacketQueue.add(result);
}
public boolean OwnsActor(String actorID){
return OwnedActorID != null && OwnedActorID.equals(actorID);
}