diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/README.md b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9f51e23971cff6ef9f5fabb57fdd6ddb4576a683 --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/README.md @@ -0,0 +1,9 @@ +## Homework 4: Receiving ESPDUs and sending a Fire PDU + +### Description +If an ESPDU is received and this entity is identified as hostile, then a Fire PDU is sent to engage this entity. For sending ESPDUs [SchnitzlerSimulationProgram](../../homework3/Schnitzler/SchnitzlerSimulationProgram.java) can be used. + +The following examples were used: + +* [AllPduSender](../../../../examples/src/OpenDis7Examples/AllPduSender.java) +* [EspduReceiver](../../../../examples/src/OpenDis7Examples/EspduReceiver.java) \ No newline at end of file diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/SchnitzlerEspduReceiverAndShooter.java b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/SchnitzlerEspduReceiverAndShooter.java new file mode 100644 index 0000000000000000000000000000000000000000..8c4afa463ffaced3473b19ddfd27c8d48cbc873f --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/SchnitzlerEspduReceiverAndShooter.java @@ -0,0 +1,179 @@ +package MV3500Cohort2024JulySeptember.homework4.Schnitzler; + +import edu.nps.moves.dis7.entities.deu.platform.land.Leopard2A7PLUS; +import edu.nps.moves.dis7.enumerations.DisPduType; +import edu.nps.moves.dis7.enumerations.ForceID; +import edu.nps.moves.dis7.pdus.*; +import edu.nps.moves.dis7.utilities.*; +import java.awt.geom.Point2D; +import java.io.*; +import java.net.*; +import java.util.*; + +/** + * Receives PDUs from the network in IEEE DIS format. Adapted from OpenDIS + * library example package edu.nps.moves.examples + * + * @author DMcG + * @version $Id:$ + */ +public class SchnitzlerEspduReceiverAndShooter { + + /** + * Default constructor + */ + public SchnitzlerEspduReceiverAndShooter() { + // default constructor + } + /** + * Max size of a PDU in binary format that we can receive. This is actually + * somewhat outdated--PDUs can be larger--but this is a reasonable starting + * point. + */ + private static final int MAX_PDU_SIZE = 8192; + + /** + * Default multicast group address we send on. + * + * @see + * <a href="https://en.wikipedia.org/wiki/Multicast_address" target="_blank">https://en.wikipedia.org/wiki/Multicast_address</a> + */ + public static final String DEFAULT_MULTICAST_ADDRESS = "239.1.2.3"; + + /** + * Default multicast port used, matches Wireshark DIS capture default + * + * @see + * <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)" target="_blank">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> + */ + public static final int DEFAULT_MULTICAST_PORT = 3000; + + /** + * Output prefix to identify this class + */ + private final static String TRACE_PREFIX = "[" + SchnitzlerEspduReceiverAndShooter.class.getName() + "] "; + + /** + * Program invocation, execution starts here + * + * @param args command-line arguments + */ + public static void main(String args[]) { + MulticastSocket multicastSocket; + InetAddress multicastInetAddress; + DatagramPacket packet; + PduFactory pduFactory = new PduFactory(); + DisTime.TimestampStyle timestampStyle = DisTime.TimestampStyle.IEEE_ABSOLUTE; + DisTime.setTimestampStyle(timestampStyle); + int pduCount = 0; + EntityStatePdu shooter = pduFactory.makeEntityStatePdu(); + EntityID entityID = new EntityID(); + + entityID.setSiteID(2).setApplicationID(3).setEntityID(1); + + shooter.setEntityID(entityID); + shooter.setForceId(ForceID.OPPOSING); + shooter.setEntityType(new Leopard2A7PLUS()); + shooter.setMarking("Hunter"); + shooter.getMarkingString(); + + shooter.getEntityLocation().setX(75.0); + shooter.getEntityLocation().setY(75.0); + shooter.getEntityLocation().setZ(0.0); + Vector3Float currentVelocityFloat = new Vector3Float(); + currentVelocityFloat.setX(0.0f); + currentVelocityFloat.setY(0.0f); + currentVelocityFloat.setZ(0.0f); + shooter.setEntityLinearVelocity(currentVelocityFloat); + + System.out.println(TRACE_PREFIX + "started..."); + + try { + // Specify the socket to receive data + multicastSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT); +// socket.setBroadcast(true); + + multicastInetAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS); +// socket.joinGroup(address); // deprecated + // ======================================================================= + // new approach using interface + NetworkInterface networkInterface = NetworkInterface.getByInetAddress(multicastInetAddress); + SocketAddress localMulticastSocketAddress = new InetSocketAddress(multicastInetAddress, DEFAULT_MULTICAST_PORT); + multicastSocket.joinGroup(localMulticastSocketAddress, networkInterface); + // ======================================================================= + + System.out.println(TRACE_PREFIX + "listening for PDU packets on " + multicastInetAddress.getHostAddress() + " port " + DEFAULT_MULTICAST_PORT); + System.out.println("To quit: stop or kill this process"); + System.out.println("==============="); + + while (true) // Loop infinitely, receiving datagrams + { + byte buffer[] = new byte[MAX_PDU_SIZE]; + packet = new DatagramPacket(buffer, buffer.length); // reset packet each time + + multicastSocket.receive(packet); // process blocks here until receipt of network packet with PDU + + List<Pdu> pduBundle = pduFactory.getPdusFromBundle(packet.getData(), packet.getLength()); + if (pduBundle.size() > 1) { + System.out.println("Received PDU bundle size is " + pduBundle.size()); + } + + for (Pdu nextPdu : pduBundle) // iterator loop through PDU bundle + { + pduCount++; + String receiptMessage = String.format("%3s", pduCount) // right justify, 3 characters + + ". received PDU type " + nextPdu.getPduType().getValue() + "=" + nextPdu.getPduType().name() + " " + nextPdu.getClass().getSimpleName(); + if (nextPdu instanceof EntityStatePdu) { + System.out.println(receiptMessage); + EntityID receivedEntityID = ((EntityStatePdu) nextPdu).getEntityID(); + Vector3Double position = ((EntityStatePdu) nextPdu).getEntityLocation(); + System.out.println(" entityID triplet: [" + receivedEntityID.getSiteID() + ", " + receivedEntityID.getApplicationID() + ", " + receivedEntityID.getEntityID() + "] "); + System.out.println(" Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "]"); + if (((EntityStatePdu) nextPdu).getForceId() != shooter.getForceId()) { + FirePdu firePdu = new FirePdu(); + firePdu.setFiringEntityID(entityID); + firePdu.setTargetEntityID(receivedEntityID); + firePdu.setLocationInWorldCoordinates(position); + // careful here! keep object instantiations inside of loop to avoid endless array and packet growth + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + try { + firePdu.marshal(dos); // dos is DataOutputStream connected to ByteArrayOutputStrea + + buffer = baos.toByteArray(); + packet = new DatagramPacket(buffer, buffer.length, multicastInetAddress, DEFAULT_MULTICAST_PORT); + multicastSocket.send(packet); + + + String currentPduTypePadded = String.format("%-49s", firePdu.getPduType().toString()); // - indicates right padding of whitespace + String packetLengthPadded = String.format("%3s", packet.getLength()); + + System.out.println("Sent packet, " + + // currentPduTypeValuePadded + " " + + currentPduTypePadded + + "(packet.getLength()=" + packetLengthPadded + ")" + + // diagnostic, beware of ever-growing packet size! + " of type " + firePdu.getClass().getSimpleName()); + } catch (Exception ex) { + System.out.println("Marshaling error" + ex); + } + } + } else if (nextPdu instanceof FirePdu) { + System.out.println(receiptMessage); + Vector3Double position = ((FirePdu) nextPdu).getLocationInWorldCoordinates(); + System.out.println(" FirePdu locationInWorldCoordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "]"); + System.out.println("==============="); + } else { + System.out.println(receiptMessage); + } + } // end of bundle loop + } // end of while loop + } // end try block + catch (IOException ioe) { + System.out.println(TRACE_PREFIX + "Problem with input/output, see exception trace:"); + System.out.println(ioe); + } + System.out.println(TRACE_PREFIX + "complete."); + } // end main +} // end class diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/package-info.java b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..c7ab8b22c564959af81bd999da2b926afaf0672d --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework4/Schnitzler/package-info.java @@ -0,0 +1,10 @@ +/** + * Final project assignments supporting the NPS MOVES MV3500 Networked Graphics course. + * + * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/tree/master/assignments" target="_blank">networkedGraphicsMV3500 assignments</a> + * @see java.lang.Package + * @see <a href="https://stackoverflow.com/questions/22095487/why-is-package-info-java-useful" target="_blank">StackOverflow: why-is-package-info-java-useful</a> + * @see <a href="https://stackoverflow.com/questions/624422/how-do-i-document-packages-in-java" target="_blank">StackOverflow: how-do-i-document-packages-in-java</a> + */ + +package MV3500Cohort2024JulySeptember.homework4.Schnitzler;