/** * Copyright (c) 2008-2024, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved. * This work is provided under a BSD open-source license, see project license.html or license.txt * * This main class is my submission for HW 3. * * @author ethanjwilliams */ package MV3500Cohort2024JulySeptember.homework3.Williams; import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon; import edu.nps.moves.dis7.entities.swe.platform.surface._002Triton; import edu.nps.moves.dis7.enumerations.*; import edu.nps.moves.dis7.pdus.*; import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.PduFactory; import java.time.LocalDateTime; import java.util.logging.Level; import java.util.logging.Logger; /** * The purpose of this inheritable class is to provide an easily modifiable * example simulation program that includes DIS-capable entities performing * tasks of interest, and then reporting activity via PDUs to the network. * Default program initialization includes PDU recording turned on by default. * * Homework 3 networking choices: * This simulation uses UDP multicast for efficient distribution of PDUs to * multiple participants, which is great for large-scale simulations where * state updates need to reach all networked participants. UDP is chosen over * TCP due to its lower latency, which is essential for real-time simulations. * * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramLog.txt" target="_blank">ExampleSimulationProgramLog.txt</a> * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramPduCaptureLog.dislog" target="_blank">ExampleSimulationProgramPduCaptureLog.dislog</a> * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramFlowDiagram.pdf" target="_blank">ExampleSimulationProgramFlowDiagram.pdf</a> * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramWireshark.png" target="_blank">ExampleSimulationProgramWireshark.png</a> * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramSequenceDiagram.png" target="_blank">ExampleSimulationProgramSequenceDiagram.png</a> */ public class ExampleSimulationProgram { private String descriptor = this.getClass().getSimpleName(); protected DisChannel disChannel; protected PduFactory pduFactory; private double simulationTimeStepDuration = 1.0; double simulationTimeInitial = 0.0; double simulationTimeSeconds = simulationTimeInitial; int MAX_LOOP_COUNT = 4; String narrativeMessage1 = new String(); String narrativeMessage2 = new String(); String narrativeMessage3 = new String(); protected EntityID entityID_1 = new EntityID(); protected EntityID entityID_2 = new EntityID(); protected EntityStatePdu entityStatePdu_1; protected EntityStatePdu entityStatePdu_2; protected FirePdu firePdu_1a; protected FirePdu firePdu_1b; protected MunitionDescriptor munitionDescriptor1; public ExampleSimulationProgram() { initialize(); } public ExampleSimulationProgram(String newDescriptor) { descriptor = newDescriptor; initialize(); } public ExampleSimulationProgram(String address, int port) { disChannel.setNetworkAddress(address); disChannel.setNetworkPort(port); disChannel.setVerboseComments(true); disChannel.setVerboseDisNetworkInterface(true); disChannel.setVerbosePduRecorder(true); initialize(); } private void initialize() { initializeDisChannel(); initializeSimulationEntities(); disChannel.join(); String timeStepMessage = "Simulation timestep duration " + getSimulationTimeStepDuration() + " seconds"; disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_SIMULATION_TIMESTEP, timeStepMessage); } private void initializeDisChannel() { if (disChannel == null) disChannel = new DisChannel(); else { disChannel.printlnTRACE ("*** warning, duplicate invocation of initializeDisChannel() ignored"); return; } pduFactory = disChannel.getPduFactory(); disChannel.setDescriptor(this.getClass().getSimpleName()); disChannel.setUpNetworkInterface(); disChannel.printlnTRACE ("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress() + ", getNetworkPort()=" + disChannel.getNetworkPort()); disChannel.getDisNetworkInterface().setVerbose(true); disChannel.printlnTRACE ("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending() + ", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt()); disChannel.getPduRecorder().setVerbose(true); } public void initializeSimulationEntities() { if (pduFactory == null) pduFactory = disChannel.getPduFactory(); entityStatePdu_1 = pduFactory.makeEntityStatePdu(); entityStatePdu_2 = pduFactory.makeEntityStatePdu(); firePdu_1a = pduFactory.makeFirePdu(); firePdu_1b = pduFactory.makeFirePdu(); munitionDescriptor1 = new MunitionDescriptor(); entityID_1.setSiteID((int)(Math.random() * 100)) .setApplicationID((int)(Math.random() * 100)) .setEntityID((int)(Math.random() * 100)); disChannel.addEntity(entityID_1); entityID_2.setSiteID((int)(Math.random() * 100)) .setApplicationID((int)(Math.random() * 100)) .setEntityID((int)(Math.random() * 100)); disChannel.addEntity(entityID_2); entityStatePdu_1.setEntityID(entityID_1); entityStatePdu_1.setForceId(ForceID.FRIENDLY); entityStatePdu_1.setEntityType(new _001Poseidon()); entityStatePdu_1.setMarking("Ethan's Poseidon #1"); entityStatePdu_2.setEntityID(entityID_2); entityStatePdu_2.setForceId(ForceID.OPPOSING); entityStatePdu_2.setEntityType(new _002Triton()); entityStatePdu_2.setMarking("Ethan's Triton #2"); munitionDescriptor1.setQuantity(1); firePdu_1a.setDescriptor(munitionDescriptor1).setRange(1000.0f); } @SuppressWarnings("SleepWhileInLoop") public void runSimulationLoops () { try { final int SIMULATION_MAX_LOOP_COUNT = 10; int simulationLoopCount = 0; boolean simulationComplete = false; String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now(); disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage); while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) { simulationLoopCount++; entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + (Math.random() * 2)); System.out.println ("... My simulation just did something..."); System.out.flush(); narrativeMessage1 = "Ethan's Custom Simulation Program"; narrativeMessage2 = "Loop " + simulationLoopCount + " - MV3500 Custom Version"; narrativeMessage3 = "Simulation developed by Ethan Williams"; if (simulationLoopCount > MAX_LOOP_COUNT) { simulationComplete = true; } Thread.sleep((long)(getSimulationTimeStepDuration() * 1000)); System.out.println ("... [Pausing for " + getSimulationTimeStepDuration() + " seconds]"); sendAllPdusForLoopTimestep(simulationTimeSeconds, entityStatePdu_1, firePdu_1a, DisChannel.COMMENTPDU_APPLICATION_STATUS, narrativeMessage1, narrativeMessage2); disChannel.sendSinglePdu(simulationTimeSeconds, entityStatePdu_2); System.out.println ("... [PDUs of interest successfully sent for this loop]"); System.out.flush(); if (simulationComplete || (simulationLoopCount > 10000)) { System.out.println ("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); System.out.flush(); break; } simulationTimeSeconds += getSimulationTimeStepDuration(); } narrativeMessage2 = "runSimulation() completed successfully"; disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); System.out.println ("... [final=completion CommentPdu successfully sent for simulation]"); disChannel.leave(); } catch (InterruptedException iex) { Logger.getLogger(ExampleSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex); } } public void sendAllPdusForLoopTimestep(double simTimeSeconds, EntityStatePdu entityStatePdu, FirePdu firePdu, VariableRecordType commentType, String... comments) { if (entityStatePdu != null) disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu); if (firePdu != null) disChannel.sendSinglePdu(simTimeSeconds, firePdu); disChannel.sendCommentPdu(simTimeSeconds, commentType, comments); } protected void handleArguments (String[] args) { if (args.length == 2) { if ((args[0] != null) && !args[0].isEmpty()) thisProgram.disChannel.setNetworkAddress(args[0]); if ((args[1] != null) && !args[1].isEmpty()) thisProgram.disChannel.setNetworkPort(Integer.parseInt(args[1])); } else if (args.length != 0) { System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]"); System.exit(-1); } } public String getDescriptor() { return descriptor; } public void setDescriptor(String newDescriptor) { if (newDescriptor == null) newDescriptor = ""; this.descriptor = newDescriptor; } public double getSimulationTimeStepDuration() { return simulationTimeStepDuration; } public void setSimulationTimeStepDuration(double timeStepDurationSeconds) { this.simulationTimeStepDuration = timeStepDurationSeconds; } protected static ExampleSimulationProgram thisProgram; public static void main(String[] args) { thisProgram = new ExampleSimulationProgram("test constructor"); thisProgram.disChannel.printlnTRACE("main() started..."); thisProgram.handleArguments(args); thisProgram.runSimulationLoops(); thisProgram.disChannel.tearDownNetworkInterface(); thisProgram.disChannel.printlnTRACE("complete."); System.exit(0); } }