Skip to content
Snippets Groups Projects
Commit 71d7008a authored by tbavl's avatar tbavl
Browse files

Bavlsik Assignment 3

parent da692916
No related branches found
No related tags found
No related merge requests found
/** /**
* Copyright (c) 2008-2023, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved. * Copyright (c) 2008-2023, 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 work is provided under a BSD open-source license, see project license.html or license.txt
*
* @author brutzman@nps.edu * @author brutzman@nps.edu
* @author timothy.bavlsik@nps.edu
*/ */
package MV3500Cohort2024JulySeptember.homework3.Bavlsik; package MV3500Cohort2024JulySeptember.homework3.Bavlsik;
...@@ -12,156 +14,194 @@ import edu.nps.moves.dis7.pdus.*; ...@@ -12,156 +14,194 @@ import edu.nps.moves.dis7.pdus.*;
import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.DisChannel;
import edu.nps.moves.dis7.utilities.PduFactory; import edu.nps.moves.dis7.utilities.PduFactory;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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 * This program runs a simulation that initializes two entities, of which one will
* tasks of interest, and then reporting activity via PDUs to the network. * attempt to find and destroy the other, and one which will flee the other entity.
* Default program initialization includes PDU recording turned on by default. * Default program initialization includes PDU recording turned on by default.
* @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
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramFlowDiagram.pdf" target="_blank">ExampleSimulationProgramFlowDiagram.pdf</a> * <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/ExampleSimulationProgramWireshark.png" target="_blank">ExampleSimulationProgramWireshark.png</a> * @see
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramSequenceDiagram.png" target="_blank">ExampleSimulationProgramSequenceDiagram.png</a> * <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 BavlsikSimulationProgram public class BavlsikSimulationProgram {
{
/* **************************** infrastructure code, modification is seldom needed ************************* */ /* **************************** infrastructure code, modification is seldom needed ************************* */
private String descriptor = this.getClass().getSimpleName(); private String descriptor = this.getClass().getSimpleName();
/** DIS channel defined by network address/port combination includes multiple utility capabilities */ /**
* DIS channel defined by network address/port combination includes multiple
* utility capabilities
*/
protected DisChannel disChannel; protected DisChannel disChannel;
/** Factory object used to create new PDU instances */ /**
* Factory object used to create new PDU instances
*/
protected PduFactory pduFactory; protected PduFactory pduFactory;
/** seconds per loop for real-time or simulation execution */ /**
private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate * seconds per loop for real-time or simulation execution
/** initial simulation time in seconds */ */
double simulationTimeInitial = 0.0; private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate
/** current simulation time in seconds */ /**
double simulationTimeSeconds = simulationTimeInitial; * initial simulation time in seconds
/** Maximum number of simulation loops */ */
double simulationTimeInitial = 0.0;
/**
* current simulation time in seconds
*/
double simulationTimeSeconds = simulationTimeInitial;
/**
* Maximum number of simulation loops
*/
int MAX_LOOP_COUNT = 4; int MAX_LOOP_COUNT = 4;
String narrativeMessage1 = new String(); String narrativeMessage1 = new String();
String narrativeMessage2 = new String(); String narrativeMessage2 = new String();
String narrativeMessage3 = new String(); String narrativeMessage3 = new String();
/** EntityID settings for entity 1 */ /**
protected EntityID entityID_1 = new EntityID(); * EntityID settings for entity 1
/** EntityID settings for entity 2 */ */
protected EntityID entityID_2 = new EntityID(); protected EntityID entityID_1 = new EntityID();
/** ESPDU for entity 1 */ /**
protected EntityStatePdu entityStatePdu_1; * EntityID settings for entity 2
/** ESPDU for entity 2 */ */
protected EntityStatePdu entityStatePdu_2; protected EntityID entityID_2 = new EntityID();
/** FirePdu for entity 1 first weapon (if any) */ /**
protected FirePdu firePdu_1a; * ESPDU for entity 1
/** FirePdu for entity 1 second weapon (if any) */ */
protected FirePdu firePdu_1b; protected EntityStatePdu entityStatePdu_1;
/** MunitionDescriptor for these weapons */ /**
* ESPDU for entity 2
*/
protected EntityStatePdu entityStatePdu_2;
/**
* FirePdu for entity 1 first weapon (if any)
*/
protected FirePdu firePdu_1a;
/**
* FirePdu for entity 1 second weapon (if any)
*/
protected FirePdu firePdu_1b;
/**
* MunitionDescriptor for these weapons
*/
protected MunitionDescriptor munitionDescriptor1; protected MunitionDescriptor munitionDescriptor1;
// hey programmer, what other state do you want? this is a good place to declare it... // hey programmer, what other state do you want? this is a good place to declare it...
/** /**
* Constructor to create an instance of this class. * Constructor to create an instance of this class. Design goal: additional
* Design goal: additional built-in initialization conveniences can go here * built-in initialization conveniences can go here to keep your efforts
* to keep your efforts focused on the runSimulation() method. * focused on the runSimulation() method.
*/ */
// base constructor is not invoked automatically by other constructors // base constructor is not invoked automatically by other constructors
// https://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java // https://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java
public BavlsikSimulationProgram() public BavlsikSimulationProgram() {
{
initialize(); initialize();
} }
/** /**
* Constructor to create an instance of this class. * Constructor to create an instance of this class.
* @param newDescriptor describes this program, useful for logging and debugging *
* @param newDescriptor describes this program, useful for logging and
* debugging
*/ */
public BavlsikSimulationProgram(String newDescriptor) public BavlsikSimulationProgram(String newDescriptor) {
{
descriptor = newDescriptor; descriptor = newDescriptor;
initialize(); initialize();
} }
/** /**
* Utility Constructor that allows your example simulation program to override default network address and port * Utility Constructor that allows your example simulation program to
* override default network address and port
*
* @param address network address to use * @param address network address to use
* @param port corresponding network port to use * @param port corresponding network port to use
*/ */
public BavlsikSimulationProgram(String address, int port) public BavlsikSimulationProgram(String address, int port) {
{ disChannel.setNetworkAddress(address);
disChannel.setNetworkAddress (address); disChannel.setNetworkPort(port);
disChannel.setNetworkPort (port); disChannel.setVerboseComments(true); // TODO rename library method to disambiguate CommentPDU
disChannel.setVerboseComments (true); // TODO rename library method to disambiguate CommentPDU // TODO still seems really chatty... add silent mode?
// TODO still seems really chatty... add silent mode?
disChannel.setVerboseDisNetworkInterface(true); // Default false disChannel.setVerboseDisNetworkInterface(true); // Default false
disChannel.setVerbosePduRecorder (true); // default false disChannel.setVerbosePduRecorder(true); // default false
initialize(); initialize();
} }
/** Initialize channel setup for OpenDis7 and report a test PDU /**
* Initialize channel setup for OpenDis7 and report a test PDU
*
* @see initializeDisChannel * @see initializeDisChannel
* @see initializeSimulationEntities */ * @see initializeSimulationEntities
private void initialize() */
{ private void initialize() {
initializeDisChannel(); // must come first, uses PduFactory initializeDisChannel(); // must come first, uses PduFactory
initializeSimulationEntities(); // set unchanging parameters initializeSimulationEntities(); // set unchanging parameters
disChannel.join(); // TODO further functionality expected disChannel.join(); // TODO further functionality expected
String timeStepMessage = "Simulation timestep duration " + getSimulationTimeStepDuration() + " seconds"; String timeStepMessage = "Simulation timestep duration " + getSimulationTimeStepDuration() + " seconds";
disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_SIMULATION_TIMESTEP, timeStepMessage); disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_SIMULATION_TIMESTEP, timeStepMessage);
// additional constructor initialization can go here // additional constructor initialization can go here
} }
/** Initialize channel setup for OpenDis7 and report a test PDU */ /**
private void initializeDisChannel() * Initialize channel setup for OpenDis7 and report a test PDU
{ */
if (disChannel == null) private void initializeDisChannel() {
if (disChannel == null) {
disChannel = new DisChannel(); disChannel = new DisChannel();
else } else {
{ disChannel.printlnTRACE("*** warning, duplicate invocation of initializeDisChannel() ignored");
disChannel.printlnTRACE ("*** warning, duplicate invocation of initializeDisChannel() ignored");
return; return;
} }
pduFactory = disChannel.getPduFactory(); pduFactory = disChannel.getPduFactory();
disChannel.setDescriptor(this.getClass().getSimpleName()); // ExampleSimulationProgram might be a superclass disChannel.setDescriptor(this.getClass().getSimpleName()); // ExampleSimulationProgram might be a superclass
disChannel.setUpNetworkInterface(); disChannel.setUpNetworkInterface();
disChannel.printlnTRACE ("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress() + disChannel.printlnTRACE("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress()
", getNetworkPort()=" + disChannel.getNetworkPort()); + ", getNetworkPort()=" + disChannel.getNetworkPort());
disChannel.getDisNetworkInterface().setVerbose(true); // sending and receipt disChannel.getDisNetworkInterface().setVerbose(false); // sending and receipt
disChannel.printlnTRACE ("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending() + disChannel.printlnTRACE("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending()
", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt()); + ", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt());
disChannel.getPduRecorder().setVerbose(true); disChannel.getPduRecorder().setVerbose(false);
// TODO confirm whether recorder is explicitly started by programmer (or not) // TODO confirm whether recorder is explicitly started by programmer (or not)
// disChannel.sendCommentPdu(VariableRecordType.OTHER, "DisThreadedNetworkInterface.initializeDisChannel() complete"); // hello channel, debug // disChannel.sendCommentPdu(VariableRecordType.OTHER, "DisThreadedNetworkInterface.initializeDisChannel() complete"); // hello channel, debug
} }
/** Get ready, get set... initialize simulation entities. Who's who in the zoo? /**
* Get ready, get set... initialize simulation entities. Who's who in the
* zoo?
*/ */
public void initializeSimulationEntities() public void initializeSimulationEntities() {
{ if (pduFactory == null) {
if (pduFactory == null) pduFactory = disChannel.getPduFactory();
pduFactory = disChannel.getPduFactory(); }
entityStatePdu_1 = pduFactory.makeEntityStatePdu(); entityStatePdu_1 = pduFactory.makeEntityStatePdu();
entityStatePdu_2 = pduFactory.makeEntityStatePdu(); entityStatePdu_2 = pduFactory.makeEntityStatePdu();
firePdu_1a = pduFactory.makeFirePdu(); firePdu_1a = pduFactory.makeFirePdu();
firePdu_1b = pduFactory.makeFirePdu(); firePdu_1b = pduFactory.makeFirePdu();
munitionDescriptor1 = new MunitionDescriptor(); munitionDescriptor1 = new MunitionDescriptor();
// Your model setup: define participants. who's who in this zoo? // Your model setup: define participants. who's who in this zoo?
// Assuming you keep track of entity objects... here is some support for for Entity 1. // Assuming you keep track of entity objects... here is some support for for Entity 1.
// PDU objects are already declared and instances created, so now set their values. // PDU objects are already declared and instances created, so now set their values.
// who is who in our big zoo, sufficient for global participation if we need it // who is who in our big zoo, sufficient for global participation if we need it
entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID; entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID;
disChannel.addEntity(entityID_1); disChannel.addEntity(entityID_1);
entityID_2.setSiteID(1).setApplicationID(2).setEntityID(4); // made-up example ID; entityID_2.setSiteID(1).setApplicationID(2).setEntityID(4); // made-up example ID;
disChannel.addEntity(entityID_2); disChannel.addEntity(entityID_2);
// TODO someday, use enumerations for sites as part of a SimulationManager object; e.g. is there a unique site triplet for MOVES Institute? // TODO someday, use enumerations for sites as part of a SimulationManager object; e.g. is there a unique site triplet for MOVES Institute?
...@@ -178,181 +218,215 @@ public class BavlsikSimulationProgram ...@@ -178,181 +218,215 @@ public class BavlsikSimulationProgram
entityStatePdu_2.setForceId(ForceID.OPPOSING); entityStatePdu_2.setForceId(ForceID.OPPOSING);
entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above
entityStatePdu_2.setMarking("Entity #2"); entityStatePdu_2.setMarking("Entity #2");
//Initialize entity2's location to a random spot from (0,0,0) to (10,10,0)
Random random = new Random();
int randX = random.nextInt(10);
int randY = random.nextInt(10);
entityStatePdu_2.getEntityLocation().setX(randX);
entityStatePdu_2.getEntityLocation().setY(randY);
// TODO how should we customize this munition? what are key parameters for your simulation? // TODO how should we customize this munition? what are key parameters for your simulation?
// more is needed here by scenario authors... // more is needed here by scenario authors...
munitionDescriptor1.setQuantity(1); munitionDescriptor1.setQuantity(1);
firePdu_1a.setDescriptor(munitionDescriptor1).setRange(1000.0f); firePdu_1a.setDescriptor(munitionDescriptor1).setRange(3.0f);
} }
/** /**
* This runSimulationLoops() method is for you, a customizable programmer-modifiable * This runSimulationLoops() method is for you, a customizable
* code block for defining and running a new simulation of interest. * programmer-modifiable code block for defining and running a new
* * simulation of interest.
* Welcome! Other parts of this program handle bookkeeping and plumbing tasks so that *
* you can focus on your model entities and activities. * Welcome! Other parts of this program handle bookkeeping and plumbing
* Expandable support includes DIS EntityStatePdu, FirePdu and CommentPdu all available for * tasks so that you can focus on your model entities and activities.
* modification and sending in a simulation loop. * Expandable support includes DIS EntityStatePdu, FirePdu and CommentPdu
* Continuous improvement efforts seek to make this program as easy and straightforward * all available for modification and sending in a simulation loop.
* as possible for DIS simulationists to use and adapt. * Continuous improvement efforts seek to make this program as easy and
* All of the other methods are setup, teardown and configuration that you may find * straightforward as possible for DIS simulationists to use and adapt. All
* interesting, even helpful, but don't really have to worry about. * of the other methods are setup, teardown and configuration that you may
* find interesting, even helpful, but don't really have to worry about.
*/ */
@SuppressWarnings("SleepWhileInLoop") // yes we might do that @SuppressWarnings("SleepWhileInLoop") // yes we might do that
public void runSimulationLoops () public void runSimulationLoops() {
{ Random random = new Random();
try boolean killFlag = false;//updates if the hunter kills its prey.
{ try {
final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops. final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops.
int simulationLoopCount = 0; // variable, initialized at 0 int simulationLoopCount = 0; // variable, initialized at 0
boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet? boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet?
// TODO reset Clock Time for today's date and timestamp to zero, providing consistent outputs for each simulation run // TODO reset Clock Time for today's date and timestamp to zero, providing consistent outputs for each simulation run
String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now(); String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now();
disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage); disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage);
// TODO replace enumeration with disChannel.COMMENTPDU_TIME // TODO replace enumeration with disChannel.COMMENTPDU_TIME
// TODO fix VariableRecordType.TIME_AMP_DATE_VALID // TODO fix VariableRecordType.TIME_AMP_DATE_VALID
// =================================================================================================== // ===================================================================================================
// loop the simulation while allowed, programmer can set additional conditions to break out and finish // loop the simulation while allowed, programmer can set additional conditions to break out and finish
while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet? while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet?
{
simulationLoopCount++; // good practice: increment loop counter as first action in that loop
// =============================================================================================
// * your own simulation code starts here! *****************************************************
// =============================================================================================
// are there any other variables to modify at the beginning of your loop?
// are your reading any DIS PDUs from the network? check for them here
// compute a track, update an ESPDU, whatever it is that your model is doing...
// Where is my entity? Insert changes in position; this sample only changes X position.
entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + 1.0); // 1m per timestep
// decide whether to fire, and then update the firePdu. Hmmm, you might want a target to shoot at!
// etc. etc. your code goes here for your simulation of interest
// something happens between my simulation entities, la de da de da...
System.out.println ("... My simulation just did something, no really...");
System.out.flush(); // make sure this arrives to user even if other threads somehow become deadlocked
// make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending)
narrativeMessage1 = "MV3500 ExampleSimulationProgram";
narrativeMessage2 = "runSimulation() loop " + simulationLoopCount;
narrativeMessage3 = ""; // intentionally blank for testing
// your loop termination condition goes here
if (simulationLoopCount > MAX_LOOP_COUNT) // for example
{
simulationComplete = true;
}
// =============================================================================================
// * your own simulation code is finished here! ************************************************
// =============================================================================================
// staying synchronized with 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)(getSimulationTimeStepDuration() * 1000)); // units of seconds * (1000 msec/sec) = milliseconds
System.out.println ("... [Pausing for " + getSimulationTimeStepDuration() + " seconds]");
// OK now send the status PDUs for this loop, and then continue
System.out.println ("... sending PDUs of interest for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent");
System.out.flush();
// TODO set timesteps in PDUs
sendAllPdusForLoopTimestep(simulationTimeSeconds,
entityStatePdu_1,
firePdu_1a,
DisChannel.COMMENTPDU_APPLICATION_STATUS,
narrativeMessage1, narrativeMessage2, narrativeMessage3);
disChannel.sendSinglePdu(simulationTimeSeconds, entityStatePdu_2); // me too i.e. 2!
System.out.println ("... [PDUs of interest successfully sent for this loop]");
System.out.flush();
// ===============================
// current loop now finished, check whether to terminate if simulation complete, otherwise continue
if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good
{ {
System.out.println ("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount + simulationLoopCount++; // good practice: increment loop counter as first action in that loop
// =============================================================================================
// * your own simulation code starts here! *****************************************************
// =============================================================================================
Vector3Double entity2Location = entityStatePdu_2.getEntityLocation();
Vector3Double entity1Location = entityStatePdu_1.getEntityLocation();
System.out.println(entity1Location);
System.out.println(entity2Location);
Double deltaX = entity2Location.getX() - entity1Location.getX();
Double deltaY = entity2Location.getY() - entity1Location.getY();
System.out.println("1x: " + entity1Location.getX() + " 1y: " + entity1Location.getY() + " deltaX " + deltaX + " deltaY " + deltaY);
System.out.println("2x: " + entity2Location.getX() + " 2y: " + entity2Location.getY());
Double magnitude = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
System.out.println(magnitude);
// are there any other variables to modify at the beginning of your loop?
// are your reading any DIS PDUs from the network? check for them here
// compute a track, update an ESPDU, whatever it is that your model is doing...
// Where is my entity? Insert changes in position; this sample only changes X position.&
// entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + 1.0); // 1m per timestep
if (magnitude <= firePdu_1a.getRange()) {
System.out.println(entityStatePdu_1.getEntityID() + " FIRING AT " + entityStatePdu_2.getEntityID() + "....");
double pKill = 0.5; //probability of a hit
double shot = random.nextDouble();
System.out.println(shot);
if (shot <= pKill) {
System.out.println("...HIT!");
killFlag = true;
} else {
System.out.println("...MISS!");
}
} else {
entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + (2 * deltaX / magnitude));
entityStatePdu_1.getEntityLocation().setY(entityStatePdu_1.getEntityLocation().getY() + (2 * deltaY / magnitude));
}
//Entity2 moves away from entity 1
entityStatePdu_2.getEntityLocation().setX(entityStatePdu_2.getEntityLocation().getX() + (deltaX / magnitude));
entityStatePdu_2.getEntityLocation().setY(entityStatePdu_2.getEntityLocation().getY() + (deltaY / magnitude));
System.out.flush(); // make sure this arrives to user even if other threads somehow become deadlocked
// make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending)
narrativeMessage1 = "MV3500 ExampleSimulationProgram";
narrativeMessage2 = "runSimulation() loop " + simulationLoopCount;
narrativeMessage3 = ""; // intentionally blank for testing
// your loop termination condition goes here
if (killFlag) {
simulationComplete = true;
}
// =============================================================================================
// * your own simulation code is finished here! ************************************************
// =============================================================================================
// staying synchronized with 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) (getSimulationTimeStepDuration() * 1000)); // units of seconds * (1000 msec/sec) = milliseconds
System.out.println("... [Pausing for " + getSimulationTimeStepDuration() + " seconds]");
// OK now send the status PDUs for this loop, and then continue
System.out.println("... sending PDUs of interest for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent");
System.out.flush(); System.out.flush();
break;
// TODO set timesteps in PDUs
sendAllPdusForLoopTimestep(simulationTimeSeconds,
entityStatePdu_1,
firePdu_1a,
DisChannel.COMMENTPDU_APPLICATION_STATUS,
narrativeMessage1, narrativeMessage2, narrativeMessage3);
disChannel.sendSinglePdu(simulationTimeSeconds, entityStatePdu_2); // me too i.e. 2!
System.out.println("... [PDUs of interest successfully sent for this loop]");
System.out.flush();
// ===============================
// current loop now finished, check whether to terminate if simulation complete, otherwise continue
if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good
{
System.out.println("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount +
System.out.flush();
break;
}
simulationTimeSeconds += getSimulationTimeStepDuration(); // good practice: increment simulationTime as lastst action in that loop
} // end of simulation loop, continue until done
// ===================================================================================================// ===================================================================================================// ===================================================================================================// ===================================================================================================
if(simulationComplete){
System.out.println("Good guys sank the bads guys!");
}
else{
System.out.println("Bad guys got away... we'll get em' next time boys.");
} }
simulationTimeSeconds += getSimulationTimeStepDuration(); // good practice: increment simulationTime as lastst action in that loop narrativeMessage2 = "runSimulation() completed successfully"; // all done, so tell everyone else on the channel
// TODO better javadoc needs to be autogenerated for VariableRecordType enumerations
} // end of simulation loop, continue until done disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3);
// ===================================================================================================// ===================================================================================================// ===================================================================================================// =================================================================================================== System.out.println("... [final=completion CommentPdu successfully sent for simulation]");
narrativeMessage2 = "runSimulation() completed successfully"; // all done, so tell everyone else on the channel
// TODO better javadoc needs to be autogenerated for VariableRecordType enumerations
disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3);
System.out.println ("... [final=completion CommentPdu successfully sent for simulation]");
// disChannel.getPduRecorder(). TODO record XML as well // disChannel.getPduRecorder(). TODO record XML as well
disChannel.leave(); // embedded SimulationManager is expected to send appropriate PDUs for entity, application shutdown disChannel.leave(); // embedded SimulationManager is expected to send appropriate PDUs for entity, application shutdown
} } catch (InterruptedException iex) // handle any exception that your code might choose to provoke!
catch (InterruptedException iex) // handle any exception that your code might choose to provoke! {
{ Logger.getLogger(BavlsikSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex);
Logger.getLogger(BavlsikSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex); }
}
} }
/** /**
* Send EntityState, Fire, Comment PDUs that got updated for this loop, reflecting state of current simulation timestep. * Send EntityState, Fire, Comment PDUs that got updated for this loop,
* @param simTimeSeconds simulation time in second, applied to PDU as timestamp * reflecting state of current simulation timestep.
*
* @param simTimeSeconds simulation time in second, applied to PDU as
* timestamp
* @param entityStatePdu the ESPDU to send, if any * @param entityStatePdu the ESPDU to send, if any
* @param firePdu the FirePDU to send, if any * @param firePdu the FirePDU to send, if any
* @param commentType enumeration value describing purpose of the narrative comment PDU * @param commentType enumeration value describing purpose of the narrative
* @param comments String array of narrative comments * comment PDU
* @see DisChannel * @param comments String array of narrative comments
// * @see DisTime // TODO find renamed version * @see DisChannel // * @see DisTime // TODO find renamed version
* @see <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html" target="_blank">Passing Information to a Method or a Constructor</a> Arbitrary Number of Arguments * @see
* <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html" target="_blank">Passing
* Information to a Method or a Constructor</a> Arbitrary Number of
* Arguments
*/ */
public void sendAllPdusForLoopTimestep(double simTimeSeconds, public void sendAllPdusForLoopTimestep(double simTimeSeconds,
EntityStatePdu entityStatePdu, EntityStatePdu entityStatePdu,
FirePdu firePdu, FirePdu firePdu,
VariableRecordType commentType, VariableRecordType commentType,
// vararg... variable-length set of String comments can optionally follow // vararg... variable-length set of String comments can optionally follow
String... comments) String... comments) {
{ if (entityStatePdu != null) {
if (entityStatePdu != null)
disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu); disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu);
}
if (firePdu != null)
if (firePdu != null) {
disChannel.sendSinglePdu(simTimeSeconds, firePdu); // bang disChannel.sendSinglePdu(simTimeSeconds, firePdu); // bang
}
disChannel.sendCommentPdu(simTimeSeconds, commentType, comments); // empty comments are filtered disChannel.sendCommentPdu(simTimeSeconds, commentType, comments); // empty comments are filtered
} }
/** /**
* Initial execution via main() method: handle args array of command-line initialization (CLI) arguments here * Initial execution via main() method: handle args array of command-line
* initialization (CLI) arguments here
*
* @param args command-line parameters: network address and port * @param args command-line parameters: network address and port
*/ */
protected void handleArguments (String[] args) protected void handleArguments(String[] args) {
{
// initial execution: handle args array of initialization arguments here // initial execution: handle args array of initialization arguments here
if (args.length == 2) if (args.length == 2) {
{ if ((args[0] != null) && !args[0].isEmpty()) {
if ((args[0] != null) && !args[0].isEmpty())
thisProgram.disChannel.setNetworkAddress(args[0]); thisProgram.disChannel.setNetworkAddress(args[0]);
if ((args[1] != null) && !args[1].isEmpty()) }
if ((args[1] != null) && !args[1].isEmpty()) {
thisProgram.disChannel.setNetworkPort(Integer.parseInt(args[1])); thisProgram.disChannel.setNetworkPort(Integer.parseInt(args[1]));
} }
else if (args.length != 0) } else if (args.length != 0) {
{
System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]"); System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]");
System.exit(-1); System.exit(-1);
} }
} }
/** /**
* Get simple descriptor (such as parent class name) for this network interface, used in trace statements * Get simple descriptor (such as parent class name) for this network
* interface, used in trace statements
*
* @return simple descriptor name * @return simple descriptor name
*/ */
public String getDescriptor() { public String getDescriptor() {
...@@ -360,17 +434,21 @@ public class BavlsikSimulationProgram ...@@ -360,17 +434,21 @@ public class BavlsikSimulationProgram
} }
/** /**
* Set new simple descriptor (such as parent class name) for this network interface, used in trace statements * Set new simple descriptor (such as parent class name) for this network
* interface, used in trace statements
*
* @param newDescriptor simple descriptor name for this interface * @param newDescriptor simple descriptor name for this interface
*/ */
public void setDescriptor(String newDescriptor) { public void setDescriptor(String newDescriptor) {
if (newDescriptor == null) if (newDescriptor == null) {
newDescriptor = ""; newDescriptor = "";
}
this.descriptor = newDescriptor; this.descriptor = newDescriptor;
} }
/** /**
* parameter accessor method * parameter accessor method
*
* @return the simulationTimeStepDuration in seconds * @return the simulationTimeStepDuration in seconds
*/ */
public double getSimulationTimeStepDuration() { public double getSimulationTimeStepDuration() {
...@@ -379,35 +457,42 @@ public class BavlsikSimulationProgram ...@@ -379,35 +457,42 @@ public class BavlsikSimulationProgram
/** /**
* parameter accessor method * parameter accessor method
* @param timeStepDurationSeconds the simulationTimeStepDuration in seconds to set *
* @param timeStepDurationSeconds the simulationTimeStepDuration in seconds
* to set
*/ */
public void setSimulationTimeStepDuration(double timeStepDurationSeconds) { public void setSimulationTimeStepDuration(double timeStepDurationSeconds) {
this.simulationTimeStepDuration = timeStepDurationSeconds; this.simulationTimeStepDuration = timeStepDurationSeconds;
} }
/** Locally instantiable copy of program, can be subclassed. */ /**
* Locally instantiable copy of program, can be subclassed.
*/
protected static BavlsikSimulationProgram thisProgram; protected static BavlsikSimulationProgram thisProgram;
/** /**
* Main method is first executed when a program instance is loaded. * Main method is first executed when a program instance is loaded.
* @see <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html" target="_blank">Java Tutorials: A Closer Look at the "Hello World!" Application</a> *
* @see
* <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html" target="_blank">Java
* Tutorials: A Closer Look at the "Hello World!" Application</a>
* @param args command-line parameters: network address and port. * @param args command-line parameters: network address and port.
* Command-line arguments are an array of optional String parameters that are passed from execution environment during invocation * Command-line arguments are an array of optional String parameters that
* are passed from execution environment during invocation
*/ */
public static void main(String[] args) public static void main(String[] args) {
{
thisProgram = new BavlsikSimulationProgram("test constructor"); // create instance of self within static main() method thisProgram = new BavlsikSimulationProgram("test constructor"); // create instance of self within static main() method
thisProgram.disChannel.printlnTRACE("main() started..."); thisProgram.disChannel.printlnTRACE("main() started...");
thisProgram.handleArguments(args); // process any command-line invocation arguments thisProgram.handleArguments(args); // process any command-line invocation arguments
thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ... thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ...
thisProgram.disChannel.tearDownNetworkInterface(); // make sure no processes are left lingering thisProgram.disChannel.tearDownNetworkInterface(); // make sure no processes are left lingering
thisProgram.disChannel.printlnTRACE("complete."); // report successful completion thisProgram.disChannel.printlnTRACE("complete."); // report successful completion
System.exit(0); // ensure all threads and sockets released System.exit(0); // ensure all threads and sockets released
} }
} }
## Homework 3: Example Simulation Recording using OpenDIS Network Streams ## Homework 3: Example Simulation Recording using OpenDIS Network Streams
This program runs a simulation between two entites. One entity is initialized at
<!-- Viewable at https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/assignments/src/MV3500Cohort2024JulySeptember/homework3/README.md --> (0,0,0) and the other is randomly placed. The hunter entity moves towards the prey
entity until it is in range. When in range the hunter attempts to shoot the prey.
### Assignment If successful, the simulation ends. The prey entity constantly attemps to move away
from the hunter.
1. Adapt the functionality for [OpenDIS ExampleSimulationProgram](../../../../examples/src/OpenDis7Examples/ExampleSimulationProgram.java), modifying provided code \ No newline at end of file
2. Experiment with the enumeration values that set up each entity and PDU. What works for you? What makes sense for your future work?
3. Adapt or replace the UML diagrams to describe what you have going on.
4. Record, save and replay your result stream using [PduRecorder](https://savage.nps.edu/opendis7-java/javadoc/edu/nps/moves/dis7/utilities/stream/PduRecorder.html) or [Wireshark](https://www.wireshark.org)
* see local [assignments/src/pduLog](../../../pduLog) subdirectory for latest opendis log files
* Coming soon, we will also (again have) [X3D-Edit](https://savage.nps.edu/X3D-Edit) for DIS stream recording/replay
5. Observe good-practice conventions in the [assignments README](../../../README.md) and [current-course README](../README.md) instructions.
This assignment presents a Problem Prototyping opportunity.
While some minimal functionality is expected, the general outline of
a networking problem and proposed solution holds great interest.
Think of it as warmup preparation for your future work.
This is also a freeplay opportunity.
You have the option to pick one or more of the provided course example programs
and adapt the source to demonstrate a new client-server handshake protocol of interest.
Be sure to provide a rationale that justifies why the networking choices you made
(TCP/UDP, unicast/multicast, etc.) are the best for the problem you are addressing.
You may find that the prior [homework2 README](../homework2/README.md) still provides
helpful details on what specific deliverables are expected in each homework assignment.
Team efforts are encouraged, though if you choose a team approach be sure to justify why.
This is a good warmup prior to final projects. Have fun with Java networking!
### Prior Assignment, August 2019
In 2019, students worked together on a single project to check wireless multicast connectivity recently deployed on NPS campus.
See their experimental results in the [NPS Multicast Connectivity Report](../../MV3500Cohort2019JulySeptember/homework3).
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment