/** * 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; import java.util.logging.Level; import java.util.logging.Logger; 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. Constructor is not currently needed. } /** * 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(); } /** * Programmer-modifiable method for defining and running a new simulation of interest. * Support include DIS EntityStatePdu, FirePdu and CommentPdu all available for * modification and sending in a simulation loop. */ @SuppressWarnings("SleepWhileInLoop") public void runSimulation () { try { final double LOOP_DURATION_SECONDS = 1.0; // seconds final int MAX_LOOP_COUNT = 10; int loopCount = 0; VariableRecordType narrativeType = VariableRecordType.OTHER; // of potential use boolean simulationComplete = false; // sentinel variable as termination condition // TODO reset clock to zero each time for consistent outputs. // your model setup: who's who in this zoo? // create PDU objects and set their values EntityID entityID_1 = new EntityID(); entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID EntityStatePdu entityStatePdu = pduFactory.makeEntityStatePdu(); entityStatePdu.setEntityID(entityID_1); FirePdu firePdu = pduFactory.makeFirePdu(); // should we customize this munition? what is it for your simulation? while (loopCount < MAX_LOOP_COUNT) // loop the simulation while allowed, can set additional conditions to break { String narrativeMessage1, narrativeMessage2, narrativeMessage3; // initialize loop variables loopCount++; // ============================================================================================= // your own simulation code starts here! // compute a track, update an ESPDU, whatever it is that your model is doing... // Where is my entity? entityStatePdu.getEntityLocation().setX(entityStatePdu.getEntityLocation().getX() + 1.0); // 1m per timestep // decide whether to fire, and then update the firePdu. Hmmm, you might want a target to shoort at! // etc. etc. your code goes here // make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending) narrativeMessage1 = "MV3500 ExampleSimulationProgram"; narrativeMessage2 = "runSimulation() loop " + loopCount; narrativeMessage3 = ""; // intentionally blank for testing // your loop termination condition goes here if (loopCount > 4) // for example { simulationComplete = true; } // your own simulation code is finished here! // ============================================================================================= // keep track of timestep: wait duration for elapsed time in this loop // Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes Thread.sleep((long)(LOOP_DURATION_SECONDS * 1000)); // seconds * (1000 msec/sec) = milliseconds System.out.println ("... Pausing for " + LOOP_DURATION_SECONDS + " seconds"); // send the status PDUs for this loop and continue 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"); // =============================== // loop now finished, thus terminate if simulation complete, otherwise send latest PDUs and continue if (simulationComplete || (loopCount > 10000)) // for example; including fail-safe condition is good { System.out.println ("... Termination condition met, simulationComplete=" + simulationComplete); break; } } // end of while loop } catch (Exception ex) // handle any exception that your code might choose to provoke! { Logger.getLogger(ExampleSimulationProgram.class.getName()).log(Level.SEVERE, null, ex); } } }