Captive Imagination
July 31, 2010, 11:48:43 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News: Hosting change completed. Please send an e-mail to support@captiveimagination.com if you have any problems.
 
   Home   Help Search Calendar Login Register  
Pages: [1]   Go Down
  Print  
Author Topic: Proposed patch for regional sync'ing  (Read 604 times)
0 Members and 2 Guests are viewing this topic.
Tumaini
JGN Developer
Jr. Member
*****
Offline Offline

Posts: 51


View Profile
« on: December 08, 2009, 12:35:09 PM »

I've been working on fixing regional sync'ing, using the proximity method in GraphicalController.
The updating bit has already been commited, but the create/remove bit is bigger and therefore I provide a patch here, so that anyone can test it and see if it's working as intended in their program, before I commit it to the repository.

With this patch objects that return 0 from proximity for a given player id are not updated to that player and if it a create message had previously been sent (when proximity returned a value > 0) a remove message is sent.
Also, if proximity returns 0 already when a client connects, no create message is sent.
If proximity later returns a value > 0, a create message is sent to the player in question.

The proximity method should return a value between 0 and 1, inclusive.
0 means the object is not visible to (or should not be updated for) the player with that player id.
1 means it is visible and should be updated at regular speed.
A value between 0 and 1, exclusive, means it is visible and should be updated at a reduced rate (closer to 0 means more time between updates).

Please let me know in this thread if you have any problems or if your tests were successful as well.

Code:
Index: src/com/captiveimagination/jgn/synchronization/SynchronizationManager.java
===================================================================
--- src/com/captiveimagination/jgn/synchronization/SynchronizationManager.java (revision 1280)
+++ src/com/captiveimagination/jgn/synchronization/SynchronizationManager.java (working copy)
@@ -164,9 +164,15 @@
 
  // Send create message onward
  if (client != null) {
- client.broadcast(wrapper.getCreateMessage());
+ client.sendToServer(wrapper.getCreateMessage());
  } else {
- server.sendToAll(wrapper.getCreateMessage());
+ for(JGNConnection conn : server.getConnections()) {
+ if(controller.proximity(wrapper.getObject(), conn.getPlayerId()) > 0f) {
+ System.out.println("Sending create for "+wrapper.getId());
+ wrapper.setLastAction(conn.getPlayerId(), (short)1);
+ server.sendToPlayer(wrapper.getCreateMessage(), conn.getPlayerId());
+ }
+ }
  }
 
  // Add to manager to be updated
@@ -202,7 +208,16 @@
  client.sendToServer(release);
  }
  } else {
- server.sendToAll(remove);
+ //Check which players are near this object
+ for(JGNConnection conn : server.getConnections()) {
+ if(controller.proximity(wrapper.getObject(), conn.getPlayerId()) > 0f) {
+ if(wrapper.hasLastAction(conn.getPlayerId())) {
+ if(wrapper.getLastAction(conn.getPlayerId()) != 2) {
+ server.sendToPlayer(remove, conn.getPlayerId());
+ }
+ }
+ }
+ }
 
  // Release id
  serverReleaseId(wrapper.getId());
@@ -335,6 +350,16 @@
  SyncWrapper wrapper = new SyncWrapper(obj, 0, message, message.getPlayerId());
  wrapper.setId(message.getSyncObjectId());
  passive.add(wrapper);
+ if(server != null) {
+ // Forward create message to clients
+ for(JGNConnection conn : server.getConnections()) {
+ if(controller.proximity(wrapper.getObject(), conn.getPlayerId()) > 0f && conn.getPlayerId() != wrapper.getOwnerPlayerId()) {
+ System.out.println("Sending create for "+wrapper.getId());
+ wrapper.setLastAction(conn.getPlayerId(), (short)1);
+ server.sendToPlayer(wrapper.getCreateMessage(), conn.getPlayerId());
+ }
+ }
+ }
  return obj;
  }
  }
