From 6a4d24f95534d05aa526eb4b057397edcfc05067 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Sat, 5 Mar 2011 00:25:23 +0000 Subject: Rough Addition of P2P code. --- src/alden/Peer.java | 588 ++++++++++++++++++++++++++++++ src/alden/PeerCoordinates.java | 53 +++ src/alden/PeerInformation.java | 39 ++ src/alden/PeerMessage.java | 28 ++ src/tesseract/TesseractServer.java | 34 ++ src/tesseract/TesseractUI.java | 29 +- src/tesseract/World.java | 83 +++-- src/tesseract/objects/PhysicalObject.java | 10 +- 8 files changed, 810 insertions(+), 54 deletions(-) create mode 100644 src/alden/Peer.java create mode 100644 src/alden/PeerCoordinates.java create mode 100644 src/alden/PeerInformation.java create mode 100644 src/alden/PeerMessage.java create mode 100644 src/tesseract/TesseractServer.java (limited to 'src') diff --git a/src/alden/Peer.java b/src/alden/Peer.java new file mode 100644 index 0000000..931cc10 --- /dev/null +++ b/src/alden/Peer.java @@ -0,0 +1,588 @@ +package alden; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Observable; + +import javax.swing.SwingWorker; +import javax.vecmath.Vector2f; + + +@SuppressWarnings("restriction") +public class Peer extends Observable { + /** + * The default port number for incoming network connections. + */ + public static final int DEFAULT_SERVER_PORT = 5507; + + private PeerInformation myInfo; + private ArrayList peers; + private ServerSocket serverSocket; + private SwingWorker worker; + + /** + * A flag indicating whether internal operation messages (useful for + * debugging) are logged to the console. This field may be modified at any + * time. + */ + public boolean logEnabled; + + /** + * Initializes a new Peer object. The Peer is + * not connected to a network and sends a log of internal operation + * messages to the console. + */ + public Peer() { + this(true); + } + + /** + * Initializes a new Peer object with message logging + * controlled by the logEnabled parameter. The + * Peer is not connected to a network. + * + * @param logEnabled Initial value for the logEnabled field. + */ + public Peer(boolean logEnabled) { + myInfo = new PeerInformation(); + this.logEnabled = logEnabled; + } + + /** + * Establishes a new peer-to-peer network with this Peer + * as the sole member. The logical coordinates of this + * Peer are chosen randomly. + * + * @return true if the new network was established + * successfully, or false otherwise. + */ + public boolean createNetwork() { + return createNetwork(new PeerCoordinates()); + } + + /** + * Establishes a new peer-to-peer network with this Peer + * as the sole member. The logical coordinates of this + * Peer are specified by parameter location. + * + * @param location Logical coordinates for this Peer + * within the new network. + * + * @return true if the new network was established + * successfully, or false otherwise. + */ + public boolean createNetwork(PeerCoordinates location) { + if (serverSocket == null) + if (!startServer()) + return false; + peers = new ArrayList(); + myInfo.location = location; + logMessage("Established network @ " + myInfo.location); + return true; + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * port number of the known Peer must be + * {@link #DEFAULT_SERVER_PORT DEFAULT_SERVER_PORT}. The logical coordinates + * of this Peer are chosen randomly. + * + * @param host + * The domain name or IP address of a Peer within + * the network. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(String host) { + return connectToNetwork(host, DEFAULT_SERVER_PORT); + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * port number of the known Peer must be + * {@link #DEFAULT_SERVER_PORT DEFAULT_SERVER_PORT}. The preferred logical + * coordinates of this Peer are specified by parameter + * location, but the actual logical coordinates may be chosen + * randomly to avoid collision with other Peers. + * + * @param host + * The domain name or IP address of a Peer within + * the network. + * @param location + * Preferred logical coordinates for this Peer. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(String host, PeerCoordinates location) { + return connectToNetwork(host, DEFAULT_SERVER_PORT, location); + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * logical coordinates of this Peer are chosen randomly. + * + * @param host + * The domain name or IP address of a Peer within + * the network. + * @param port + * The port number of a Peer within the network. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(String host, int port) { + try { + return connectToNetwork(InetAddress.getByName(host), port); + } catch (UnknownHostException e) { + System.err.println(e); + return false; + } + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * preferred logical coordinates of this Peer are specified by + * parameter location, but the actual logical coordinates may + * be chosen randomly to avoid collision with other Peers. + * + * @param host + * The domain name or IP address of a Peer within + * the network. + * @param port + * The port number of a Peer within the network. + * @param location + * Preferred logical coordinates for this Peer. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(String host, int port, PeerCoordinates location) { + try { + return connectToNetwork(InetAddress.getByName(host), port, location); + } catch (UnknownHostException e) { + System.err.println(e); + return false; + } + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * port number of the known Peer must be + * {@link #DEFAULT_SERVER_PORT DEFAULT_SERVER_PORT}. The logical coordinates + * of this Peer are chosen randomly. + * + * @param host + * The IP address of a Peer within the network. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(InetAddress host) { + return connectToNetwork(host, DEFAULT_SERVER_PORT); + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * port number of the known Peer must be + * {@link #DEFAULT_SERVER_PORT DEFAULT_SERVER_PORT}. The preferred logical + * coordinates of this Peer are specified by parameter + * location, but the actual logical coordinates may be chosen + * randomly to avoid collision with other Peers. + * + * @param host + * The IP address of a Peer within the network. + * @param location + * Preferred logical coordinates for this Peer. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(InetAddress host, PeerCoordinates location) { + return connectToNetwork(host, DEFAULT_SERVER_PORT, location); + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * logical coordinates of this Peer are chosen randomly. + * + * @param host + * The IP address of a Peer within the network. + * @param port + * The port number of a Peer within the network. + * + * @return true if this Peer successfully + * connected to the network, or false otherwise. + */ + public boolean connectToNetwork(InetAddress host, int port) { + return connectToNetwork(host, port, new PeerCoordinates()); + } + + /** + * Connects this Peer to an existing peer-to-peer network. The + * preferred logical coordinates of this Peer are specified by + * parameter location, but the actual logical coordinates may + * be chosen randomly to avoid collision with other Peers. + * + * @param host + * The IP address of a Peer within the network. + * @param port + * The port number of a Peer within the network. + * @param location + * Preferred logical coordinates for this Peer. + * + * @return true if this Peer successfully connects + * to the network, or false otherwise. + */ + public boolean connectToNetwork(InetAddress host, int port, PeerCoordinates location) { + if (serverSocket == null) + if (!startServer()) + return false; + try { + Socket socket = new Socket(); + try { + socket.connect(new InetSocketAddress(host, port), 10000); + } catch (IOException e) { + System.out.println("Unable to connect to " + host + ":" + port); + return false; + } + ObjectOutputStream socketOut = new ObjectOutputStream(socket.getOutputStream()); + socketOut.writeObject(createJoinMessage(location)); + socket.close(); + while (myInfo.location == null) + Thread.sleep(1000); + logMessage("Joined network @ " + myInfo.location); + return true; + } catch (Exception e) { + System.err.println(e); + return false; + } + } + + /** + * Disconnects this Peer from the peer-to-peer network. + */ + public synchronized void disconnectFromNetwork() { + PeerMessage mesg = createAddPeersMessage(); + mesg.peers = peers; + for (PeerInformation peer : peers) + sendMessage(mesg, peer); + mesg = createRemovePeersMessage(); + for (PeerInformation peer : peers) + sendMessage(mesg, peer); + worker.cancel(true); + try { + serverSocket.close(); + } catch (IOException e) { + } + serverSocket = null; + System.out.println(myInfo + " disconnected"); + } + + /** + * Identifies the Peer in the network adjacent to this + * Peer in the direction (x,y). + * + * @param x + * X component of a direction relative to the logical coordinates + * of this Peer. + * @param y + * Y component of a direction relative to the logical coordinates + * of this Peer. + * + * @return A PeerInformation object representing the adjacent + * Peer, or null if no adjacent + * Peer exists. + */ + public synchronized PeerInformation getPeerInDirection(float x, float y) { + float minDistance = Float.POSITIVE_INFINITY; + PeerInformation minPeer = null; + + Vector2f startPoint = new Vector2f(myInfo.location.getX(), myInfo.location.getY()); + Vector2f direction = new Vector2f(x, y); + for (PeerInformation peer : peers) { + Vector2f normal = new Vector2f(peer.location.getX() - startPoint.x, peer.location.getY() - startPoint.y); + Vector2f midpoint = new Vector2f((peer.location.getX() + startPoint.x) / 2f, (peer.location.getY() + startPoint.y) / 2f); + + float denominator = direction.dot(normal); + if (denominator == 0) + continue; + midpoint.scaleAdd(-1, startPoint, midpoint); + float distance = midpoint.dot(normal) / denominator; + if (distance > 0 && distance < minDistance) { + minDistance = distance; + minPeer = peer; + } + } + + // Tuples for fixed boundaries: normal.x, normal.y, point.x, point.y + float boundaries[] = {1, 0, PeerCoordinates.MIN_X, PeerCoordinates.MIN_Y, + 0, 1, PeerCoordinates.MIN_X, PeerCoordinates.MIN_Y, + -1, 0, PeerCoordinates.MAX_X, PeerCoordinates.MAX_Y, + 0, -1, PeerCoordinates.MAX_X, PeerCoordinates.MAX_X}; + for (int i = 0; i < boundaries.length; i += 4) { + Vector2f normal = new Vector2f(boundaries[i], boundaries[i+1]); + Vector2f point = new Vector2f(boundaries[i+2], boundaries[i+3]); + + float denominator = direction.dot(normal); + if (denominator == 0) + continue; + point.scaleAdd(-1, startPoint, point); + float distance = point.dot(normal) / denominator; + if (distance > 0 && distance < minDistance) + return null; + } + + return minPeer; + } + + /** + * A method that sends a CollidableObject to all + * Peers in the network. + * + * @param payload + * A CollidableObject. + * + * @return true if the message was successfully sent to all + * Peers, or false otherwise. + */ + public synchronized boolean sendToAllPeers(CollidableObject payload) { + PeerMessage message = createPayloadMessage(payload); + boolean success = true; + for (PeerInformation peer : peers) + success = sendMessage(message, peer) && success; + return success; + } + + /** + * A method that sends an object to all + * Peers in the network. + * + * @param payload + * An object. + * + * @return true if the message was successfully sent to all + * Peers, or false otherwise. + */ + public synchronized boolean sendExtraToAllPeers(Object payload) { + PeerMessage message = createExtraMessage(payload); + boolean success = true; + for (PeerInformation peer : peers) + success = sendMessage(message, peer) && success; + return success; + } + + private boolean startServer() { + return startServer(DEFAULT_SERVER_PORT); + } + + private boolean startServer(int port) { + while (true) { + try { + serverSocket = new ServerSocket(port); + } catch (IOException e) { + port++; + continue; + } catch (SecurityException e) { + System.err.println(e); + return false; + } + try { + myInfo.address = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + System.err.println(e); + try { + serverSocket.close(); + } catch (IOException e1) { + } + serverSocket = null; + return false; + } + myInfo.port = port; + break; + } + + System.out.println("Listening on " + myInfo.address + ":" + myInfo.port); + + worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + while (!isCancelled()) { + logMessage("Waiting for peer connection..."); + try { + Socket socket = serverSocket.accept(); + processConnection(socket); + } catch (SocketException e) { + } catch (IOException e) { + System.err.println(e); + } + } + return null; + } + }; + worker.execute(); + + return true; + } + + private synchronized void processConnection(Socket socket) { + ObjectInputStream socketIn; + PeerMessage mesg; + try { + socketIn = new ObjectInputStream(socket.getInputStream()); + mesg = (PeerMessage)socketIn.readObject(); + } catch (Exception e) { + System.err.println(e); + return; + } + if (mesg.sender.address == null || mesg.type != PeerMessage.Type.JOIN) + mesg.sender.address = socket.getInetAddress(); + switch (mesg.type) { + case JOIN: + logMessage("Received JOIN message from " + mesg.sender); + while (true) { + PeerInformation peer = lookup(mesg.sender.location); + if (peer != myInfo) { + sendMessage(mesg, peer); + break; + } else if (myInfo.location.equals(mesg.sender.location)) + mesg.sender.location.setToRandomCoordinate(); + else { + sendMessage(createJoinResultMessage(mesg.sender.location), mesg.sender); + break; + } + } + break; + case JOIN_RESULT: + logMessage("Received JOIN_RESULT message from " + mesg.sender); + assert(peers == null); + peers = mesg.peers; + assert(myInfo.location == null); + myInfo.location = mesg.location; + PeerMessage newMesg = createAddPeersMessage(); + for (PeerInformation peer : peers) { + logMessage("Adding peer " + peer); + sendMessage(newMesg, peer); + } + logMessage("Adding peer " + mesg.sender); + sendMessage(newMesg, mesg.sender); + peers.add(mesg.sender); + break; + case ADD_PEERS: + logMessage("Received ADD_PEERS message from " + mesg.sender); + if (!peers.contains(mesg.sender)) { + logMessage("Adding peer " + mesg.sender); + peers.add(mesg.sender); + } + for (PeerInformation peer : mesg.peers) + if (!peers.contains(peer) && !myInfo.equals(peer)) { + logMessage("Adding peer " + peer); + peers.add(peer); + } + break; + case REMOVE_PEERS: + logMessage("Received REMOVE_PEERS message from " + mesg.sender); + if (peers.contains(mesg.sender)) { + logMessage("Removing peer " + mesg.sender); + peers.remove(mesg.sender); + } + for (PeerInformation peer : mesg.peers) + if (peers.contains(peer)) { + logMessage("Removing peer " + peer); + peers.remove(peer); + } + break; + + case PAYLOAD: + logMessage("Received PAYLOAD message from " + mesg.sender); + + setChanged(); + notifyObservers(mesg.payload); + + break; + + case EXTRA: + logMessage("Received EXTRA message from " + mesg.sender); + + if (mesg.id != null && mesg.id.equals(PeerMessage.DEFAULT_ID)) { + setChanged(); + notifyObservers(mesg.extra); + } + + break; + } + } + + private synchronized PeerInformation lookup(PeerCoordinates location) { + double minDistance = myInfo.location.distanceTo(location); + int min = -1; + for (int i = 0; i < peers.size(); i++) { + double distance = peers.get(i).location.distanceTo(location); + if (distance < minDistance) { + minDistance = distance; + min = i; + } + } + if (min == -1) + return myInfo; + return peers.get(min); + } + + private boolean sendMessage(PeerMessage message, PeerInformation destination) { + try { + Socket socket = new Socket(destination.address, destination.port); + ObjectOutputStream socketOut = new ObjectOutputStream(socket.getOutputStream()); + socketOut.writeObject(message); + socket.close(); + } catch (IOException e) { + System.err.println(e); + return false; + } + return true; + } + + private PeerMessage createJoinMessage(PeerCoordinates location) { + PeerInformation tmp = new PeerInformation(null, myInfo.port, location); + return new PeerMessage(PeerMessage.Type.JOIN, tmp); + } + + private PeerMessage createJoinResultMessage(PeerCoordinates location) { + PeerMessage mesg = new PeerMessage(PeerMessage.Type.JOIN_RESULT, myInfo); + mesg.peers = peers; + mesg.location = location; + return mesg; + } + + private PeerMessage createAddPeersMessage() { + return new PeerMessage(PeerMessage.Type.ADD_PEERS, myInfo); + } + + private PeerMessage createRemovePeersMessage() { + return new PeerMessage(PeerMessage.Type.REMOVE_PEERS, myInfo); + } + + private PeerMessage createPayloadMessage(CollidableObject payload) { + PeerMessage mesg = new PeerMessage(PeerMessage.Type.PAYLOAD, myInfo); + mesg.payload = payload; + return mesg; + } + + private PeerMessage createExtraMessage(Object payload) { + PeerMessage mesg = new PeerMessage(PeerMessage.Type.EXTRA, myInfo); + mesg.extra = payload; + return mesg; + } + + private void logMessage(String text) { + if (logEnabled) + System.out.println(new Date() + " -- " + text); + } +} diff --git a/src/alden/PeerCoordinates.java b/src/alden/PeerCoordinates.java new file mode 100644 index 0000000..4d0e445 --- /dev/null +++ b/src/alden/PeerCoordinates.java @@ -0,0 +1,53 @@ +package alden; +import java.io.*; + +public class PeerCoordinates implements Serializable { + private static final long serialVersionUID = 3667108226485766929L; + public static final int MIN_X = 0; + public static final int MAX_X = 99; + public static final int MIN_Y = 0; + public static final int MAX_Y = 99; + + private int x; + private int y; + + public PeerCoordinates() { + setToRandomCoordinate(); + } + + public PeerCoordinates(int x, int y) { + if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) + throw new IllegalArgumentException(); + + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public double distanceTo(PeerCoordinates other) { + return Math.sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y)); + } + + public String toString() { + return "(" + x + ", " + y + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof PeerCoordinates)) + return false; + + return x == ((PeerCoordinates)other).x && y == ((PeerCoordinates)other).y; + } + + public void setToRandomCoordinate() { + x = MIN_X + (int)((MAX_X - MIN_X + 1) * Math.random()); + y = MIN_Y + (int)((MAX_Y - MIN_Y + 1) * Math.random()); + } +} diff --git a/src/alden/PeerInformation.java b/src/alden/PeerInformation.java new file mode 100644 index 0000000..3d94f11 --- /dev/null +++ b/src/alden/PeerInformation.java @@ -0,0 +1,39 @@ +package alden; +import java.io.*; +import java.net.*; + +public class PeerInformation implements Serializable { + private static final long serialVersionUID = 3667108226485766929L; + public static final String DEFAULT_ID = "something unique"; + + public InetAddress address; + public int port; + public PeerCoordinates location; + public String id; + + public PeerInformation() { + id = DEFAULT_ID; + } + + public PeerInformation(PeerInformation other) { + this(other.address, other.port, other.location); + } + + public PeerInformation(InetAddress address, int port, PeerCoordinates location) { + this(); + this.address = address; + this.port = port; + this.location = location; + } + + public String toString() { + return address + ":" + port + " @ " + location; + } + + public boolean equals(Object other) { + if (!(other instanceof PeerInformation)) + return false; + + return location.equals(((PeerInformation)other).location); + } +} diff --git a/src/alden/PeerMessage.java b/src/alden/PeerMessage.java new file mode 100644 index 0000000..a5af7de --- /dev/null +++ b/src/alden/PeerMessage.java @@ -0,0 +1,28 @@ +package alden; +import java.io.*; +import java.util.*; + + +public class PeerMessage implements Serializable { + private static final long serialVersionUID = 3667108226485766929L; + public static final String DEFAULT_ID = "TesseractProject"; + + public enum Type { + JOIN, JOIN_RESULT, ADD_PEERS, REMOVE_PEERS, PAYLOAD, EXTRA; + } + + public Type type; + public PeerInformation sender; + public PeerCoordinates location; + public ArrayList peers; + public CollidableObject payload; + public Object extra; + public String id; + + public PeerMessage(Type type, PeerInformation sender) { + this.type = type; + this.sender = sender; + peers = new ArrayList(); + this.id = DEFAULT_ID; + } +} diff --git a/src/tesseract/TesseractServer.java b/src/tesseract/TesseractServer.java new file mode 100644 index 0000000..3518c38 --- /dev/null +++ b/src/tesseract/TesseractServer.java @@ -0,0 +1,34 @@ +package tesseract; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import alden.Peer; + +/** + * This class is not part of the deliverable. This class is simply a server to + * help peers get into the network. + * + * @author jesse + */ +public class TesseractServer { + public static void main(String[] args) { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + Peer server = new Peer(); + server.createNetwork(); + + try { + Thread.sleep(2000); + } catch (InterruptedException e1) { + } + while (true) { + System.out.print("Enter text to send: "); + try { + String input = in.readLine(); + server.sendExtraToAllPeers(input); + } catch (IOException e) { + } + } + } +} diff --git a/src/tesseract/TesseractUI.java b/src/tesseract/TesseractUI.java index 1d6a5cc..85f46a1 100644 --- a/src/tesseract/TesseractUI.java +++ b/src/tesseract/TesseractUI.java @@ -42,10 +42,9 @@ import tesseract.newmenu.NewParticleMenuItem; import tesseract.newmenu.NewPlanarPolygonMenuItem; import tesseract.newmenu.NewSurfBoardMenuItem; import tesseract.newmenu.NewToroidMenuItem; -import tesseract.objects.Box; -import tesseract.objects.ChainLink2; import tesseract.objects.PhysicalObject; import tesseract.objects.Sphere; +import alden.Peer; import com.sun.j3d.utils.picking.PickCanvas; import com.sun.j3d.utils.picking.PickResult; @@ -83,6 +82,11 @@ public class TesseractUI extends JFrame { */ private World myWorld; + /** + * The Peer Object + */ + private Peer myPeer; + /** * The Canvas. */ @@ -121,9 +125,12 @@ public class TesseractUI extends JFrame { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + myPeer = new Peer(true); + myWorld = new World( new BoundingBox(new Point3d(-UNIT / 2, -UNIT / 2, -UNIT / 2), - new Point3d(UNIT / 2, UNIT / 2, UNIT / 2))); + new Point3d(UNIT / 2, UNIT / 2, UNIT / 2)), + myPeer); myCurrentObject = null; @@ -150,20 +157,8 @@ public class TesseractUI extends JFrame { // THIS IS WHERE OBJECTS ARE FORCED INTO EXISTANCE // TODO: REMOVE TEST CODE - // Lookie! Linked chainlinks! - //myWorld.addObject(new ChainLink2(new Vector3f(0.15f, 0, 0), 1)); - //ChainLink2 o = new ChainLink2(new Vector3f(), 1); - //o.setRotation(); - - //myWorld.addForce(new AirDrag()); - - //World.addObject(new Box(0.18f, 0.1f, 0.25f, new Vector3f(0.1f, -0.10f, 0))); - //myWorld.addObject(new Box(0.18f, 0.25f, 0.1f, new Vector3f(-0.1f, 0, 0))); - PhysicalObject s = new Sphere(.05f, new Vector3f()); - s.setAngularVelocity(new Vector3f(0, 2, 0)); - myWorld.addObject(s); - - //myWorld.addObject(o); + myPeer.connectToNetwork("127.0.0.1"); + //myPeer.createNetwork(); } /** diff --git a/src/tesseract/World.java b/src/tesseract/World.java index e898a27..eb9d26b 100644 --- a/src/tesseract/World.java +++ b/src/tesseract/World.java @@ -3,12 +3,13 @@ package tesseract; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Observable; +import java.util.Observer; import javax.media.j3d.BoundingBox; import javax.media.j3d.BoundingLeaf; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; -import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.IndexedLineArray; import javax.media.j3d.Light; @@ -19,20 +20,17 @@ import javax.vecmath.Point3d; import javax.vecmath.Vector3f; import tesseract.forces.Force; -import tesseract.objects.PhysicalObject; - import tesseract.objects.HalfSpace; - -import com.sun.j3d.utils.picking.PickTool; -import com.sun.j3d.utils.picking.behaviors.PickTranslateBehavior; -import com.sun.j3d.utils.picking.behaviors.PickZoomBehavior; +import tesseract.objects.PhysicalObject; +import alden.CollidableObject; +import alden.Peer; /** * Model of the 3D world. * * @author Jesse Morgan */ -public class World { +public class World implements Observer { /** * Root element of the world. */ @@ -46,25 +44,17 @@ public class World { /** * A list of the objects in the world. */ - private List myObjects; + private List myObjects; /** * A list of the forces in the world. */ private List myForces; - //private List emitters; - //private boolean enableEmitters; - - // A list of all the particles in the world - //private List particles; - - // A list of all the objects particles may collide with - //private List collidables; - - // Available forces - //private static final ParticleForceGenerator forces[] = {new Gravity(0.4f)}; - //private boolean activeForces[]; + /** + * The peer object for this world. + */ + private Peer myPeer; /** * Update rate for the world. @@ -76,11 +66,13 @@ public class World { * * @param bounds The bounding box of the world. */ - public World(final BoundingBox bounds) { + public World(final BoundingBox bounds, final Peer peer) { myVirtualWorldBounds = bounds; - + myPeer = peer; + myPeer.addObserver(this); + myForces = new LinkedList(); - myObjects = new LinkedList(); + myObjects = new LinkedList(); // TODO: Should this go here? myScene = new BranchGroup(); @@ -174,25 +166,30 @@ public class World { */ public void tick() { // Iterate over objects in the world. - Iterator itr = myObjects.iterator(); + Iterator itr = myObjects.iterator(); List children = new LinkedList(); while (itr.hasNext()) { - PhysicalObject obj = itr.next(); + CollidableObject obj = itr.next(); // Apply forces - for (Force force : myForces) { - force.applyForceTo(obj); + if (obj instanceof PhysicalObject) { + for (Force force : myForces) { + force.applyForceTo((PhysicalObject) obj); + } } // Update the object's state. obj.updateState(1f / UPDATE_RATE); // Spawn new objects? - List newChildren = obj.spawnChildren(1f / UPDATE_RATE); - if (newChildren != null) { - children.addAll(newChildren); + if (obj instanceof PhysicalObject) { + List newChildren = + ((PhysicalObject) obj).spawnChildren(1f / UPDATE_RATE); + if (newChildren != null) { + children.addAll(newChildren); + } } // If it leaves the bounds of the world, DESTROY IT @@ -212,7 +209,7 @@ public class World { } } - // Add new children to thr world. + // Add new children to the world. for (PhysicalObject obj : children) { myScene.addChild(obj.getGroup()); } @@ -232,7 +229,7 @@ public class World { * * @param obj The object to add */ - public void addObject(final PhysicalObject obj) { + public void addObject(final CollidableObject obj) { myScene.addChild(obj.getGroup()); myObjects.add(obj); } @@ -261,11 +258,29 @@ public class World { public void resetWorld() { myForces.clear(); - for (PhysicalObject obj : myObjects) { + for (CollidableObject obj : myObjects) { obj.detach(); } myObjects.clear(); addHalfspaces(); } + + /** + * Observer Callback. + * Called when a PAYLOAD or EXTRA peer message is recieved. + * + * @param peer The network peer. + * @param obj The object from the network. + */ + public void update(final Observable peer, final Object obj) { + if (obj != null) { + if (obj instanceof PhysicalObject) { + addObject((PhysicalObject) obj); + + } else if (obj instanceof CollidableObject) { + addObject((CollidableObject) obj); + } + } + } } diff --git a/src/tesseract/objects/PhysicalObject.java b/src/tesseract/objects/PhysicalObject.java index c743e8e..d4e4e3b 100644 --- a/src/tesseract/objects/PhysicalObject.java +++ b/src/tesseract/objects/PhysicalObject.java @@ -2,7 +2,6 @@ package tesseract.objects; import java.util.List; -import javax.media.j3d.GeometryArray; import javax.media.j3d.Node; import javax.media.j3d.Shape3D; import javax.media.j3d.TransformGroup; @@ -20,12 +19,17 @@ import com.sun.j3d.utils.geometry.Primitive; * to the transform group for it to be visible. * * @author Jesse Morgan - */ + */ public class PhysicalObject extends CollidableObject { + /** + * Generated Serial UID + */ + private static final long serialVersionUID = -8418338503604062404L; + protected boolean collidable; protected boolean mySelected; - + public PhysicalObject(final Vector3f thePosition, final float mass) { super(mass); this.position.set(thePosition); -- cgit v1.2.3