diff --git a/examples/src/OpenDis7Examples/ExampleSimulationProgram.java b/examples/src/OpenDis7Examples/ExampleSimulationProgram.java new file mode 100644 index 0000000000000000000000000000000000000000..e3bb082c56cd61ddb60dca80a197698962690543 --- /dev/null +++ b/examples/src/OpenDis7Examples/ExampleSimulationProgram.java @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2008-2020, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved. + * This work is provided under a BSD open-source license, see project license.html and license.txt + */ +package OpenDis7Examples; + +import edu.nps.moves.dis7.enumerations.VariableRecordType; +import edu.nps.moves.dis7.pdus.CommentPdu; +import edu.nps.moves.dis7.pdus.EntityID; +import edu.nps.moves.dis7.pdus.EntityStatePdu; +import edu.nps.moves.dis7.pdus.FirePdu; +import edu.nps.moves.dis7.pdus.Pdu; +import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface; +import edu.nps.moves.dis7.utilities.PduFactory; +import java.util.ArrayList; + +public class ExampleSimulationProgram +{ + // class variables + PduFactory pduFactory = new PduFactory(); + DisThreadedNetworkInterface disNetworkInterface; + DisThreadedNetworkInterface.PduListener pduListener; + Pdu receivedPdu; + + private String networkAddress = "239.1.2.3"; + private int networkPort = 3000; + + /** + * Constructor design goal: additional built-in initialization conveniences can go here + * to keep student efforts focused on the runSimulation() method. + */ + public ExampleSimulationProgram() + { + // Under consideration. + } + + /** + * Utility Constructor + * @param address network address to use + * @param port corresponding network port to use + */ + public ExampleSimulationProgram(String address, int port) + { + setNetworkAddress(address); + + setNetworkPort(port); + } + + /** + * @return the networkAddress + */ + public String getNetworkAddress() + { + return networkAddress; + } + + /** + * @param networkAddress the networkAddress to set + */ + public final void setNetworkAddress(String networkAddress) + { + this.networkAddress = networkAddress; + } + + /** + * @return the networkPort + */ + public int getNetworkPort() + { + return networkPort; + } + + /** + * @param networkPort the networkPort to set + */ + public final void setNetworkPort(int networkPort) + { + this.networkPort = networkPort; + } + + /** + * Initialize network interface, choosing best available network interface + */ + public void setUpNetworkInterface() + { + disNetworkInterface = new DisThreadedNetworkInterface(getNetworkAddress(), getNetworkPort()); + + System.out.println("Network confirmation: address=" + disNetworkInterface.getMcastGroup() + " port=" + disNetworkInterface.getDisPort()); + pduListener = new DisThreadedNetworkInterface.PduListener() + { + /** Callback handler for listener */ + @Override + public void incomingPdu(Pdu newPdu) + { + receivedPdu = newPdu; + } + }; + disNetworkInterface.addListener(pduListener); + } + + /** All done, release network resources */ + public void tearDownNetworkInterface() + { + disNetworkInterface.removeListener(pduListener); + disNetworkInterface.kill(); + disNetworkInterface = null; + } + + /** + * Send a single Protocol Data Unit (PDU) of any type + * @param pdu the pdu to send + */ + private void sendSinglePdu(Pdu pdu) + { + try + { + disNetworkInterface.send(pdu); + Thread.sleep(100); // TODO consider refactoring the wait logic and moving externally + } + catch (InterruptedException ex) + { + System.err.println(this.getClass().getName() + " Error sending PDU: " + ex.getLocalizedMessage()); + System.exit(1); + } + } + + /** + * Send EntityState, Fire, Comment PDUs + * @see <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html">Passing Information to a Method or a Constructor</a> Arbitrary Number of Arguments + * @param entityStatePdu the ESPDU to send, if any + * @param firePdu the FirePDU to send, if any + * @param commentType enumeration value describing the narrative comment + * @param comments String array of narrative comments + */ + public void sendAllPdus(EntityStatePdu entityStatePdu, + FirePdu firePdu, + VariableRecordType commentType, + // vararg... variable length string + String... comments) + { + if (entityStatePdu != null) + sendSinglePdu(entityStatePdu); + + if (firePdu != null) + sendSinglePdu(firePdu); // bang + + if ((comments != null) && (comments.length > 0)) + { + ArrayList<String> newCommentsList = new ArrayList<>(); + for (int i = 0; i < comments.length; i++) + { + if (!comments[i].isEmpty()) + newCommentsList.add(comments[i]); // OK found something to send + } + if (!newCommentsList.isEmpty()) + { + if (commentType == null) + commentType = VariableRecordType.OTHER; + CommentPdu commentPdu = pduFactory.makeCommentPdu(commentType, newCommentsList.toArray(new String[0])); // comments); + sendSinglePdu(commentPdu); + } + } + } + + /** + * Main method is first executed when a program instance is loaded. + * @see <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html">Java Tutorials: A Closer Look at the "Hello World!" Application</a> + * @param args command-line arguments are an array of optional String parameters that are passed from execution environment during invocation + */ + public static void main(String[] args) + { + ExampleSimulationProgram thisProgram = new ExampleSimulationProgram(); // creates instance + + // initial execution: can handle args array of initialization arguments here + if (args.length == 2) + { + if ((args[0] != null) && !args[0].isEmpty()) + thisProgram.setNetworkAddress(args[0]); + + if ((args[1] != null) && !args[1].isEmpty()) + thisProgram.setNetworkPort(Integer.parseInt(args[1])); + } + else if (args.length != 0) + { + System.err.println("Usage: " + thisProgram.getClass().getName() + " [address port]"); + System.exit(-1); + } + // OK here we go... + + thisProgram.setUpNetworkInterface(); + + thisProgram.runSimulation (); // customization code goes in there + + thisProgram.tearDownNetworkInterface(); + } + + /** + * User-modifiable method for defining and running a simulation. + */ + public void runSimulation () + { + final int MAX_LOOP_COUNT = 10; + int loopCount = 0; + VariableRecordType narrativeType = VariableRecordType.OTHER; + boolean simulationComplete = false; // termination condition + + // model setup + EntityID entityID_1 = new EntityID(); + entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); + + EntityStatePdu entityStatePdu = pduFactory.makeEntityStatePdu(); + entityStatePdu.setEntityID(entityID_1); + + FirePdu firePdu = pduFactory.makeFirePdu(); + + while (loopCount < MAX_LOOP_COUNT) // loop while allowed, can set additional conditions to break + { + String narrativeMessage1, narrativeMessage2, narrativeMessage3; + // initialize loop variables + loopCount++; + + // =============================== + // your own simulation code here! + + + + + // your narrative code for CommentPdu here, set all to empty strings to avoid sending + narrativeMessage1 = "MV3500 ExampleSimulation"; + narrativeMessage2 = "runSimulation loop " + loopCount; + narrativeMessage3 = ""; // intentionally blank for testing + + // =============================== + // your loop termination condition + if (loopCount > 4) // for example + { + simulationComplete = true; + System.out.println ("*** termination condition met, simulationComplete=" + simulationComplete); + } + // loop now finished so terminate if simulation complete, otherwise send latest PDUs and continue + if (simulationComplete) + break; + System.out.println ("sending PDUs for simulation step " + loopCount + ", monitor loopback to confirm sent"); + sendAllPdus(entityStatePdu, firePdu, null, narrativeMessage1, narrativeMessage2, narrativeMessage3); + System.out.println ("... PDUs successfully sent"); + } + } +}