input handling with server synchronisation

This commit is contained in:
Halbear
2026-05-27 19:19:24 +01:00
parent 7e1e95342a
commit 56f89a79e2
11 changed files with 329 additions and 16 deletions
@@ -1,14 +1,14 @@
package net.halbear.hvf.Entity;
import net.halbear.hvf.Entity.Renderer.VehicleAnimationManager;
import net.halbear.hvf.Registry.Input.InputManager;
import net.halbear.hvf.Util.VehicleData.EngineCategories;
import net.halbear.hvf.Util.VehicleData.VehicleBuildInfo;
import net.halbear.hvf.Util.VehicleData.VehicleClassification;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.MoverType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.IPacket;
import net.minecraft.network.datasync.DataParameter;
@@ -16,20 +16,17 @@ import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class VehicleBaseEntity extends Entity {
public static final DataParameter<CompoundNBT> VEHICLE_SYNCHED_PARAMETERS = EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.COMPOUND_NBT);
private static final VehicleAnimationManager<VehicleBaseEntity> ANIMATION_MANAGER = new VehicleAnimationManager<>();
private Map<String, byte[]> BASE_BYTE_ARRAY_PARAMETERS = new HashMap<>();
private Map<String, Double> BASE_DOUBLE_PARAMETERS = new HashMap<>();
private Map<String, Float> BASE_FLOAT_PARAMETERS = new HashMap<>();
private Map<String, Integer> BASE_INT_PARAMETERS = new HashMap<>();
@@ -79,6 +76,15 @@ public class VehicleBaseEntity extends Entity {
BASE_INT_PARAMETERS.put("YAW_CONTROL_INPUT",0);
BASE_INT_PARAMETERS.put("ROLL_CONTROL_INPUT",0);
BASE_INT_PARAMETERS.put("PITCH_CONTROL_INPUT",0);
List<String> VehicleKeybindActions = vehicleBuildInfo.GetVehicleInputActions();
byte[] VehicleByteActions = new byte[VehicleKeybindActions.size()];
final int[] index = {0};
VehicleKeybindActions.forEach(action->{
VehicleByteActions[index[0]] = (InputManager.INPUT_BYTE_VALUES.get(action));
index[0]++;
});
BASE_BYTE_ARRAY_PARAMETERS.put("INPUT_DATA",new byte[0]);
BASE_BYTE_ARRAY_PARAMETERS.put("POTENTIAL_INPUTS",VehicleByteActions);
switch (vehicleClassification){
case Aeroplane:
BASE_INT_PARAMETERS.put("ENGINE_COUNT",(Integer) vehicleBuildInfo.GetEngineCount());
@@ -99,6 +105,7 @@ public class VehicleBaseEntity extends Entity {
BASE_INT_PARAMETERS.forEach(SyncedData::putInt);
BASE_STRING_PARAMETERS.forEach(SyncedData::putString);
BASE_BOOL_PARAMETERS.forEach(SyncedData::putBoolean);
BASE_BYTE_ARRAY_PARAMETERS.forEach(SyncedData::putByteArray);
this.dataManager.set(VEHICLE_SYNCHED_PARAMETERS,SyncedData);
}
public void SetRenderState(String NewState){
@@ -147,6 +154,14 @@ public class VehicleBaseEntity extends Entity {
public Boolean GetBooleanDataValue(String ValueName){
return this.dataManager.get(VEHICLE_SYNCHED_PARAMETERS).getBoolean(ValueName);
}
public void SetByteArrayValue(String ValueName, byte[] Value){
CompoundNBT SyncedData = this.dataManager.get(VEHICLE_SYNCHED_PARAMETERS).copy();
SyncedData.putByteArray(ValueName,Value);
this.dataManager.set(VEHICLE_SYNCHED_PARAMETERS,SyncedData);
}
public byte[] GetByteArrayValue(String ValueName){
return this.dataManager.get(VEHICLE_SYNCHED_PARAMETERS).getByteArray(ValueName);
}
public void SetVehicleRoll(float value){
SetFloatDataValue("ORIENTATION_ROLL",value);
}
@@ -164,6 +179,14 @@ public class VehicleBaseEntity extends Entity {
SetVehiclePitch(Pitch);
}
public UUID GetPilot(){
if(this.isBeingRidden() && this.getPassengers().get(0) instanceof ServerPlayerEntity){
ServerPlayerEntity player = (ServerPlayerEntity) this.getPassengers().get(0);
return player.getUniqueID();
}
return null;
}
public void OnPunchedEvent(){
}
@@ -1,6 +1,7 @@
package net.halbear.hvf;
import net.halbear.hvf.Registry.ModEntities;
import net.halbear.hvf.Util.ServerSynchronisation.InputArrayNetworking;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraftforge.common.MinecraftForge;
@@ -35,9 +36,11 @@ public class Halsvehicleframework {
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
//register the mod elements on the mod event bus (loads them)
InputArrayNetworking.Register();
ModEntities.ENTITY_TYPES.register(bus);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void setup(final FMLCommonSetupEvent event) {
@@ -3,17 +3,16 @@ package net.halbear.hvf.Registry.EventHandlers;
import net.halbear.hvf.UsageExamples.Aeroplane.Renderer.AeroplaneRenderer;
import net.halbear.hvf.UsageExamples.Airboat.Renderer.AirboatRenderer;
import net.halbear.hvf.Halsvehicleframework;
import net.halbear.hvf.Registry.ModEntities;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.halbear.hvf.Registry.*;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import static net.halbear.hvf.Registry.Input.ModKeybinds.*;
@Mod.EventBusSubscriber(modid = Halsvehicleframework.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class ClientEventHandler {
@@ -22,5 +21,17 @@ public class ClientEventHandler {
public static void init(final FMLClientSetupEvent event) {
RenderingRegistry.registerEntityRenderingHandler(ModEntities.AEROPLANE.get(), AeroplaneRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(ModEntities.AIRBOAT.get(), AirboatRenderer::new);
ClientRegistry.registerKeyBinding(FORWARD_KEY);
ClientRegistry.registerKeyBinding(BACKWARD_KEY);
ClientRegistry.registerKeyBinding(STRAFE_LEFT_KEY);
ClientRegistry.registerKeyBinding(STRAFE_RIGHT_KEY);
ClientRegistry.registerKeyBinding(ACCELERATE_KEY);
ClientRegistry.registerKeyBinding(BRAKE_KEY);
ClientRegistry.registerKeyBinding(TURN_LEFT_KEY);
ClientRegistry.registerKeyBinding(TURN_RIGHT_KEY);
ClientRegistry.registerKeyBinding(CLUTCH_KEY);
ClientRegistry.registerKeyBinding(GEAR_UP_KEY);
ClientRegistry.registerKeyBinding(GEAR_DOWN_KEY);
}
}
@@ -2,15 +2,41 @@ package net.halbear.hvf.Registry.EventHandlers;
import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.halbear.hvf.Halsvehicleframework;
import net.halbear.hvf.Registry.Input.InputManager;
import net.halbear.hvf.Util.ServerSynchronisation.InputArrayNetworking;
import net.halbear.hvf.Util.ServerSynchronisation.InputArrayPacket;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.Arrays;
@Mod.EventBusSubscriber(modid = Halsvehicleframework.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class ModEventHandler {
@SubscribeEvent
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
if (event.phase == TickEvent.Phase.END && event.player.world.isRemote()) {
PlayerEntity player = event.player;
if(player.isPassenger() && player.getRidingEntity() instanceof VehicleBaseEntity){
VehicleBaseEntity vehicle = (VehicleBaseEntity) player.getRidingEntity();
byte[] bytesFromBytes = new byte[InputManager.ActiveKeys.size()];
for(int i = 0; i < InputManager.ActiveKeys.size(); i++){
bytesFromBytes[i] = InputManager.ActiveKeys.get(i);
}
if(!Arrays.equals(bytesFromBytes, vehicle.GetByteArrayValue("INPUT_DATA"))) {
InputArrayNetworking.INSTANCE.sendToServer(new InputArrayPacket(bytesFromBytes));
}
if(!InputManager.ActiveKeys.equals(InputManager.LastActiveKeys)){
InputManager.SetLastActiveKeys();
}
}
}
}
@SubscribeEvent
public static void onEntityPunch(AttackEntityEvent event) {
PlayerEntity player = event.getPlayer();
@@ -0,0 +1,24 @@
package net.halbear.hvf.Registry.Input;
import net.halbear.hvf.Halsvehicleframework;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.ArrayList;
import java.util.List;
@Mod.EventBusSubscriber(modid = Halsvehicleframework.MOD_ID, value = Dist.CLIENT)
public class InputHandler {
@SubscribeEvent
public static void onKeyInput(InputEvent.KeyInputEvent event) {
List<Byte> PressedKeys = new ArrayList<>();
InputManager.KEY_BINDING_MAP.forEach((Binding, Name)->{
if(Binding.isKeyDown()){
PressedKeys.add(InputManager.INPUT_BYTE_VALUES.get(Name));
}
});
InputManager.SetActiveKeys(PressedKeys);
}
}
@@ -0,0 +1,59 @@
package net.halbear.hvf.Registry.Input;
import net.minecraft.client.settings.KeyBinding;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
public class InputManager {
public static final Map<String, Byte> INPUT_BYTE_VALUES = new HashMap<>();
public static final Map<Byte, String> INPUT_BYTE_VALUES_REVERSE_LOOKUP = new HashMap<>();
public static final Map<KeyBinding, String> KEY_BINDING_MAP = new HashMap<>();
public static List<Byte> ActiveKeys = new ArrayList<>();
public static List<Byte> LastActiveKeys = new ArrayList<>();
public static void AddActiveKey(Byte Key){ActiveKeys.add(Key);}
public static List<Byte>GetActiveKeys(){return ActiveKeys;}
public static void SetActiveKeys(List<Byte> NewList){
ActiveKeys.clear();
ActiveKeys = NewList;
}
public static void SetLastActiveKeys(){
LastActiveKeys.clear();
LastActiveKeys = ActiveKeys;
}
public static void AddBinding(KeyBinding keyBinding, String BindingName){
KEY_BINDING_MAP.put(keyBinding,BindingName);
}
public static void ReCalculateByteArrays(){
INPUT_BYTE_VALUES.clear();
INPUT_BYTE_VALUES_REVERSE_LOOKUP.clear();
AtomicReference<Byte> Iterator = new AtomicReference<>((byte) -128);
KEY_BINDING_MAP.forEach((Binding, Name )->{
INPUT_BYTE_VALUES.put(Name, Iterator.get());
INPUT_BYTE_VALUES_REVERSE_LOOKUP.put(Iterator.get(), Name);
Iterator.getAndSet((byte) (Iterator.get() + 1));
});
}
static{
KEY_BINDING_MAP.put(ModKeybinds.FORWARD_KEY, "Forward");
KEY_BINDING_MAP.put(ModKeybinds.BACKWARD_KEY, "Backward");
KEY_BINDING_MAP.put(ModKeybinds.STRAFE_LEFT_KEY, "StrafeLeft");
KEY_BINDING_MAP.put(ModKeybinds.STRAFE_RIGHT_KEY, "StrafeRight");
KEY_BINDING_MAP.put(ModKeybinds.ACCELERATE_KEY, "Accelerate");
KEY_BINDING_MAP.put(ModKeybinds.BRAKE_KEY, "Brake");
KEY_BINDING_MAP.put(ModKeybinds.TURN_LEFT_KEY, "TurnLeft");
KEY_BINDING_MAP.put(ModKeybinds.TURN_RIGHT_KEY, "TurnRight");
KEY_BINDING_MAP.put(ModKeybinds.CLUTCH_KEY, "ClutchToggle");
KEY_BINDING_MAP.put(ModKeybinds.GEAR_UP_KEY, "GearShiftUp");
KEY_BINDING_MAP.put(ModKeybinds.GEAR_DOWN_KEY, "GearShiftDown");
ReCalculateByteArrays();
}
}
@@ -1,12 +1,92 @@
package net.halbear.hvf.Registry.Input;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.util.InputMappings;
import net.minecraftforge.client.settings.IKeyConflictContext;
import net.minecraftforge.client.settings.KeyConflictContext;
import net.minecraftforge.client.settings.KeyModifier;
import net.minecraftforge.common.util.Lazy;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import org.lwjgl.glfw.GLFW;
import java.util.ArrayList;
import java.util.List;
public class ModKeybinds {
public static Lazy<KeyBinding> W_KEY_INPUT = Lazy.of(()->{
return null;
});
//General controls for vehicles that exist outside of the types supported by the mod
public static KeyBinding FORWARD_KEY = new KeyBinding(
"key.hals_vehicle_framework.forward",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_W,
"key.categories.general_vehicle_controls"
);
public static KeyBinding BACKWARD_KEY = new KeyBinding(
"key.hals_vehicle_framework.backward",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_S,
"key.categories.general_vehicle_controls"
);
public static KeyBinding STRAFE_LEFT_KEY = new KeyBinding(
"key.hals_vehicle_framework.strafe_left",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_A,
"key.categories.general_vehicle_controls"
);
public static KeyBinding STRAFE_RIGHT_KEY = new KeyBinding(
"key.hals_vehicle_framework.strafe_right",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_D,
"key.categories.general_vehicle_controls"
);
//Wheeled Land Vehicles (Cars)
public static KeyBinding ACCELERATE_KEY = new KeyBinding(
"key.hals_vehicle_framework.accelerate",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_W,
"key.categories.land_vehicle_controls"
);
public static KeyBinding BRAKE_KEY = new KeyBinding(
"key.hals_vehicle_framework.brake",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_S,
"key.categories.land_vehicle_controls"
);
public static KeyBinding TURN_LEFT_KEY = new KeyBinding(
"key.hals_vehicle_framework.turn_left",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_A,
"key.categories.land_vehicle_controls"
);
public static KeyBinding TURN_RIGHT_KEY = new KeyBinding(
"key.hals_vehicle_framework.turn_right",
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_D,
"key.categories.land_vehicle_controls"
);
public static KeyBinding CLUTCH_KEY = new KeyBinding(
"key.hals_vehicle_framework.clutch",
KeyConflictContext.IN_GAME,
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_LEFT_CONTROL,
"key.categories.land_vehicle_controls"
);
public static KeyBinding GEAR_UP_KEY = new KeyBinding(
"key.hals_vehicle_framework.gear_up",
KeyConflictContext.IN_GAME,
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_UP,
"key.categories.land_vehicle_controls"
);
public static KeyBinding GEAR_DOWN_KEY = new KeyBinding(
"key.hals_vehicle_framework.gear_down",
KeyConflictContext.IN_GAME,
InputMappings.Type.KEYSYM,
GLFW.GLFW_KEY_DOWN,
"key.categories.land_vehicle_controls"
);
}
@@ -20,7 +20,8 @@ public class Aeroplane extends VehicleBaseEntity {
.SetWingSpan(2)
.SetMaxSpeedMS(70)
.SetCentreOfMass(new Vector3d(0,0,2))
.SetPilotSeat(new Vector3d(0.0D, -1D, 0.0D));
.SetPilotSeat(new Vector3d(0.0D, -1D, 0.0D))
.AddPassengerSeat(new Vector3d(0.0D, -1D, 1.0D));
public Aeroplane(EntityType<?> Type, World WorldIn) {
super(Type, WorldIn, buildInfo);
@@ -0,0 +1,26 @@
package net.halbear.hvf.Util.ServerSynchronisation;
import net.halbear.hvf.Halsvehicleframework;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;
public class InputArrayNetworking {
private static final String PROTOCOL = "1";
public static SimpleChannel INSTANCE;
private static int PacketID = 0;
public static void Register(){
INSTANCE = NetworkRegistry.newSimpleChannel(
new ResourceLocation(Halsvehicleframework.MOD_ID, "vehicle_input_channel"),
()-> PROTOCOL,
PROTOCOL :: equals,
PROTOCOL :: equals
);
INSTANCE.registerMessage(PacketID++,
InputArrayPacket.class,
InputArrayPacket::Encode,
InputArrayPacket::decode,
InputArrayPacket::ServerHandle);
}
}
@@ -0,0 +1,53 @@
package net.halbear.hvf.Util.ServerSynchronisation;
import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.fml.network.NetworkEvent;
import java.util.function.Supplier;
public class InputArrayPacket {
private final byte[] byteArray;
public InputArrayPacket(byte[] arrayIn){
byteArray = arrayIn;
}
public static void Encode(InputArrayPacket packet, PacketBuffer packetBuffer){
packetBuffer.writeByteArray(packet.byteArray);
}
public static InputArrayPacket decode(PacketBuffer packetBuffer){
return new InputArrayPacket(packetBuffer.readByteArray());
}
public static void ServerHandle(InputArrayPacket packet, Supplier<NetworkEvent.Context> ContextSupplier){
NetworkEvent.Context Context = ContextSupplier.get();
Context.enqueueWork(()->{
ServerPlayerEntity player = Context.getSender();
if (player != null) {
String Message = "";
Entity playerEntity = player.getEntity();
if(playerEntity.isPassenger()){
Entity PotentialVehicle = playerEntity.getRidingEntity();
Message += " Entity: " + PotentialVehicle.getName().getString();
if(PotentialVehicle instanceof VehicleBaseEntity){
Message += " Is a HVF vehicle!";
VehicleBaseEntity Vehicle = (VehicleBaseEntity)PotentialVehicle;
if(Vehicle.GetPilot() == player.getUniqueID()) {
Vehicle.SetByteArrayValue("INPUT_DATA", packet.byteArray);
Message += " Packet Sent By Pilot - SUCCESS";
} else{
Message += " Packet Sent By Passenger - REJECTED";
}
}
}
player.sendMessage(new StringTextComponent(Message),player.getUniqueID());
}
});
Context.setPacketHandled(true);
}
}
@@ -20,9 +20,15 @@ public class VehicleBuildInfo {
private double Gravity = 4.9f;
private boolean AdheresToGravity = true;
private Vector3d PilotSeat;
private List<String> BuiltInVehicleInputActions = new ArrayList<>();
private List<Vector3d> PassengerSeats = new ArrayList<>();
private List<Float> FuelTanks = new ArrayList<>();
public VehicleBuildInfo RegisterInputAction(String ActionName){
BuiltInVehicleInputActions.add(ActionName);
return this;
}
public VehicleBuildInfo AddPassengerSeat(Vector3d SeatIn){
PassengerSeats.add(SeatIn);
return this;
@@ -100,6 +106,7 @@ public class VehicleBuildInfo {
public double GetGravityStrength(){return Gravity;}
public Vector3d GetPilotSeat(){return PilotSeat;}
public List<Vector3d> GetPassengerSeats(){return PassengerSeats;}
public List<String> GetVehicleInputActions(){return BuiltInVehicleInputActions;}
public List<Float> GetFuelTanks(){return FuelTanks;}
public FuelType GetFuelType(){return this.FuelType;}
public float GetMaxSpeedMS(){return MaxSpeedMS;}