@@ -459,25 +484,76 @@
  public void connected(JGNConnection connection) {
  // Client connected to server - send creation messages to new connection
  for (SyncWrapper wrapper : queue) {
- connection.sendMessage(wrapper.getCreateMessage());
+ if(controller.proximity(wrapper.getObject(), connection.getPlayerId()) > 0f) {
+ if(wrapper.hasLastAction(connection.getPlayerId())) {
+ if(wrapper.getLastAction(connection.getPlayerId()) != 1) {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId());
+ }
+ }
+ else {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId());
+ }
+ }
  }
  for (SyncWrapper wrapper : disabled) {
- connection.sendMessage(wrapper.getCreateMessage());
+ if(controller.proximity(wrapper.getObject(), connection.getPlayerId()) > 0f) {
+ if(wrapper.hasLastAction(connection.getPlayerId())) {
+ if(wrapper.getLastAction(connection.getPlayerId()) != 1) {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId());
+ }
+ }
+ else {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId());
+ }
+ }
  }
  for (SyncWrapper wrapper : passive) {
- connection.sendMessage(wrapper.getCreateMessage());
+ if(controller.proximity(wrapper.getObject(), connection.getPlayerId()) > 0f) {
+ if(wrapper.hasLastAction(connection.getPlayerId())) {
+ if(wrapper.getLastAction(connection.getPlayerId()) != 1) {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId()+" to "+connection.getPlayerId());
+ }
+ }
+ else {
+ connection.sendMessage(wrapper.getCreateMessage());
+ wrapper.setLastAction(connection.getPlayerId(), (short)1);
+ System.out.println("Sending create for "+wrapper.getId()+" to "+connection.getPlayerId());
+ }
+ }
  }
  }
 
  public void disconnected(JGNConnection connection) {
  // Remove all connections associated with this player
- short playerId = connection.getPlayerId();
  for (SyncWrapper wrapper : passive) {
- if (wrapper.getOwnerPlayerId() == playerId) {
+ if (wrapper.getOwnerPlayerId() == connection.getPlayerId()) {
  SynchronizeRemoveMessage removeMessage = new SynchronizeRemoveMessage();
  removeMessage.setSyncObjectId(wrapper.getId());
  removeQueue.add(removeMessage);
  }
  }
+ //Remove values for lastServerUpdate and lastAction for this connection
+ for (SyncWrapper wrapper : passive) {
+ wrapper.removeLastServerUpdateKey(connection.getPlayerId());
+ wrapper.removeLastActionKey(connection.getPlayerId());
+ }
+ for (SyncWrapper wrapper : queue) {
+ wrapper.removeLastServerUpdateKey(connection.getPlayerId());
+ wrapper.removeLastActionKey(connection.getPlayerId());
+ }
+ for (SyncWrapper wrapper : disabled) {
+ wrapper.removeLastServerUpdateKey(connection.getPlayerId());
+ wrapper.removeLastActionKey(connection.getPlayerId());
+ }
  }
 }
\ No newline at end of file
Index: src/com/captiveimagination/jgn/synchronization/SyncWrapper.java
===================================================================
--- src/com/captiveimagination/jgn/synchronization/SyncWrapper.java (revision 1279)
+++ src/com/captiveimagination/jgn/synchronization/SyncWrapper.java (working copy)
@@ -40,6 +40,7 @@
 import com.captiveimagination.jgn.clientserver.JGNServer;
 import com.captiveimagination.jgn.synchronization.message.SynchronizeCreateMessage;
 import com.captiveimagination.jgn.synchronization.message.SynchronizeMessage;
