diff --git a/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavBeacon.java b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavBeacon.java index 473553678..e1dfe73ff 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavBeacon.java +++ b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavBeacon.java @@ -87,6 +87,11 @@ public double getBearingDelta(AEntityB_Existing entity) { return delta; } + public double getGlideSlopeDelta(AEntityB_Existing entity) { + double delta = glideSlope - Math.toDegrees(Math.asin((entity.position.y - position.y) / entity.position.distanceTo(position))); + return delta; + } + public IWrapperNBT save(IWrapperNBT data) { data.setString("name", name); data.setDouble("glideSlope", glideSlope); diff --git a/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypoint.java b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypoint.java new file mode 100644 index 000000000..8297ffdfb --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypoint.java @@ -0,0 +1,214 @@ +package minecrafttransportsimulator.baseclasses; +import java.util.*; + +import minecrafttransportsimulator.entities.components.AEntityB_Existing; +import minecrafttransportsimulator.entities.components.AEntityD_Definable; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.IWrapperNBT; +import minecrafttransportsimulator.mcinterface.InterfaceManager; + +/** + * waypoint class + */ + +//structure:{waypoints:{index:value,name:value,targetSpeed:value,bearing:value,position:value}} + +public class NavWaypoint { + public static final String WAYPOINT_LISTING_KEY = "waypoints"; + private static final Map> cachedWaypointMaps = new HashMap<>(); + private static final Map> v_cachedWaypointMaps = new HashMap<>(); + + //use an editable value as key + public final String index; + //information + public final String name; + public final double targetSpeed; + public final double bearing; + public final Point3D position; + + + + //Global Operation + public static Map getAllWaypointsFromWorld(AWrapperWorld world) { + if (!cachedWaypointMaps.containsKey(world)) { + IWrapperNBT waypointListing = world.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + Map waypointMap = new HashMap<>(); + for (String waypointIndex : waypointListing.getAllNames()) { + waypointMap.put(waypointIndex, new NavWaypoint(waypointListing.getData(waypointIndex))); + } + cachedWaypointMaps.put(world, waypointMap); + } else { + return Collections.emptyMap(); + } + } + + return cachedWaypointMaps.get(world); + } + + + public static NavWaypoint getByIndexFromWorld(AWrapperWorld world, String index) { + if (!cachedWaypointMaps.containsKey(world)) { + IWrapperNBT waypointListing = world.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + Map waypointMap = new HashMap<>(); + for (String waypointIndex : waypointListing.getAllNames()) { + waypointMap.put(waypointIndex, new NavWaypoint(waypointListing.getData(waypointIndex))); + } + cachedWaypointMaps.put(world, waypointMap); + } else { + return null; + } + } + + return cachedWaypointMaps.get(world).get(index); + } + + public static void removeFromWorld(AWrapperWorld world, String index) { + if (index != null) { + if (cachedWaypointMaps.containsKey(world)) { + cachedWaypointMaps.get(world).remove(index); + } + + IWrapperNBT waypointListing = world.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + waypointListing.deleteEntry(index); + world.setData(WAYPOINT_LISTING_KEY, waypointListing); + } + } + } + + + public NavWaypoint(AWrapperWorld world, String index, String name, double targetspeed, double bearing, Point3D position) { + this.index = index; + this.name = name; + this.targetSpeed = targetspeed; + this.bearing = bearing; + this.position = position; + IWrapperNBT waypointListing = world.getData(WAYPOINT_LISTING_KEY); + if (waypointListing == null) { + waypointListing = InterfaceManager.coreInterface.getNewNBTWrapper(); + } + waypointListing.setData(index, save(InterfaceManager.coreInterface.getNewNBTWrapper())); + world.setData(WAYPOINT_LISTING_KEY, waypointListing); + cachedWaypointMaps.remove(world); + } + + + //Vehicle Operation + + public NavWaypoint(AEntityD_Definable entity, String index, String name, double targetspeed, double bearing, Point3D position, IWrapperNBT data) { + this.index = index; + this.name = name; + this.targetSpeed = targetspeed; + this.bearing = bearing; + this.position = position; + IWrapperNBT waypointListing = data.getData(WAYPOINT_LISTING_KEY); + if (waypointListing == null) { + waypointListing = InterfaceManager.coreInterface.getNewNBTWrapper(); + } + waypointListing.setData(index, save(InterfaceManager.coreInterface.getNewNBTWrapper())); + data.setData(WAYPOINT_LISTING_KEY, waypointListing); + v_cachedWaypointMaps.remove(entity); + } + + public static NavWaypoint getByIndexFromVehicle(AEntityD_Definable entity, String index, IWrapperNBT data) { + //check data + if(data == null)return null; + + if (!v_cachedWaypointMaps.containsKey(entity)) { + IWrapperNBT waypointListing = data.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + Map waypointMap = new HashMap<>(); + for (String waypointIndex : waypointListing.getAllNames()) { + waypointMap.put(waypointIndex, new NavWaypoint(waypointListing.getData(waypointIndex))); + } + v_cachedWaypointMaps.put(entity, waypointMap); + } else { + return null; + } + } + + //check if this index is existed + if(v_cachedWaypointMaps.get(entity)!=null)return v_cachedWaypointMaps.get(entity).get(index); + else return null; + } + public static Map getAllWaypointsFromVehicle(AEntityD_Definable entity, IWrapperNBT data) { + //check data + if(data == null)return null; + + if (!v_cachedWaypointMaps.containsKey(entity)) { + IWrapperNBT waypointListing = data.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + Map waypointMap = new HashMap<>(); + for (String waypointIndex : waypointListing.getAllNames()) { + waypointMap.put(waypointIndex, new NavWaypoint(waypointListing.getData(waypointIndex))); + } + v_cachedWaypointMaps.put(entity, waypointMap); + } else { + return null; + } + } + + return v_cachedWaypointMaps.get(entity); + } + public static void removeFromVehicle(AEntityD_Definable entity, String index, IWrapperNBT data) { + if (index != null) { + if (v_cachedWaypointMaps.containsKey(entity)) { + v_cachedWaypointMaps.get(entity).remove(index); + } + + IWrapperNBT waypointListing = data.getData(WAYPOINT_LISTING_KEY); + if (waypointListing != null) { + waypointListing.deleteEntry(index); + data.setData(WAYPOINT_LISTING_KEY, waypointListing); + } + } + } + + + + //Universal Operation + + //internal init + private NavWaypoint(IWrapperNBT data) { + this.index = data.getString("index"); + this.name = data.getString("name"); + this.targetSpeed = data.getDouble("targetSpeed"); + this.bearing = data.getDouble("bearing"); + this.position = data.getPoint3dCompact("location"); + } + + public double getBearingDelta(AEntityB_Existing entity) { + double delta = Math.toDegrees(Math.atan2(entity.position.x - position.x, entity.position.z - position.z)) + bearing + 180; + while (delta < -180) + delta += 360; + while (delta > 180) + delta -= 360; + return delta; + } + + public IWrapperNBT save(IWrapperNBT data) { + data.setString("index",index); + data.setString("name", name); + data.setDouble("targetSpeed", targetSpeed); + data.setDouble("bearing", bearing); + data.setPoint3dCompact("location", position); + return data; + } + + public static void sortWaypointListByIndex(List globalWaypointList) { + Collections.sort(globalWaypointList, new Comparator() { + @Override + public int compare(NavWaypoint wp1, NavWaypoint wp2) { + try { + int index1 = Integer.parseInt(wp1.index); + int index2 = Integer.parseInt(wp2.index); + return Integer.compare(index1, index2); + } catch (NumberFormatException e) { + return 0; + } + } + }); + } +} \ No newline at end of file diff --git a/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypointUpdater.java b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypointUpdater.java new file mode 100644 index 000000000..5e0653d31 --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/NavWaypointUpdater.java @@ -0,0 +1,102 @@ +package minecrafttransportsimulator.baseclasses; + +import minecrafttransportsimulator.entities.components.AEntityD_Definable; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.IWrapperNBT; + +/** + * used for updating waypoint data from client. + */ +public class NavWaypointUpdater { + public NavWaypoint currentWaypoint; + + public NavWaypointUpdater(NavWaypoint currentWaypoint) { + this.currentWaypoint = currentWaypoint; + } + + private void destroyFromWorld(AWrapperWorld world) { + if (currentWaypoint != null) { + NavWaypoint.removeFromWorld(world, currentWaypoint.index); + } + } + public void updateStateFromWorld(AWrapperWorld world, String waypointIndex, String waypointName, String targetSpeedStr, String bearingStr, String xStr, String yStr, String zStr, String isDeleted ) { + boolean Deleted = Boolean.parseBoolean(isDeleted); + + if(Deleted == true){ + destroyFromWorld(world); + }else{ + try { + if (waypointIndex == null || waypointIndex.trim().isEmpty()) { + throw new IllegalArgumentException("Waypoint index cannot be empty."); + } + + String name = waypointName; + + double targetSpeed = Double.parseDouble(targetSpeedStr); + + double bearing = Double.parseDouble(bearingStr); + + double x = Double.parseDouble(xStr); + double y = Double.parseDouble(yStr); + double z = Double.parseDouble(zStr); + + if (currentWaypoint != null) { + NavWaypoint.removeFromWorld(world, currentWaypoint.index); + currentWaypoint = null; + } + currentWaypoint = new NavWaypoint(world,waypointIndex,waypointName,targetSpeed,bearing,new Point3D(x, y, z)); + + } catch (NumberFormatException e) { +// System.err.println("Invalid input: Expected numerical values for targetSpeed, bearing, and position."); + } catch (IllegalArgumentException e) { +// System.err.println("Invalid input: " + e.getMessage()); + } catch (Exception e) { +// System.err.println("An unexpected error occurred: " + e.getMessage()); + } + } + + } + + private void destroyFromVehicle(AEntityD_Definable entity, IWrapperNBT data) { + if (currentWaypoint != null) { + NavWaypoint.removeFromVehicle(entity, currentWaypoint.index,data); + } + } + public void updateStateFromVehicle(AEntityD_Definable entity,IWrapperNBT data ,String waypointIndex, String waypointName, String targetSpeedStr, String bearingStr, String xStr, String yStr, String zStr, String isDeleted ) { + boolean Deleted = Boolean.parseBoolean(isDeleted); + + if(Deleted == true){ + destroyFromVehicle(entity, data); + }else{ + try { + if (waypointIndex == null || waypointIndex.trim().isEmpty()) { + throw new IllegalArgumentException("Waypoint index cannot be empty."); + } + + String name = waypointName; + + double targetSpeed = Double.parseDouble(targetSpeedStr); + + double bearing = Double.parseDouble(bearingStr); + + double x = Double.parseDouble(xStr); + double y = Double.parseDouble(yStr); + double z = Double.parseDouble(zStr); + + if (currentWaypoint != null) { + NavWaypoint.removeFromVehicle(entity, currentWaypoint.index, data); + currentWaypoint = null; + } + currentWaypoint = new NavWaypoint(entity,waypointIndex,waypointName,targetSpeed,bearing,new Point3D(x, y, z),data); + + } catch (NumberFormatException e) { +// System.err.println("Invalid input: Expected numerical values for targetSpeed, bearing, and position."); + } catch (IllegalArgumentException e) { +// System.err.println("Invalid input: " + e.getMessage()); + } catch (Exception e) { +// System.err.println("An unexpected error occurred: " + e.getMessage()); + } + } + + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/baseclasses/PIDController.java b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/PIDController.java new file mode 100644 index 000000000..3453c3e9a --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/baseclasses/PIDController.java @@ -0,0 +1,27 @@ +package minecrafttransportsimulator.baseclasses; + +public class PIDController { + private double kp; + private double ki; + private double kd; + private double prevError; + private double integral; + + public PIDController(double kp, double ki, double kd) { + this.kp = kp; + this.ki = ki; + this.kd = kd; + } + + public double loop(double error, double step) { + integral += error * step; + double derivative = (error - prevError) / step; + prevError = error; + return kp * error + ki * integral + kd * derivative; + } + + public void clear() { + integral = 0; + prevError = 0; + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/entities/instances/AEntityVehicleE_Powered.java b/mccore/src/main/java/minecrafttransportsimulator/entities/instances/AEntityVehicleE_Powered.java index ce9ac186f..9892f983d 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/entities/instances/AEntityVehicleE_Powered.java +++ b/mccore/src/main/java/minecrafttransportsimulator/entities/instances/AEntityVehicleE_Powered.java @@ -2,12 +2,10 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.UUID; -import minecrafttransportsimulator.baseclasses.BoundingBox; -import minecrafttransportsimulator.baseclasses.ComputedVariable; -import minecrafttransportsimulator.baseclasses.NavBeacon; -import minecrafttransportsimulator.baseclasses.Point3D; +import minecrafttransportsimulator.baseclasses.*; import minecrafttransportsimulator.entities.components.AEntityD_Definable; import minecrafttransportsimulator.items.instances.ItemInstrument; import minecrafttransportsimulator.items.instances.ItemItem; @@ -61,7 +59,14 @@ public abstract class AEntityVehicleE_Powered extends AEntityVehicleD_Moving { public double electricPower; public double electricFlow; public String selectedBeaconName; + public String selectedWaypointIndex; public NavBeacon selectedBeacon; + public final String SELECTED_WAYPOINT_LIST_KEY = "selectedWaypoints"; + public final String WAYPOINT_ORDER_KEY = "WaypointOrder"; + + + + public final EntityFluidTank fuelTank; public static final double BATTERY_DEFAULT_CHARGE = 0.85715D; @@ -81,6 +86,28 @@ public AEntityVehicleE_Powered(AWrapperWorld world, IWrapperPlayer placingPlayer this.selectedBeaconName = data.getString("selectedBeaconName"); this.selectedBeacon = NavBeacon.getByNameFromWorld(world, selectedBeaconName); this.fuelTank = new EntityFluidTank(world, data.getData("fuelTank"), definition.motorized.fuelCapacity); + + //init selectedWaypoints + try{ + this.waypointData = data.getData(SELECTED_WAYPOINT_LIST_KEY); + this.selectedWaypointIndex = "-1"; + if(this.waypointData != null){ + IWrapperNBT waypointOrderData = data.getData(WAYPOINT_ORDER_KEY); + int ListIndex = 0; + for(String line:waypointOrderData.getAllNames()){ + String Index = waypointOrderData.getString("ListIndex"+Integer.toString(ListIndex)); + selectedWaypointList.add(NavWaypoint.getByIndexFromVehicle(this,Index,waypointData)); + ListIndex++; + } + + }else{ + this.waypointData = InterfaceManager.coreInterface.getNewNBTWrapper(); + } + }catch (Exception e){ + + } + + } else { this.electricPower = (definition.motorized.batteryCapacity * BATTERY_DEFAULT_CHARGE); this.selectedBeaconName = ""; @@ -301,6 +328,81 @@ public void updatePartList() { } } + + + //For Flight plan, selectedWaypoint should always be the last one of selectedWaypointList. + public List selectedWaypointList = new ArrayList<>(); + IWrapperNBT waypointData = InterfaceManager.coreInterface.getNewNBTWrapper(); + + //Update selected waypoint state + public void UpdateWaypointList(String operation,String opIndex,String index,String name,String targetSpeed,String bearing,String StrX,String StrY,String StrZ) { + int Index = -1; + int OpIndex = -1; + try{ + Index = Integer.parseInt(index); + OpIndex = Integer.parseInt(opIndex); + }catch (Exception e){ + } + //waypointData: not empty + switch (operation){ + case "INSERT":{ + try{ + if(NavWaypoint.getByIndexFromVehicle(this,index,waypointData)==null){ + Point3D position = new Point3D(Double.parseDouble(StrX),Double.parseDouble(StrY),Double.parseDouble(StrZ)); + NavWaypoint waypoint = new NavWaypoint(this,index,name,Double.parseDouble(targetSpeed),Double.parseDouble(bearing),position,waypointData); + if (waypoint != null && OpIndex >= 0 && OpIndex <= selectedWaypointList.size()) { + selectedWaypointList.add(OpIndex, waypoint); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + break; + } + case "REMOVE":{ + if(selectedWaypointList.size()>0){ + try { + if(NavWaypoint.getByIndexFromVehicle(this,index,waypointData)!=null) { + + if (OpIndex >= 0 && OpIndex < selectedWaypointList.size()) { + NavWaypoint waypoint = selectedWaypointList.get(OpIndex); + if (waypoint != null) { + NavWaypointUpdater waypointUpdater = new NavWaypointUpdater(waypoint); + selectedWaypointList.remove(OpIndex); + waypointUpdater.updateStateFromVehicle(this, waypointData, index, name, targetSpeed, bearing, StrX, StrY, StrZ, "true"); + } + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + break; + } + case "EDIT":{ + if(selectedWaypointList.size()>0){ + try { + if(NavWaypoint.getByIndexFromVehicle(this,index,waypointData)!=null){ + NavWaypoint waypoint = selectedWaypointList.get(OpIndex); + if (waypoint != null){ + NavWaypointUpdater waypointUpdater = new NavWaypointUpdater(waypoint); + waypointUpdater.updateStateFromVehicle(this, waypointData, index, name, targetSpeed, bearing, StrX, StrY, StrZ, "false"); + if(waypoint!=null)selectedWaypointList.set(OpIndex, waypointUpdater.currentWaypoint); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + break; + } + default:{ + break; + } + } + } + + public FuelTankResult checkFuelTankCompatibility(String fluid) { //Check tank first to make sure there's not a mis-match. if (!fuelTank.getFluid().isEmpty()) { @@ -368,6 +470,23 @@ public IWrapperNBT save(IWrapperNBT data) { data.setDouble("electricPower", electricPower); data.setString("selectedBeaconName", selectedBeaconName); data.setData("fuelTank", fuelTank.save(InterfaceManager.coreInterface.getNewNBTWrapper())); + + if(waypointData!= null)data.setData(SELECTED_WAYPOINT_LIST_KEY, waypointData); + //save point order + try{ + int ListIndex = 0; + IWrapperNBT waypointOrderData = InterfaceManager.coreInterface.getNewNBTWrapper(); + for(NavWaypoint waypoint:selectedWaypointList){ + waypointOrderData.setString("ListIndex"+Integer.toString(ListIndex),waypoint.index); + ListIndex++; + } + data.setData(WAYPOINT_ORDER_KEY, waypointOrderData); + }catch (Exception e){ + e.printStackTrace(); + } + + + return data; } diff --git a/mccore/src/main/java/minecrafttransportsimulator/entities/instances/EntityVehicleF_Physics.java b/mccore/src/main/java/minecrafttransportsimulator/entities/instances/EntityVehicleF_Physics.java index cffa54e91..3fb1e0c36 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/entities/instances/EntityVehicleF_Physics.java +++ b/mccore/src/main/java/minecrafttransportsimulator/entities/instances/EntityVehicleF_Physics.java @@ -4,12 +4,7 @@ import java.util.List; import java.util.Set; -import minecrafttransportsimulator.baseclasses.BoundingBox; -import minecrafttransportsimulator.baseclasses.ColorRGB; -import minecrafttransportsimulator.baseclasses.ComputedVariable; -import minecrafttransportsimulator.baseclasses.Point3D; -import minecrafttransportsimulator.baseclasses.TowingConnection; -import minecrafttransportsimulator.baseclasses.TransformationMatrix; +import minecrafttransportsimulator.baseclasses.*; import minecrafttransportsimulator.entities.components.AEntityB_Existing; import minecrafttransportsimulator.entities.components.AEntityG_Towable; import minecrafttransportsimulator.items.instances.ItemVehicle; @@ -66,6 +61,23 @@ public class EntityVehicleF_Physics extends AEntityVehicleE_Powered { //Autopilot. public final ComputedVariable autopilotValueVar; public final ComputedVariable autolevelEnabledVar; + public final ComputedVariable autopilotNavEnabledVar; + public final ComputedVariable autopilotHeadingEnabledVar; + public final ComputedVariable autopilotAltitudeEnabledVar; + public final ComputedVariable autopilotSpeedEnabledVar; + public final ComputedVariable autopilotVerticalSpeedEnabledVar; + public final ComputedVariable autopilotPositionX; + public final ComputedVariable autopilotPositionY; + public final ComputedVariable autopilotPositionZ; + public final ComputedVariable autopilotHeading; + public final ComputedVariable autopilotAltitude; + public final ComputedVariable autopilotSpeed; + public final ComputedVariable autopilotVerticalSpeed; +// private PIDController verticalSpeedController = new PIDController(0.001, 0.000005, 0.01); + private final PIDController verticalSpeedController = new PIDController(0.003, 10, 0.01); + private final PIDController speedController = new PIDController(0.15, 0.000375, 0.00003); +// private PIDController cdiDeflectionController = new PIDController(4.5, 0.4, 0.0); + private final PIDController cdiDeflectionController = new PIDController(10.0, 0.2, 0.2); //Open top. public final ComputedVariable openTopVar; @@ -154,6 +166,18 @@ public EntityVehicleF_Physics(AWrapperWorld world, IWrapperPlayer placingPlayer, addVariable(this.autopilotValueVar = new ComputedVariable(this, "autopilot", data)); addVariable(this.autolevelEnabledVar = new ComputedVariable(this, "auto_level", data)); addVariable(this.openTopVar = new ComputedVariable(this, "hasOpenTop", data)); + addVariable(this.autopilotNavEnabledVar = new ComputedVariable(this, "autopilot_nav_enable")); + addVariable(this.autopilotHeadingEnabledVar = new ComputedVariable(this, "autopilot_heading_enable")); + addVariable(this.autopilotAltitudeEnabledVar = new ComputedVariable(this, "autopilot_altitude_enable")); + addVariable(this.autopilotSpeedEnabledVar = new ComputedVariable(this, "autopilot_speed_enable")); + addVariable(this.autopilotVerticalSpeedEnabledVar = new ComputedVariable(this, "autopilot_vertical_speed_enable")); + addVariable(this.autopilotHeading = new ComputedVariable(this, "autopilot_heading", data)); + addVariable(this.autopilotAltitude = new ComputedVariable(this, "autopilot_altitude", data)); + addVariable(this.autopilotVerticalSpeed = new ComputedVariable(this, "autopilot_vertical_speed", data)); + addVariable(this.autopilotSpeed = new ComputedVariable(this, "autopilot_speed", data)); + addVariable(this.autopilotPositionX = new ComputedVariable(this, "autopilot_position_x", data)); + addVariable(this.autopilotPositionY = new ComputedVariable(this, "autopilot_position_y", data)); + addVariable(this.autopilotPositionZ = new ComputedVariable(this, "autopilot_position_z", data)); addVariable(this.dragCoefficientVar = new ComputedVariable(this, "dragCoefficient")); addVariable(this.ballastControlVar = new ComputedVariable(this, "ballastControl", data)); @@ -611,19 +635,65 @@ protected void adjustControlSurfaces() { } } } else if (definition.motorized.isAircraft && autopilotValueVar.isActive) { - //Normal aircraft. Do autopilot operations if required. - //If we are not flying at a steady elevation, angle the elevator to compensate - if (-motion.y * 10 > elevatorTrimVar.currentValue + 1 && elevatorTrimVar.currentValue < MAX_ELEVATOR_TRIM) { - elevatorTrimVar.adjustBy(0.1, true); - } else if (-motion.y * 10 < elevatorTrimVar.currentValue - 1 && elevatorTrimVar.currentValue > -MAX_ELEVATOR_TRIM) { - elevatorTrimVar.adjustBy(-0.1, true); - } - //Keep the roll angle at 0. - if (-orientation.angles.z > aileronTrimVar.currentValue + 0.1 && aileronTrimVar.currentValue < MAX_AILERON_TRIM) { - aileronTrimVar.adjustBy(0.1, true); - } else if (-orientation.angles.z < aileronTrimVar.currentValue - 0.1 && aileronTrimVar.currentValue > -MAX_AILERON_TRIM) { - aileronTrimVar.adjustBy(-0.1, true); +// if (autopilotNavEnabledVar.isActive) { + if (selectedBeacon != null) { + autopilotPositionX.setTo(selectedBeacon.position.x, true); + autopilotPositionY.setTo(selectedBeacon.position.y, true); + autopilotPositionZ.setTo(selectedBeacon.position.z, true); + System.out.println("Naving beacon"); + navILS(); + setHeading(); + setVerticalSpeed(); + } else if (!selectedWaypointIndex.equals("-1")) { + NavWaypoint waypoint = selectedWaypointList.get(Integer.parseInt(selectedWaypointIndex)); + autopilotPositionX.setTo(waypoint.position.x, true); + autopilotPositionY.setTo(waypoint.position.y, true); + autopilotPositionZ.setTo(waypoint.position.z, true); + System.out.println("Going waypoint guided"); + navGPS(); + setHeading(); + setAltitude(); + setVerticalSpeed(); + } else { +// autopilotNavEnabledVar.setActive(false, true); + //TODO: this is potential bug where player use beacon nav first, change to waypoint then back to beacon, all without turning off nav mode + cdiDeflectionController.clear(); + System.out.println("Leveling out"); + autopilotAltitude.setTo(position.y - seaLevel, true); + autopilotHeading.setTo(-orientation.angles.y, true); + setHeading(); + setAltitude(); + setVerticalSpeed(); + } +// } + if (autopilotHeadingEnabledVar.isActive) { + System.out.println("Heading to " + autopilotHeading.currentValue); + setHeading(); + } + if (autopilotAltitudeEnabledVar.isActive) { + setAltitude(); + } + if (autopilotSpeedEnabledVar.isActive) { + setSpeed(); + } else { + speedController.clear(); } + if (autopilotVerticalSpeedEnabledVar.isActive) { + setVerticalSpeed(); + } else { + verticalSpeedController.clear(); + } +// if (selectedBeacon == null) { +// autopilotPositionX.setTo(0, true); +// autopilotPositionZ.setTo(0, true); +// } +// autopilotPositionY.setTo(100, true); +// navGPS(); +// autopilotHeading.setTo(360, true); +// setHeading(); +// autopilotVerticalSpeed.setTo(1, true); +// setVerticalSpeed(); +// navILS(); } //If we don't have controllers, reset control states to 0. @@ -656,6 +726,159 @@ protected void adjustControlSurfaces() { } } + public void autolevel() { + //If we are not flying at a steady elevation, angle the elevator to compensate + if (-motion.y * 10 > elevatorTrimVar.currentValue + 1 && elevatorTrimVar.currentValue < MAX_ELEVATOR_TRIM) { + elevatorTrimVar.adjustBy(0.1, true); + } else if (-motion.y * 10 < elevatorTrimVar.currentValue - 1 && elevatorTrimVar.currentValue > -MAX_ELEVATOR_TRIM) { + elevatorTrimVar.adjustBy(-0.1, true); + } + + if (-orientation.angles.z > aileronTrimVar.currentValue + 0.1 && aileronTrimVar.currentValue < MAX_AILERON_TRIM) { + aileronTrimVar.adjustBy(0.1, true); + } else if (-orientation.angles.z < aileronTrimVar.currentValue - 0.1 && aileronTrimVar.currentValue > -MAX_AILERON_TRIM) { + aileronTrimVar.adjustBy(-0.1, true); + } + } + + public void navGPS() { +// double heading = Math.toDegrees(Math.atan2(autopilotPositionZ.currentValue - position.z , autopilotPositionX.currentValue - position.x)); + double heading; + heading = Math.toDegrees(Math.atan2(autopilotPositionX.currentValue - position.x, autopilotPositionZ.currentValue - position.z)); + if (ConfigSystem.client.controlSettings.north360.value) + heading += 180; + heading = (heading + 360) % 360; + autopilotHeading.setTo(heading, true); + autopilotAltitude.setTo(autopilotPositionY.currentValue, true); + } + + public void navILS() { + // Horizontal navigation + double delta = selectedBeacon.getBearingDelta(this); + double output = cdiDeflectionController.loop(delta, 0.05); + if (output < -45) { + output = -45; + cdiDeflectionController.clear(); + } else if (output > 45) { + output = 45; + cdiDeflectionController.clear(); + } + double heading = output + selectedBeacon.bearing + 180; + autopilotHeading.setTo(heading, true); + + // Vertical navigation + delta = selectedBeacon.getGlideSlopeDelta(this); + output = delta * 45; + if (output > 20) { + output = 20; + } else if (output < -45) { + output = -45; + } + // Output = Math.toDegrees(Math.asin(motion.y / velocity)) + autopilotVerticalSpeed.setTo(Math.sin(Math.toRadians(output))*velocity*speedFactor*20, true); + } + + public void setSpeed() { + double delta = autopilotSpeed.currentValue - indicatedSpeed; + double output = speedController.loop(delta, 1); + if (output < 0) { + output = 0; + } else if (output > MAX_THROTTLE) { + output = 1; + } + double signalDelta = output - throttleVar.currentValue; + if (signalDelta > 0) { + if (signalDelta > 0.0125) { + signalDelta = 0.0125; + } + throttleVar.adjustBy(signalDelta, true); + } else if (signalDelta < 0) { + if (signalDelta < -0.0125) { + signalDelta = -0.0125; + } + throttleVar.adjustBy(signalDelta, true); + } + } + + public void setHeading() { + double currentHeading = -orientation.angles.y; + if (ConfigSystem.client.controlSettings.north360.value) + currentHeading += 180; + currentHeading = (currentHeading + 360) %360; + double delta = (autopilotHeading.currentValue + currentHeading) % 360; + if (delta > 180) { + delta = -(360 - delta); + } +// double delta = orientation.angles.getClampedYDelta(autopilotHeading.currentValue); + double output = delta; + // Clamp banking angle to 45 deg + if (output > 45) { + output = 45; + } else if (output < -45) { + output = -45; + } +// System.out.println("Heading " + delta + " " + output); +// This was the control before tranforming +// -orientation.angles.z - output > aileronTrimVar.currentValue + 0.1 + double signalDelta = -orientation.angles.z - output - aileronTrimVar.currentValue - 0.1; + if (signalDelta > 0 && aileronTrimVar.currentValue < MAX_AILERON_TRIM) { + if (signalDelta > 0.75) { + signalDelta = 0.75; + } + aileronTrimVar.adjustBy(signalDelta, true); + } else if (signalDelta < 0 && aileronTrimVar.currentValue > -MAX_AILERON_TRIM) { + if (signalDelta < -0.75) { + signalDelta = -0.75; + } + aileronTrimVar.adjustBy(signalDelta, true); + } + } + + public void setAltitude() { +// if (autopilotSpeed.isActive) { + +// } + double deltaAltitude = autopilotAltitude.currentValue - (position.y - seaLevel); + double output = deltaAltitude * 0.50; +// if (!autopilotVerticalSpeed.isActive) { +// if (-motion.y * 10 > elevatorTrimVar.currentValue + 1 && elevatorTrimVar.currentValue < MAX_ELEVATOR_TRIM) { +// elevatorTrimVar.adjustBy(0.1, true); +// } else if (-motion.y * 10 < elevatorTrimVar.currentValue - 1 && elevatorTrimVar.currentValue > -MAX_ELEVATOR_TRIM) { +// elevatorTrimVar.adjustBy(-0.1, true); +// } +// return; + autopilotVerticalSpeed.setTo(output, true); +// } + // Slow down the ascending + if ((deltaAltitude > 0 && output < autopilotVerticalSpeed.currentValue) || (deltaAltitude < 0 && output > autopilotVerticalSpeed.currentValue)) { + autopilotVerticalSpeed.setTo(output, true); + } + System.out.println("Altitude " + deltaAltitude + " " + output); + } + + public void setVerticalSpeed() { + double delta = autopilotVerticalSpeed.currentValue - motion.y * speedFactor * 20; + double output = verticalSpeedController.loop(delta, 0.05); + if (output < -MAX_ELEVATOR_TRIM) { + output = -MAX_ELEVATOR_TRIM; + } else if (output > MAX_ELEVATOR_TRIM) { + output = MAX_ELEVATOR_TRIM; + } +// System.out.println("Vertical speed " + delta + " " + output); + double signalDelta = output - elevatorTrimVar.currentValue; + if (signalDelta > 0) { + if (signalDelta > 0.75) { + signalDelta = 0.75; + } + elevatorTrimVar.adjustBy(signalDelta, true); + } else if (signalDelta < 0) { + if (signalDelta < -0.75) { + signalDelta = -0.75; + } + elevatorTrimVar.adjustBy(signalDelta, true); + } + } + protected double getRecursiveTowingThrust() { if (!towingConnections.isEmpty()) { double thrust = 0; @@ -828,9 +1051,9 @@ public ComputedVariable createComputedVariable(String variable, boolean createDe case ("beacon_glideslope_setpoint"): return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? selectedBeacon.glideSlope : 0, false); case ("beacon_glideslope_actual"): - return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? Math.toDegrees(Math.asin((position.y - selectedBeacon.position.y) / position.distanceTo(selectedBeacon.position))) : 0, false); + return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? -selectedBeacon.getGlideSlopeDelta(this) + selectedBeacon.glideSlope : 0, false); case ("beacon_glideslope_delta"): - return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? selectedBeacon.glideSlope - Math.toDegrees(Math.asin((position.y - selectedBeacon.position.y) / position.distanceTo(selectedBeacon.position))) : 0, false); + return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? selectedBeacon.getGlideSlopeDelta(this) : 0, false); case ("beacon_distance"): return new ComputedVariable(this, variable, partialTicks -> selectedBeacon != null ? Math.hypot(-selectedBeacon.position.z + position.z,-selectedBeacon.position.x + position.x) : 0, false); case ("radar_detected"): diff --git a/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIPanel.java b/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIPanel.java index 9eb2a5e68..4ba8aacdf 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIPanel.java +++ b/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIPanel.java @@ -401,6 +401,44 @@ public void handleKeyTyped(char typedChar, int typedCode, TextBoxControlKey cont } break; } + case HEADING: { + if (ConfigSystem.settings.general.allPlanesWithNav.value) { + beaconBox = new GUIComponentTextBox(this, 0, -10, panelComponent.width, panelComponent.height, vehicle.autopilotHeading.currentValue + "", ColorRGB.WHITE, 5, (int) panelComponent.textureStart.x, (int) panelComponent.textureStart.y, panelComponent.width, panelComponent.height) { + @Override + public void handleKeyTyped(char typedChar, int typedCode, TextBoxControlKey control) { + super.handleKeyTyped(typedChar, typedCode, control); + //Update the vehicle beacon state. + try { + int heading = Integer.parseInt(getText()); + InterfaceManager.packetInterface.sendToServer(new PacketEntityVariableSet(vehicle.autopilotHeading, heading)); + } catch (Exception e) {} + } + }; + addComponent(beaconBox); + newComponent = beaconBox; + text = "Hdg"; + } + break; + } + case HEADING_ENABLE: { + newComponent = new GUIPanelButton(this, panelComponent) { + @Override + public void onClicked(boolean leftSide) { + if (vehicle.autopilotHeadingEnabledVar.isActive) { + InterfaceManager.packetInterface.sendToServer(new PacketEntityVariableSet(vehicle.autopilotHeadingEnabledVar, 0)); + } else if (vehicle.definition.motorized.isAircraft) { + InterfaceManager.packetInterface.sendToServer(new PacketEntityVariableSet(vehicle.autopilotHeadingEnabledVar, 1)); + } + } + + @Override + public int getState() { + return vehicle.autopilotValueVar.isActive ? 1 : 0; + } + }; + text = vehicle.definition.motorized.isAircraft ? "AUTO" : "CRUISE"; + break; + } case ROLL_TRIM: { newComponent = new GUIPanelTrimButton(this, panelComponent, vehicle.aileronTrimVar, -0.1, EntityVehicleF_Physics.MAX_AILERON_TRIM); text = "ROLL TRIM"; diff --git a/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIWaypointManager.java b/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIWaypointManager.java new file mode 100644 index 000000000..f3c214c76 --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/guis/instances/GUIWaypointManager.java @@ -0,0 +1,689 @@ +package minecrafttransportsimulator.guis.instances; + +import minecrafttransportsimulator.baseclasses.ColorRGB; +import minecrafttransportsimulator.baseclasses.NavWaypoint; +import minecrafttransportsimulator.entities.instances.EntityVehicleF_Physics; +import minecrafttransportsimulator.guis.components.AGUIBase; +import minecrafttransportsimulator.guis.components.GUIComponentButton; +import minecrafttransportsimulator.guis.components.GUIComponentLabel; +import minecrafttransportsimulator.guis.components.GUIComponentTextBox; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.IWrapperPlayer; +import minecrafttransportsimulator.mcinterface.InterfaceManager; +import minecrafttransportsimulator.packets.instances.*; + +import java.util.*; + +public class GUIWaypointManager extends AGUIBase { + + private final AWrapperWorld world; + private final IWrapperPlayer player; + + /** + * Global Waypoint Related Variable + * + * */ + private int scrollSpot = 0; + private GUIComponentButton PageUpButton; + private GUIComponentButton PageDownButton; + private GUIComponentButton addWaypointButton; + private GUIComponentButton removeWaypointButton; + private final List waypointSelectionButtons = new ArrayList<>(); + private final List waypointNameList = new ArrayList<>(); + private final List waypointXList = new ArrayList<>(); + private final List waypointYList = new ArrayList<>(); + private final List waypointZList = new ArrayList<>(); + + //cache map directly from getAllWaypointsFromWorld() + private Map globalWaypoint; + //cache list should be shown + private List globalWaypointList; + private NavWaypoint currentWaypoint; + private int currentWaypointIndex = -1; + //cache max index + private int maxWaypointIndex; + + /** + * Vehicle Waypoint Related Variable + * + * */ + private final EntityVehicleF_Physics vehicle; + private int V_scrollSpot = 0; + private GUIComponentButton V_PageUpButton; + private GUIComponentButton V_PageDownButton; + private GUIComponentButton V_addWaypointButton; + private GUIComponentButton V_removeWaypointButton; + private final List V_waypointSelectionButtons = new ArrayList<>(); + private final List V_waypointNameList = new ArrayList<>(); + private final List V_waypointXList = new ArrayList<>(); + private final List V_waypointYList = new ArrayList<>(); + private final List V_waypointZList = new ArrayList<>(); + + //cache list should be shown + private List V_globalWaypointList; + private NavWaypoint V_currentWaypoint; + private int V_currentWaypointIndex = -1; + //cache max index + private int V_maxWaypointIndex; + + private final int lineHeight = 11; + private final int globalOffset = 10; + private final int vehicleOffet = 98; + + + public GUIWaypointManager(IWrapperPlayer player,EntityVehicleF_Physics vehicle) + { + super(); + this.player = player; + this.world = player.getWorld(); + this.vehicle = vehicle; + this.globalWaypoint = NavWaypoint.getAllWaypointsFromWorld(world); + } + + /** + * Global + * */ + public void updateGlobalWaypointList() { + globalWaypoint = NavWaypoint.getAllWaypointsFromWorld(world); + globalWaypointList = new ArrayList<>(globalWaypoint.values()); + NavWaypoint.sortWaypointListByIndex(globalWaypointList); + } + public void updateCurrentWaypoint(int index) { + if(index-1){ + currentWaypointIndex = index; + currentWaypoint = globalWaypointList.get(index); + }else{ + currentWaypoint = null; + currentWaypointIndex = -1; + } + } + public void updateMaxWaypointIndex() { + + if(globalWaypointList.size()>0){ + for(NavWaypoint waypoint:globalWaypointList){ + maxWaypointIndex = Math.max(maxWaypointIndex,Integer.parseInt(waypoint.index)); + } + }else{ + maxWaypointIndex = -1; + } + } + public void setupGlobalPart() { + updateGlobalWaypointList(); + waypointSelectionButtons.clear(); + waypointNameList.clear(); + waypointXList.clear(); + waypointYList.clear(); + waypointZList.clear(); + + for (int pageIndex = 0; pageIndex < 7; ++pageIndex) { + int finalpageIndex = pageIndex; + + //Index button init + GUIComponentButton button = new GUIComponentButton(this, guiLeft + 10, guiTop + 10 + lineHeight * waypointSelectionButtons.size() + globalOffset, 25, lineHeight, Integer.toString(pageIndex+scrollSpot+1)) {//width205 + @Override + public void onClicked(boolean leftSide) { + for(GUIComponentButton IndexButton:waypointSelectionButtons){ + IndexButton.enabled = true; + } + this.enabled = false; + updateCurrentWaypoint(finalpageIndex+scrollSpot); + } + }; + addComponent(button); + + //init TextBox text + String waypointNameString = ""; + if(pageIndex+scrollSpot(vehicle.selectedWaypointList); + }else{ + V_globalWaypointList = new ArrayList<>(); + } + } + public void V_updateCurrentWaypoint(int index) { + if(index-1){ + V_currentWaypointIndex = index; + V_currentWaypoint = V_globalWaypointList.get(index); + }else{ + V_currentWaypoint = null; + V_currentWaypointIndex = -1; + } + } + public void V_updateMaxWaypointIndex() { + + if(V_globalWaypointList.size()>0){ + for(NavWaypoint waypoint:V_globalWaypointList){ + V_maxWaypointIndex = Math.max(V_maxWaypointIndex,Integer.parseInt(waypoint.index)); + } + }else{ + V_maxWaypointIndex = -1; + } + } + + + public void setupVehiclePart() { + V_updateGlobalWaypointList(); + V_waypointSelectionButtons.clear(); + V_waypointNameList.clear(); + V_waypointXList.clear(); + V_waypointYList.clear(); + V_waypointZList.clear(); + + for (int pageIndex = 0; pageIndex < 7; ++pageIndex) { + int finalpageIndex = pageIndex; + + //Index button init + GUIComponentButton button = new GUIComponentButton(this, guiLeft + 10, guiTop + 10 + lineHeight * V_waypointSelectionButtons.size() + vehicleOffet, 25, lineHeight, Integer.toString(pageIndex+V_scrollSpot+1)) {//width205 + @Override + public void onClicked(boolean leftSide) { + for(GUIComponentButton IndexButton:V_waypointSelectionButtons){ + IndexButton.enabled = true; + } + this.enabled = false; + V_updateCurrentWaypoint(finalpageIndex+V_scrollSpot); + InterfaceManager.packetInterface.sendToServer(new PacketVehicleWaypointSelectRequest(vehicle, Integer.toString(finalpageIndex+V_scrollSpot))); + } + }; + addComponent(button); + + //init TextBox text + String waypointNameString = ""; + if(pageIndex+V_scrollSpotglobalWaypointList.size()) PageDownButton.enabled = false; + else PageDownButton.enabled = true; + + for (int i = 0; i < 7; ++i){ + int finalpageIndex = i; + + GUIComponentButton button = waypointSelectionButtons.get(finalpageIndex); + GUIComponentTextBox waypointName = waypointNameList.get(finalpageIndex); + GUIComponentTextBox waypointX = waypointXList.get(finalpageIndex); + GUIComponentTextBox waypointY = waypointYList.get(finalpageIndex); + GUIComponentTextBox waypointZ = waypointZList.get(finalpageIndex); + + button.text = Integer.toString(finalpageIndex+scrollSpot+1); + //update state + if(finalpageIndex+scrollSpot != currentWaypointIndex)button.enabled = true; + + //update text in TextBox + if(!waypointName.focused) { + updateNameText(finalpageIndex); + }else if(finalpageIndex+scrollSpot globalWaypointList.size()){ + button.visible =false; + waypointName.visible = false; + waypointX.visible = false; + waypointY.visible = false; + waypointZ.visible = false; + }else{ + button.visible = true; + waypointName.visible = true; + waypointX.visible = true; + waypointY.visible = true; + waypointZ.visible = true; + } + } + } + + public void updateNameText(int i){ + GUIComponentTextBox waypointName = waypointNameList.get(i); + String waypointNameString = "NONE"; + if(i+scrollSpotglobalWaypointList.size()) PageDownButton.enabled = false; + else PageDownButton.enabled = true; + + if(V_scrollSpot==0) V_PageUpButton.enabled = false; + else V_PageUpButton.enabled = true; + if(V_scrollSpot+7+1>V_globalWaypointList.size()) V_PageDownButton.enabled = false; + else V_PageDownButton.enabled = true; + + for (int i = 0; i < 7; ++i){ + int finalpageIndex = i; + + GUIComponentButton button = V_waypointSelectionButtons.get(finalpageIndex); + GUIComponentTextBox waypointName = V_waypointNameList.get(finalpageIndex); + GUIComponentTextBox waypointX = V_waypointXList.get(finalpageIndex); + GUIComponentTextBox waypointY = V_waypointYList.get(finalpageIndex); + GUIComponentTextBox waypointZ = V_waypointZList.get(finalpageIndex); + + button.text = Integer.toString(finalpageIndex+V_scrollSpot+1); + //update state + if(finalpageIndex+V_scrollSpot != V_currentWaypointIndex)button.enabled = true; + + //update text in TextBox + if(!waypointName.focused) { + V_updateNameText(finalpageIndex); + }else if(finalpageIndex+V_scrollSpot V_globalWaypointList.size()){ + button.visible =false; + waypointName.visible = false; + waypointX.visible = false; + waypointY.visible = false; + waypointZ.visible = false; + }else{ + button.visible = true; + waypointName.visible = true; + waypointX.visible = true; + waypointY.visible = true; + waypointZ.visible = true; + } + } + } + + public void V_updateNameText(int i){ + GUIComponentTextBox waypointName = V_waypointNameList.get(i); + String waypointNameString = "NONE"; + if(i+V_scrollSpot { + private final String waypointIndex; + + public PacketVehicleWaypointSelect(EntityVehicleF_Physics entity, String waypointIndex) { + super(entity); + this.waypointIndex = waypointIndex; + } + + public PacketVehicleWaypointSelect(ByteBuf buf) { + super(buf); + this.waypointIndex = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(waypointIndex, buf); + } + + @Override + public boolean handle(AWrapperWorld world, EntityVehicleF_Physics vehicle) { + vehicle.selectedWaypointIndex = waypointIndex; + return true; + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointSelectRequest.java b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointSelectRequest.java new file mode 100644 index 000000000..6518e7536 --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointSelectRequest.java @@ -0,0 +1,37 @@ +package minecrafttransportsimulator.packets.instances; + +import io.netty.buffer.ByteBuf; +import minecrafttransportsimulator.entities.components.AEntityA_Base; +import minecrafttransportsimulator.entities.instances.EntityVehicleF_Physics; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.InterfaceManager; +import minecrafttransportsimulator.packets.components.APacketEntity; + +public class PacketVehicleWaypointSelectRequest extends APacketEntity { + private final String waypointIndex; + + public PacketVehicleWaypointSelectRequest(EntityVehicleF_Physics entity, String waypointIndex) { + super(entity); + this.waypointIndex = waypointIndex; + } + + public PacketVehicleWaypointSelectRequest(ByteBuf buf) { + super(buf); + this.waypointIndex = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(waypointIndex, buf); + } + + @Override + protected boolean handle(AWrapperWorld world, EntityVehicleF_Physics entity) { + if (!world.isClient()) { + entity.selectedWaypointIndex = waypointIndex; + InterfaceManager.packetInterface.sendToAllClients(new PacketVehicleWaypointSelect(entity, waypointIndex)); + } + return true; + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdate.java b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdate.java new file mode 100644 index 000000000..5bf98e194 --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdate.java @@ -0,0 +1,67 @@ +package minecrafttransportsimulator.packets.instances; + +import io.netty.buffer.ByteBuf; +import minecrafttransportsimulator.entities.instances.EntityVehicleF_Physics; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.packets.components.APacketEntity; + +/** + * Update waypoint selection for vehicle + */ +public class PacketVehicleWaypointUpdate extends APacketEntity { + private final String operation; + private final String opIndex; + private final String index; + private final String name; + private final String targetSpeed; + private final String bearing; + private final String StrX; + private final String StrY; + private final String StrZ; + + public PacketVehicleWaypointUpdate(EntityVehicleF_Physics vehicle, String operation,String opIndex, String index, String name, String targetSpeed, String bearing, String StrX, String StrY, String StrZ) { + super(vehicle); + this.operation = operation; + this.opIndex = opIndex; + this.index = index; + this.name = name; + this.targetSpeed = targetSpeed; + this.bearing = bearing; + this.StrX = StrX; + this.StrY = StrY; + this.StrZ = StrZ; + } + + public PacketVehicleWaypointUpdate(ByteBuf buf) { + super(buf); + this.operation = readStringFromBuffer(buf); + this.opIndex = readStringFromBuffer(buf); + this.index = readStringFromBuffer(buf); + this.name = readStringFromBuffer(buf); + this.targetSpeed = readStringFromBuffer(buf); + this.bearing = readStringFromBuffer(buf); + this.StrX = readStringFromBuffer(buf); + this.StrY = readStringFromBuffer(buf); + this.StrZ = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(operation, buf); + writeStringToBuffer(opIndex, buf); + writeStringToBuffer(index, buf); + writeStringToBuffer(name, buf); + writeStringToBuffer(targetSpeed, buf); + writeStringToBuffer(bearing, buf); + writeStringToBuffer(StrX, buf); + writeStringToBuffer(StrY, buf); + writeStringToBuffer(StrZ, buf); + } + + @Override + public boolean handle(AWrapperWorld world, EntityVehicleF_Physics vehicle) { + vehicle.UpdateWaypointList(operation,opIndex,index,name,targetSpeed,bearing,StrX,StrY,StrZ); + return true; + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdateRequest.java b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdateRequest.java new file mode 100644 index 000000000..faff7c9e4 --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketVehicleWaypointUpdateRequest.java @@ -0,0 +1,76 @@ +package minecrafttransportsimulator.packets.instances; + +import io.netty.buffer.ByteBuf; +import minecrafttransportsimulator.entities.instances.EntityVehicleF_Physics; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.InterfaceManager; +import minecrafttransportsimulator.packets.components.APacketEntity; + +/** + * Request waypoint selection update from client to server for vehicle + */ +public class PacketVehicleWaypointUpdateRequest extends APacketEntity { + private final String operation; + private final String opIndex; + private final String index; + private final String name; + private final String targetSpeed; + private final String bearing; + private final String StrX; + private final String StrY; + private final String StrZ; + + public PacketVehicleWaypointUpdateRequest(EntityVehicleF_Physics vehicle, String operation,String opIndex, String index, String name, String targetSpeed, String bearing, String StrX, String StrY, String StrZ) { + super(vehicle); + this.operation = operation; + this.opIndex = opIndex; + this.index = index; + this.name = name; + this.targetSpeed = targetSpeed; + this.bearing = bearing; + this.StrX = StrX; + this.StrY = StrY; + this.StrZ = StrZ; + } + + public PacketVehicleWaypointUpdateRequest(ByteBuf buf) { + super(buf); + this.operation = readStringFromBuffer(buf); + this.opIndex = readStringFromBuffer(buf); + this.index = readStringFromBuffer(buf); + this.name = readStringFromBuffer(buf); + this.targetSpeed = readStringFromBuffer(buf); + this.bearing = readStringFromBuffer(buf); + this.StrX = readStringFromBuffer(buf); + this.StrY = readStringFromBuffer(buf); + this.StrZ = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(operation, buf); + writeStringToBuffer(opIndex, buf); + writeStringToBuffer(index, buf); + writeStringToBuffer(name, buf); + writeStringToBuffer(targetSpeed, buf); + writeStringToBuffer(bearing, buf); + writeStringToBuffer(StrX, buf); + writeStringToBuffer(StrY, buf); + writeStringToBuffer(StrZ, buf); + } + + @Override + public boolean handle(AWrapperWorld world, EntityVehicleF_Physics vehicle) { + if(!world.isClient()){ + if(vehicle.selectedWaypointList != null && vehicle.selectedWaypointList.size()>Integer.parseInt(opIndex)){ + InterfaceManager.packetInterface.sendToAllClients(new PacketVehicleWaypointUpdate(vehicle,operation,opIndex,index,name,targetSpeed,bearing,StrX,StrY,StrZ)); + }else{ + InterfaceManager.packetInterface.sendToAllClients(new PacketVehicleWaypointUpdate(vehicle,"REMOVE",opIndex,index,"null","0.0","0.0","0.0","0.0","0.0")); + } + } + + + return true; + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdate.java b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdate.java new file mode 100644 index 000000000..cdf672dbf --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdate.java @@ -0,0 +1,65 @@ +package minecrafttransportsimulator.packets.instances; + +import io.netty.buffer.ByteBuf; +import minecrafttransportsimulator.baseclasses.NavWaypoint; +import minecrafttransportsimulator.baseclasses.NavWaypointUpdater; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.packets.components.APacketBase; +/** + * Update waypoint from client to server + */ +public class PacketWaypointUpdate extends APacketBase { + + + public final String index; + public final String name; + public final String targetSpeed; + public final String bearing; + public final String positionX; + public final String positionY; + public final String positionZ; + public final String isDeleted; + + public PacketWaypointUpdate(String waypointIndex,String waypointName, String targetSpeedStr, String bearingStr, String xStr, String yStr, String zStr, String Deleted) { + super(null); + this.index = waypointIndex; + this.name = waypointName; + this.targetSpeed = targetSpeedStr; + this.bearing = bearingStr; + this.positionX = xStr; + this.positionY = yStr; + this.positionZ = zStr; + this.isDeleted = Deleted; + } + + public PacketWaypointUpdate(ByteBuf buf) { + super(buf); + this.index = readStringFromBuffer(buf); + this.name = readStringFromBuffer(buf); + this.targetSpeed = readStringFromBuffer(buf); + this.bearing = readStringFromBuffer(buf); + this.positionX = readStringFromBuffer(buf); + this.positionY = readStringFromBuffer(buf); + this.positionZ = readStringFromBuffer(buf); + this.isDeleted = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(index, buf); + writeStringToBuffer(name, buf); + writeStringToBuffer(targetSpeed, buf); + writeStringToBuffer(bearing, buf); + writeStringToBuffer(positionX, buf); + writeStringToBuffer(positionY, buf); + writeStringToBuffer(positionZ, buf); + writeStringToBuffer(isDeleted, buf); + } + + @Override + public void handle(AWrapperWorld world) { + NavWaypointUpdater waypointUpdater = new NavWaypointUpdater(NavWaypoint.getByIndexFromWorld(world,index)); + waypointUpdater.updateStateFromWorld(world,index,name,targetSpeed,bearing,positionX,positionY,positionZ,isDeleted); + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdateRequest.java b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdateRequest.java new file mode 100644 index 000000000..d25e4a4bb --- /dev/null +++ b/mccore/src/main/java/minecrafttransportsimulator/packets/instances/PacketWaypointUpdateRequest.java @@ -0,0 +1,58 @@ +package minecrafttransportsimulator.packets.instances; + +import io.netty.buffer.ByteBuf; +import minecrafttransportsimulator.baseclasses.NavWaypoint; +import minecrafttransportsimulator.baseclasses.NavWaypointUpdater; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; +import minecrafttransportsimulator.mcinterface.IWrapperPlayer; +import minecrafttransportsimulator.mcinterface.InterfaceManager; +import minecrafttransportsimulator.packets.components.APacketBase; +import minecrafttransportsimulator.packets.components.APacketPlayer; + +/** + * Request waypoint update from client to server + * + */ +public class PacketWaypointUpdateRequest extends APacketBase { + + public final String index; + + public PacketWaypointUpdateRequest(String waypointName) { + super(null); + this.index = waypointName; + } + + public PacketWaypointUpdateRequest(ByteBuf buf) { + super(buf); + this.index = readStringFromBuffer(buf); + } + + @Override + public void writeToBuffer(ByteBuf buf) { + super.writeToBuffer(buf); + writeStringToBuffer(index, buf); + } + + @Override + public void handle(AWrapperWorld world) { + if(world.isClient()==false) { + if (NavWaypoint.getByIndexFromWorld(world, index) != null) { + NavWaypointUpdater waypointUpdater = new NavWaypointUpdater(NavWaypoint.getByIndexFromWorld(world, index)); + NavWaypoint currentWaypoint = waypointUpdater.currentWaypoint; + InterfaceManager.packetInterface.sendToAllClients(new PacketWaypointUpdate( + currentWaypoint.index, + currentWaypoint.name, + Double.toString(currentWaypoint.targetSpeed), + Double.toString(currentWaypoint.bearing), + Double.toString(currentWaypoint.position.x), + Double.toString(currentWaypoint.position.y), + Double.toString(currentWaypoint.position.z), + "false" + ) + ); + } else { + InterfaceManager.packetInterface.sendToAllClients(new PacketWaypointUpdate(index, "null", "0.0", "0.0", "0.0", "0.0", "0.0", "true")); + } + } + } +} diff --git a/mccore/src/main/java/minecrafttransportsimulator/systems/ControlSystem.java b/mccore/src/main/java/minecrafttransportsimulator/systems/ControlSystem.java index d0371b9b6..850915d75 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/systems/ControlSystem.java +++ b/mccore/src/main/java/minecrafttransportsimulator/systems/ControlSystem.java @@ -17,8 +17,10 @@ import minecrafttransportsimulator.guis.components.AGUIBase; import minecrafttransportsimulator.guis.instances.GUIPanel; import minecrafttransportsimulator.guis.instances.GUIRadio; +import minecrafttransportsimulator.guis.instances.GUIWaypointManager; import minecrafttransportsimulator.jsondefs.JSONConfigClient.ConfigJoystick; import minecrafttransportsimulator.jsondefs.JSONConfigClient.ConfigKeyboard; +import minecrafttransportsimulator.mcinterface.AWrapperWorld; import minecrafttransportsimulator.mcinterface.IWrapperPlayer; import minecrafttransportsimulator.mcinterface.InterfaceManager; import minecrafttransportsimulator.packets.instances.PacketEntityCameraChange; @@ -100,8 +102,21 @@ public static void controlGlobal(IWrapperPlayer player) { if (playerGun != null && playerGun.activeGun != null && !InterfaceManager.clientInterface.isGUIOpen() && ControlsKeyboard.GENERAL_RELOAD.isPressed()) { InterfaceManager.packetInterface.sendToServer(new PacketPartGun(playerGun.activeGun, PacketPartGun.Request.RELOAD_HAND)); } + + if(player.getEntityRiding() == null)ControlSystem.controlWaypoint(player,null); } + public static void controlWaypoint(IWrapperPlayer player, EntityVehicleF_Physics vehicle) { + if (!InterfaceManager.clientInterface.isGUIOpen() && ControlsKeyboard.GENERAL_WAYPOINT_MANAGER.isPressed()) { + if (AGUIBase.activeInputGUI instanceof GUIPanel && !AGUIBase.activeInputGUI.editingText) { + AGUIBase.activeInputGUI.close(); + } else if (!InterfaceManager.clientInterface.isGUIOpen()) { + new GUIWaypointManager(player,vehicle); + } + } + } + + private static void handleClick(IWrapperPlayer player, EntityPlayerGun playerGun, boolean leftClickDown, boolean leftClickUp, boolean rightClickDown, boolean rightClickUp) { //Either change the gun trigger state (if we are holding a gun), //or try to interact with entities if we are not. @@ -334,6 +349,9 @@ private static void controlAircraft(EntityVehicleF_Physics aircraft, boolean isP //Open or close the panel. controlPanel(aircraft, ControlsKeyboard.AIRCRAFT_PANEL); + //Open or close waypointManager + controlWaypoint(clientPlayer,aircraft); + //Check brake status. controlBrake(aircraft, ControlsJoystick.AIRCRAFT_BRAKE, ControlsJoystick.AIRCRAFT_BRAKE_DIGITAL, ControlsKeyboard.AIRCRAFT_BRAKE, ControlsKeyboard.AIRCRAFT_PARK); @@ -688,6 +706,7 @@ public enum ControlsKeyboard { GENERAL_CUSTOM3(ControlsJoystick.GENERAL_CUSTOM3, true, "NUMPAD2", LanguageSystem.INPUT_CUSTOM3), GENERAL_CUSTOM4(ControlsJoystick.GENERAL_CUSTOM4, true, "NUMPAD3", LanguageSystem.INPUT_CUSTOM4), GENERAL_RELOAD(ControlsJoystick.GENERAL_RELOAD, true, "R", LanguageSystem.INPUT_GUN_RELOAD), + GENERAL_WAYPOINT_MANAGER(ControlsJoystick.GENERAL_WAYPOINT_MANAGER, true, "5", LanguageSystem.INPUT_WAYPOINT_MANAGER), AIRCRAFT_YAW_R(ControlsJoystick.AIRCRAFT_YAW, false, "L", LanguageSystem.INPUT_YAW_R), AIRCRAFT_YAW_L(ControlsJoystick.AIRCRAFT_YAW, false, "J", LanguageSystem.INPUT_YAW_L), @@ -791,6 +810,7 @@ public enum ControlsJoystick { GENERAL_CUSTOM3(false, true, LanguageSystem.INPUT_CUSTOM3), GENERAL_CUSTOM4(false, true, LanguageSystem.INPUT_CUSTOM4), GENERAL_RELOAD(false, true, LanguageSystem.INPUT_GUN_RELOAD), + GENERAL_WAYPOINT_MANAGER(false, true, LanguageSystem.INPUT_WAYPOINT_MANAGER), AIRCRAFT_CAMLOCK(false, true, LanguageSystem.INPUT_CAMLOCK), AIRCRAFT_YAW(true, false, LanguageSystem.INPUT_YAW), diff --git a/mccore/src/main/java/minecrafttransportsimulator/systems/LanguageSystem.java b/mccore/src/main/java/minecrafttransportsimulator/systems/LanguageSystem.java index 851772d70..3850a99b7 100644 --- a/mccore/src/main/java/minecrafttransportsimulator/systems/LanguageSystem.java +++ b/mccore/src/main/java/minecrafttransportsimulator/systems/LanguageSystem.java @@ -518,6 +518,7 @@ public static class JSONLanguageFile { public static final LanguageEntry INPUT_GUN_FIRE = new LanguageEntry("input.gun_fire", "Gun"); public static final LanguageEntry INPUT_GUN_SWITCH = new LanguageEntry("input.gun_switch", "Switch Gun"); public static final LanguageEntry INPUT_GUN_RELOAD = new LanguageEntry("input.gun.reload", "Reload Gun"); + public static final LanguageEntry INPUT_WAYPOINT_MANAGER = new LanguageEntry("input.waypoint.manager", "Manage Waypoints"); public static final LanguageEntry INPUT_RADIO = new LanguageEntry("input.radio", "Radio"); public static final LanguageEntry INPUT_ZOOM_I = new LanguageEntry("input.zoom_i", "ZoomIn"); public static final LanguageEntry INPUT_ZOOM_O = new LanguageEntry("input.zoom_o", "ZoomOut");