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;