+import com.captiveimagination.jgn.synchronization.message.SynchronizeRemoveMessage;
 
 class SyncWrapper {
  private short id;
@@ -50,8 +51,19 @@
  private SynchronizeCreateMessage createMessage;
  private short ownerPlayerId;
 
+ /**
+ * Long for storing when the last update to the server was, if this is on the client
+ */
  private long lastUpdate;
+ /**
+ * Map for storing when the last update to a connected client was, if this is on the server
+ */
  private HashMap<Short, Long> lastServerUpdate = new HashMap<Short, Long>();
+ /**
+ * Map for storing the last action of create/remove for a connected client
+ * 0 = nothing; 1 = sent create message; 2 = sent remove message
+ */
+ private HashMap<Short, Short> lastAction = new HashMap<Short, Short>();
 
  public SyncWrapper(Object object, long rate, SynchronizeCreateMessage createMessage, short ownerPlayerId) {
  if (object == null) throw new RuntimeException("Object is null: " + id);
@@ -95,6 +107,36 @@
  return ownerPlayerId;
  }
 
+ /**
+ * Removes this key from the lastServerUpdate map
+ * @param playerId the key to remove
+ * @return the object referenced by this key or null if the key didn't exist
+ */
+ public Object removeLastServerUpdateKey(short playerId) {
+ return lastServerUpdate.remove(playerId);
+ }
+
+ /**
+ * Removes this key from the lastAction map
+ * @param playerId the key to remove
+ * @return the object referenced by this key or null if the key didn't exist
+ */
+ public Object removeLastActionKey(short playerId) {
+ return lastAction.remove(playerId);
+ }
+
+ public boolean hasLastAction(short playerId) {
+ return lastAction.containsKey(playerId);
+ }
+
+ public short getLastAction(short playerId) {
+ return lastAction.get(playerId);
+ }
+
+ public void setLastAction(short playerId, short value) {
+ lastAction.put(playerId, value);
+ }
+
  protected void update(SynchronizationManager manager, JGNServer server, GraphicalController controller) {
  long updateRate = rate;
  SynchronizeMessage message = controller.createSynchronizationMessage(getObject());
@@ -102,6 +144,23 @@
  message.setSyncObjectId(getId());
  for(JGNConnection conn : server.getConnections()) {
  if(controller.proximity(getObject(), conn.getPlayerId()) > 0f && conn.getPlayerId() != getOwnerPlayerId()) {
+ //Check if sent create message
+ if(lastAction.containsKey(conn.getPlayerId())) {
+ if(lastAction.get(conn.getPlayerId()) != 1) { //No create message sent
+ System.out.println("Sending create for "+getId());
+ lastAction.put(conn.getPlayerId(), (short)1);
+ getCreateMessage().setSyncObjectId(getId());
+ getCreateMessage().setSyncManagerId(manager.getId());
+ server.sendToPlayer(getCreateMessage(), conn.getPlayerId());
+ }
+ }
+ else {
+ System.out.println("Sending create for "+getId());
+ lastAction.put(conn.getPlayerId(), (short)1);
+ getCreateMessage().setSyncObjectId(getId());
+ getCreateMessage().setSyncManagerId(manager.getId());
+ server.sendToPlayer(getCreateMessage(), conn.getPlayerId());
+ }
  updateRate = (long) (rate/controller.proximity(getObject(), conn.getPlayerId()));
  if(!lastServerUpdate.containsKey(conn.getPlayerId())) {
  lastServerUpdate.put(conn.getPlayerId(), (long)0);
@@ -114,6 +173,22 @@
  lastServerUpdate.put(conn.getPlayerId(), System.nanoTime());
  }
  }
+ else if(controller.proximity(getObject(), conn.getPlayerId()) == 0f){
+ //Check if sent remove message
+ if(lastAction.containsKey(conn.getPlayerId())) {
+ if(lastAction.get(conn.getPlayerId()) != 2) { //No remove message sent
+ System.out.println("Sending remove for "+getId());
+ lastAction.put(conn.getPlayerId(), (short)2);
+ SynchronizeRemoveMessage remove = new SynchronizeRemoveMessage();
+ remove.setSyncObjectId(getId());
+ remove.setSyncManagerId(manager.getId());
+ server.sendToPlayer(remove, conn.getPlayerId());
+ }
+ }
+ else {
+ lastAction.put(conn.getPlayerId(), (short)2);
+ }
+ }
  }
  }

EDIT: Put in code tags.
EDIT2: Fixed bug with unregister that was sending not using proximity.
« Last Edit: December 10, 2009, 06:02:18 AM by Tumaini » Logged
darkfrog
Administrator
Inspired Imagination
*****
Offline Offline

Posts: 2650


View Profile
« Reply #1 on: December 09, 2009, 09:52:24 AM »

Looks good. You know you can make it more visually appealing in the forum if you use the "code" block tags, right?
Logged
Tumaini
JGN Developer
Jr. Member
*****
Offline Offline

Posts: 51


View Profile
« Reply #2 on: December 10, 2009, 06:17:12 AM »

Found a spot where I forgot to implement proximity, in the unregister method.
It's now been fixed.
Logged
darkfrog
Administrator
Inspired Imagination
*****
Offline Offline

Posts: 2650


View Profile
« Reply #3 on: December 11, 2009, 04:25:30 PM »

Have you committed this?
Logged
Tumaini
JGN Developer
Jr. Member
*****
Offline Offline

Posts: 51


View Profile
« Reply #4 on: December 12, 2009, 02:22:57 AM »

Not yet, still testing to make sure there are no bugs.
Logged
Tumaini
JGN Developer
Jr. Member
*****
Offline Offline

Posts: 51


View Profile
« Reply #5 on: December 15, 2009, 02:36:23 PM »

Since I haven't found any bugs yet and noone else seems to either, I've now committed this change to the repository.
Logged
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Page created in 0.187 seconds with 17 queries.