project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java
changeset 10017 de822cd3df3a
parent 7691 55c0a856ecd0
equal deleted inserted replaced
10015:4feced261c68 10017:de822cd3df3a
    76 
    76 
    77 import com.sun.jna.Pointer;
    77 import com.sun.jna.Pointer;
    78 
    78 
    79 /**
    79 /**
    80  * This class handles the actual communication with the networking library, running on a separate thread.
    80  * This class handles the actual communication with the networking library, running on a separate thread.
    81  * 
    81  *
    82  * In order to process net messages, this class regularly runs a tick() function on the frontlib. This
    82  * In order to process net messages, this class regularly runs a tick() function on the frontlib. This
    83  * usually happens several times per second, but it can be slowed down a lot if no fast reaction to
    83  * usually happens several times per second, but it can be slowed down a lot if no fast reaction to
    84  * events is required (e.g. to conserve battery if the application is in the background).
    84  * events is required (e.g. to conserve battery if the application is in the background).
    85  */
    85  */
    86 class ThreadedNetConnection {
    86 class ThreadedNetConnection {
    87 	private static final long TICK_INTERVAL_FAST = 100;
    87     private static final long TICK_INTERVAL_FAST = 100;
    88 	private static final long TICK_INTERVAL_SLOW = 5000;
    88     private static final long TICK_INTERVAL_SLOW = 5000;
    89 	private static final Frontlib FLIB = Flib.INSTANCE;
    89     private static final Frontlib FLIB = Flib.INSTANCE;
    90 	
    90 
    91 	public final ToNetHandler toNetHandler;
    91     public final ToNetHandler toNetHandler;
    92 	
    92 
    93 	private final Context appContext;
    93     private final Context appContext;
    94 	private final FromNetHandler fromNetHandler;
    94     private final FromNetHandler fromNetHandler;
    95 	private final TickHandler tickHandler;
    95     private final TickHandler tickHandler;
    96 
    96 
    97 	/**
    97     /**
    98 	 * conn can only be null while connecting (the first thing in the thread), and directly after disconnecting,
    98      * conn can only be null while connecting (the first thing in the thread), and directly after disconnecting,
    99 	 * in the same message (the looper is shut down on disconnect, so there will be no messages after that).
    99      * in the same message (the looper is shut down on disconnect, so there will be no messages after that).
   100 	 */
   100      */
   101 	private NetconnPtr conn;
   101     private NetconnPtr conn;
   102 	private String playerName;
   102     private String playerName;
   103 	
   103 
   104 	private ThreadedNetConnection(Context appContext, FromNetHandler fromNetHandler) {
   104     private ThreadedNetConnection(Context appContext, FromNetHandler fromNetHandler) {
   105 		this.appContext = appContext;
   105         this.appContext = appContext;
   106 		this.fromNetHandler = fromNetHandler;
   106         this.fromNetHandler = fromNetHandler;
   107 		
   107 
   108 		HandlerThread thread = new HandlerThread("NetThread");
   108         HandlerThread thread = new HandlerThread("NetThread");
   109 		thread.start();
   109         thread.start();
   110 		toNetHandler = new ToNetHandler(thread.getLooper());
   110         toNetHandler = new ToNetHandler(thread.getLooper());
   111 		tickHandler = new TickHandler(thread.getLooper(), TICK_INTERVAL_FAST, tickCb);
   111         tickHandler = new TickHandler(thread.getLooper(), TICK_INTERVAL_FAST, tickCb);
   112 	}
   112     }
   113 	
   113 
   114 	private void connect(final String name, final String host, final int port) {
   114     private void connect(final String name, final String host, final int port) {
   115 		toNetHandler.post(new Runnable() {
   115         toNetHandler.post(new Runnable() {
   116 			public void run() {
   116             public void run() {
   117 				playerName = name == null ? "Player" : name;
   117                 playerName = name == null ? "Player" : name;
   118 				File dataPath;
   118                 File dataPath;
   119 				try {
   119                 try {
   120 					dataPath = FileUtils.getDataPathFile(appContext);
   120                     dataPath = FileUtils.getDataPathFile(appContext);
   121 				} catch (FileNotFoundException e) {
   121                 } catch (FileNotFoundException e) {
   122 					shutdown(true, appContext.getString(R.string.sdcard_not_mounted));
   122                     shutdown(true, appContext.getString(R.string.sdcard_not_mounted));
   123 					return;
   123                     return;
   124 				}
   124                 }
   125 				conn = FLIB.flib_netconn_create(playerName, dataPath.getAbsolutePath()+"/", host, port);
   125                 conn = FLIB.flib_netconn_create(playerName, dataPath.getAbsolutePath()+"/", host, port);
   126 				if(conn == null) {
   126                 if(conn == null) {
   127 					shutdown(true, appContext.getString(R.string.error_connection_failed));
   127                     shutdown(true, appContext.getString(R.string.error_connection_failed));
   128 					return;
   128                     return;
   129 				}
   129                 }
   130 
   130 
   131 				FLIB.flib_netconn_onSchemeChanged(conn, cfgSchemeCb, null);
   131                 FLIB.flib_netconn_onSchemeChanged(conn, cfgSchemeCb, null);
   132 				FLIB.flib_netconn_onClientFlags(conn, clientFlagsCb, null);
   132                 FLIB.flib_netconn_onClientFlags(conn, clientFlagsCb, null);
   133 				FLIB.flib_netconn_onChat(conn, chatCb, null);
   133                 FLIB.flib_netconn_onChat(conn, chatCb, null);
   134 				FLIB.flib_netconn_onConnected(conn, connectedCb, null);
   134                 FLIB.flib_netconn_onConnected(conn, connectedCb, null);
   135 				FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
   135                 FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
   136 				FLIB.flib_netconn_onEngineMessage(conn, engineMessageCb, null);
   136                 FLIB.flib_netconn_onEngineMessage(conn, engineMessageCb, null);
   137 				FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
   137                 FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
   138 				FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
   138                 FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
   139 				FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
   139                 FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
   140 				FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
   140                 FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
   141 				FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
   141                 FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
   142 				FLIB.flib_netconn_onMapChanged(conn, mapChangedCb, null);
   142                 FLIB.flib_netconn_onMapChanged(conn, mapChangedCb, null);
   143 				FLIB.flib_netconn_onMessage(conn, messageCb, null);
   143                 FLIB.flib_netconn_onMessage(conn, messageCb, null);
   144 				FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
   144                 FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
   145 				FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
   145                 FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
   146 				FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
   146                 FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
   147 				FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null);
   147                 FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null);
   148 				FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null);
   148                 FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null);
   149 				FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
   149                 FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
   150 				FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
   150                 FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
   151 				FLIB.flib_netconn_onRunGame(conn, runGameCb, null);
   151                 FLIB.flib_netconn_onRunGame(conn, runGameCb, null);
   152 				FLIB.flib_netconn_onScriptChanged(conn, scriptChangedCb, null);
   152                 FLIB.flib_netconn_onScriptChanged(conn, scriptChangedCb, null);
   153 				// FLIB.flib_netconn_onServerVar(conn, serverVarCb, null);
   153                 // FLIB.flib_netconn_onServerVar(conn, serverVarCb, null);
   154 				FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
   154                 FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
   155 				FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
   155                 FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
   156 				FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
   156                 FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
   157 				FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
   157                 FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
   158 				FLIB.flib_netconn_onWeaponsetChanged(conn, weaponsetChangedCb, null);
   158                 FLIB.flib_netconn_onWeaponsetChanged(conn, weaponsetChangedCb, null);
   159 				
   159 
   160 				tickHandler.start();
   160                 tickHandler.start();
   161 			}
   161             }
   162 		});
   162         });
   163 	}
   163     }
   164 	
   164 
   165 	public static ThreadedNetConnection startConnection(Context appContext, FromNetHandler fromNetHandler, String playerName, String host, int port) {
   165     public static ThreadedNetConnection startConnection(Context appContext, FromNetHandler fromNetHandler, String playerName, String host, int port) {
   166 		ThreadedNetConnection result = new ThreadedNetConnection(appContext, fromNetHandler);
   166         ThreadedNetConnection result = new ThreadedNetConnection(appContext, fromNetHandler);
   167 		result.connect(playerName, host, port);
   167         result.connect(playerName, host, port);
   168 		return result;
   168         return result;
   169 	}
   169     }
   170 	
   170 
   171 	public void setFastTickRate(boolean fastTickRate) {
   171     public void setFastTickRate(boolean fastTickRate) {
   172 		tickHandler.setInterval(fastTickRate ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW);
   172         tickHandler.setInterval(fastTickRate ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW);
   173 	}
   173     }
   174 	
   174 
   175 	private final Runnable tickCb = new Runnable() {
   175     private final Runnable tickCb = new Runnable() {
   176 		public void run() {
   176         public void run() {
   177 			FLIB.flib_netconn_tick(conn);
   177             FLIB.flib_netconn_tick(conn);
   178 		}
   178         }
   179 	};
   179     };
   180 	
   180 
   181 	private final SchemeCallback cfgSchemeCb = new SchemeCallback() {
   181     private final SchemeCallback cfgSchemeCb = new SchemeCallback() {
   182 		public void callback(Pointer context, SchemePtr schemePtr) {
   182         public void callback(Pointer context, SchemePtr schemePtr) {
   183 			sendFromNet(MSG_SCHEME_CHANGED, schemePtr.deref());
   183             sendFromNet(MSG_SCHEME_CHANGED, schemePtr.deref());
   184 		}
   184         }
   185 	};
   185     };
   186 	
   186 
   187 	private final MapIntCallback mapChangedCb = new MapIntCallback() {
   187     private final MapIntCallback mapChangedCb = new MapIntCallback() {
   188 		public void callback(Pointer context, MapRecipePtr mapPtr, int updateType) {
   188         public void callback(Pointer context, MapRecipePtr mapPtr, int updateType) {
   189 			sendFromNet(MSG_MAP_CHANGED, updateType, mapPtr.deref());
   189             sendFromNet(MSG_MAP_CHANGED, updateType, mapPtr.deref());
   190 		}
   190         }
   191 	};
   191     };
   192 	
   192 
   193 	private final StrCallback scriptChangedCb = new StrCallback() {
   193     private final StrCallback scriptChangedCb = new StrCallback() {
   194 		public void callback(Pointer context, String script) {
   194         public void callback(Pointer context, String script) {
   195 			sendFromNet(MSG_SCRIPT_CHANGED, script);
   195             sendFromNet(MSG_SCRIPT_CHANGED, script);
   196 		}
   196         }
   197 	};
   197     };
   198 	
   198 
   199 	private final WeaponsetCallback weaponsetChangedCb = new WeaponsetCallback() {
   199     private final WeaponsetCallback weaponsetChangedCb = new WeaponsetCallback() {
   200 		public void callback(Pointer context, WeaponsetPtr weaponsetPtr) {
   200         public void callback(Pointer context, WeaponsetPtr weaponsetPtr) {
   201 			sendFromNet(MSG_WEAPONSET_CHANGED, weaponsetPtr.deref());				
   201             sendFromNet(MSG_WEAPONSET_CHANGED, weaponsetPtr.deref());
   202 		}
   202         }
   203 	};
   203     };
   204 	
   204 
   205 	private final StrCallback lobbyJoinCb = new StrCallback() {
   205     private final StrCallback lobbyJoinCb = new StrCallback() {
   206 		public void callback(Pointer context, String name) {
   206         public void callback(Pointer context, String name) {
   207 			sendFromNet(MSG_LOBBY_JOIN, name);
   207             sendFromNet(MSG_LOBBY_JOIN, name);
   208 		}
   208         }
   209 	};
   209     };
   210 	
   210 
   211 	private final StrStrCallback lobbyLeaveCb = new StrStrCallback() {
   211     private final StrStrCallback lobbyLeaveCb = new StrStrCallback() {
   212 		public void callback(Pointer context, String name, String msg) {
   212         public void callback(Pointer context, String name, String msg) {
   213 			sendFromNet(MSG_LOBBY_LEAVE, Pair.create(name, msg));
   213             sendFromNet(MSG_LOBBY_LEAVE, Pair.create(name, msg));
   214 		}
   214         }
   215 	};
   215     };
   216 	
   216 
   217 	private final StrCallback roomJoinCb = new StrCallback() {
   217     private final StrCallback roomJoinCb = new StrCallback() {
   218 		public void callback(Pointer context, String name) {
   218         public void callback(Pointer context, String name) {
   219 			sendFromNet(MSG_ROOM_JOIN, name);
   219             sendFromNet(MSG_ROOM_JOIN, name);
   220 		}
   220         }
   221 	};
   221     };
   222 	
   222 
   223 	private final StrStrCallback roomLeaveCb = new StrStrCallback() {
   223     private final StrStrCallback roomLeaveCb = new StrStrCallback() {
   224 		public void callback(Pointer context, String name, String message) {
   224         public void callback(Pointer context, String name, String message) {
   225 			sendFromNet(MSG_ROOM_LEAVE, Pair.create(name, message));
   225             sendFromNet(MSG_ROOM_LEAVE, Pair.create(name, message));
   226 		}
   226         }
   227 	};
   227     };
   228 	
   228 
   229 	private final StrStrBoolCallback clientFlagsCb = new StrStrBoolCallback() {
   229     private final StrStrBoolCallback clientFlagsCb = new StrStrBoolCallback() {
   230 		public void callback(Pointer context, String nick, String flags, boolean newFlagsState) {
   230         public void callback(Pointer context, String nick, String flags, boolean newFlagsState) {
   231 			sendFromNet(MSG_CLIENT_FLAGS, new ClientFlagsUpdate(nick, flags, newFlagsState));
   231             sendFromNet(MSG_CLIENT_FLAGS, new ClientFlagsUpdate(nick, flags, newFlagsState));
   232 		}
   232         }
   233 	};
   233     };
   234 	
   234 
   235 	private final StrStrCallback chatCb = new StrStrCallback() {
   235     private final StrStrCallback chatCb = new StrStrCallback() {
   236 		public void callback(Pointer context, String name, String msg) {
   236         public void callback(Pointer context, String name, String msg) {
   237 			sendFromNet(MSG_CHAT, Pair.create(name, msg));
   237             sendFromNet(MSG_CHAT, Pair.create(name, msg));
   238 		}
   238         }
   239 	};
   239     };
   240 	
   240 
   241 	private final IntStrCallback messageCb = new IntStrCallback() {
   241     private final IntStrCallback messageCb = new IntStrCallback() {
   242 		public void callback(Pointer context, int type, String msg) {
   242         public void callback(Pointer context, int type, String msg) {
   243 			sendFromNet(MSG_MESSAGE, type, msg);
   243             sendFromNet(MSG_MESSAGE, type, msg);
   244 		}
   244         }
   245 	};
   245     };
   246 	
   246 
   247 	private final RoomCallback roomAddCb = new RoomCallback() {
   247     private final RoomCallback roomAddCb = new RoomCallback() {
   248 		public void callback(Pointer context, RoomPtr roomPtr) {
   248         public void callback(Pointer context, RoomPtr roomPtr) {
   249 			sendFromNet(MSG_ROOM_ADD, roomPtr.deref());
   249             sendFromNet(MSG_ROOM_ADD, roomPtr.deref());
   250 		}
   250         }
   251 	};
   251     };
   252 	
   252 
   253 	private final StrRoomCallback roomUpdateCb = new StrRoomCallback() {
   253     private final StrRoomCallback roomUpdateCb = new StrRoomCallback() {
   254 		public void callback(Pointer context, String name, RoomPtr roomPtr) {
   254         public void callback(Pointer context, String name, RoomPtr roomPtr) {
   255 			sendFromNet(MSG_ROOM_UPDATE, Pair.create(name, roomPtr.deref()));
   255             sendFromNet(MSG_ROOM_UPDATE, Pair.create(name, roomPtr.deref()));
   256 		}
   256         }
   257 	};
   257     };
   258 	
   258 
   259 	private final StrCallback roomDeleteCb = new StrCallback() {
   259     private final StrCallback roomDeleteCb = new StrCallback() {
   260 		public void callback(Pointer context, final String name) {
   260         public void callback(Pointer context, final String name) {
   261 			sendFromNet(MSG_ROOM_DELETE, name);
   261             sendFromNet(MSG_ROOM_DELETE, name);
   262 		}
   262         }
   263 	};
   263     };
   264 	
   264 
   265 	private final RoomListCallback roomlistCb = new RoomListCallback() {
   265     private final RoomListCallback roomlistCb = new RoomListCallback() {
   266 		public void callback(Pointer context, RoomArrayPtr arg1, int count) {
   266         public void callback(Pointer context, RoomArrayPtr arg1, int count) {
   267 			sendFromNet(MSG_ROOMLIST, arg1.getRooms(count));
   267             sendFromNet(MSG_ROOMLIST, arg1.getRooms(count));
   268 		}
   268         }
   269 	};
   269     };
   270 	
   270 
   271 	private final VoidCallback connectedCb = new VoidCallback() {
   271     private final VoidCallback connectedCb = new VoidCallback() {
   272 		public void callback(Pointer context) {
   272         public void callback(Pointer context) {
   273 			FLIB.flib_netconn_send_request_roomlist(conn);
   273             FLIB.flib_netconn_send_request_roomlist(conn);
   274 			playerName = FLIB.flib_netconn_get_playername(conn);
   274             playerName = FLIB.flib_netconn_get_playername(conn);
   275 			sendFromNet(MSG_CONNECTED, playerName);
   275             sendFromNet(MSG_CONNECTED, playerName);
   276 		}
   276         }
   277 	};
   277     };
   278 	
   278 
   279 	private final StrCallback passwordRequestCb = new StrCallback() {
   279     private final StrCallback passwordRequestCb = new StrCallback() {
   280 		public void callback(Pointer context, String nickname) {
   280         public void callback(Pointer context, String nickname) {
   281 			sendFromNet(MSG_PASSWORD_REQUEST, playerName);
   281             sendFromNet(MSG_PASSWORD_REQUEST, playerName);
   282 		}
   282         }
   283 	};
   283     };
   284 	
   284 
   285 	private final BoolCallback enterRoomCb = new BoolCallback() {
   285     private final BoolCallback enterRoomCb = new BoolCallback() {
   286 		public void callback(Pointer context, boolean isChief) {
   286         public void callback(Pointer context, boolean isChief) {
   287 			sendFromNet(MSG_ENTER_ROOM_FROM_LOBBY, isChief);
   287             sendFromNet(MSG_ENTER_ROOM_FROM_LOBBY, isChief);
   288 		}
   288         }
   289 	};
   289     };
   290 	
   290 
   291 	private final IntStrCallback leaveRoomCb = new IntStrCallback() {
   291     private final IntStrCallback leaveRoomCb = new IntStrCallback() {
   292 		public void callback(Pointer context, int reason, String message) {
   292         public void callback(Pointer context, int reason, String message) {
   293 			sendFromNet(MSG_LEAVE_ROOM, reason, message);
   293             sendFromNet(MSG_LEAVE_ROOM, reason, message);
   294 		}
   294         }
   295 	};
   295     };
   296 	
   296 
   297 	private final TeamCallback teamAddedCb = new TeamCallback() {
   297     private final TeamCallback teamAddedCb = new TeamCallback() {
   298 		public void callback(Pointer context, TeamPtr team) {
   298         public void callback(Pointer context, TeamPtr team) {
   299 			sendFromNet(MSG_TEAM_ADDED, team.deref());
   299             sendFromNet(MSG_TEAM_ADDED, team.deref());
   300 		}
   300         }
   301 	};
   301     };
   302 	
   302 
   303 	private final StrCallback teamDeletedCb = new StrCallback() {
   303     private final StrCallback teamDeletedCb = new StrCallback() {
   304 		public void callback(Pointer context, String teamName) {
   304         public void callback(Pointer context, String teamName) {
   305 			sendFromNet(MSG_TEAM_DELETED, teamName);
   305             sendFromNet(MSG_TEAM_DELETED, teamName);
   306 		}
   306         }
   307 	};
   307     };
   308 	
   308 
   309 	private final StrCallback teamAcceptedCb = new StrCallback() {
   309     private final StrCallback teamAcceptedCb = new StrCallback() {
   310 		public void callback(Pointer context, String teamName) {
   310         public void callback(Pointer context, String teamName) {
   311 			sendFromNet(MSG_TEAM_ACCEPTED, teamName);
   311             sendFromNet(MSG_TEAM_ACCEPTED, teamName);
   312 		}
   312         }
   313 	};
   313     };
   314 	
   314 
   315 	private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
   315     private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
   316 		public void callback(Pointer context, String teamName, int colorIndex) {
   316         public void callback(Pointer context, String teamName, int colorIndex) {
   317 			sendFromNet(MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
   317             sendFromNet(MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
   318 		}
   318         }
   319 	};
   319     };
   320 	
   320 
   321 	private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
   321     private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
   322 		public void callback(Pointer context, String teamName, int hogCount) {
   322         public void callback(Pointer context, String teamName, int hogCount) {
   323 			sendFromNet(MSG_HOG_COUNT_CHANGED, hogCount, teamName);
   323             sendFromNet(MSG_HOG_COUNT_CHANGED, hogCount, teamName);
   324 		}
   324         }
   325 	};
   325     };
   326 	
   326 
   327 	private final BytesCallback engineMessageCb = new BytesCallback() {
   327     private final BytesCallback engineMessageCb = new BytesCallback() {
   328 		public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) {
   328         public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) {
   329 			sendFromNet(MSG_ENGINE_MESSAGE, buffer.deref(size.intValue()));
   329             sendFromNet(MSG_ENGINE_MESSAGE, buffer.deref(size.intValue()));
   330 		}
   330         }
   331 	};
   331     };
   332 	
   332 
   333 	private final VoidCallback runGameCb = new VoidCallback() {
   333     private final VoidCallback runGameCb = new VoidCallback() {
   334 		public void callback(Pointer context) {
   334         public void callback(Pointer context) {
   335 			GameSetupPtr configPtr = FLIB.flib_netconn_create_gamesetup(conn);
   335             GameSetupPtr configPtr = FLIB.flib_netconn_create_gamesetup(conn);
   336 			sendFromNet(MSG_RUN_GAME, configPtr.deref());
   336             sendFromNet(MSG_RUN_GAME, configPtr.deref());
   337 			FLIB.flib_gamesetup_destroy(configPtr);
   337             FLIB.flib_gamesetup_destroy(configPtr);
   338 		}
   338         }
   339 	};
   339     };
   340 	
   340 
   341 	private void shutdown(boolean error, String message) {
   341     private void shutdown(boolean error, String message) {
   342 		if(conn != null) {
   342         if(conn != null) {
   343 			FLIB.flib_netconn_destroy(conn);
   343             FLIB.flib_netconn_destroy(conn);
   344 			conn = null;
   344             conn = null;
   345 		}
   345         }
   346 		tickHandler.stop();
   346         tickHandler.stop();
   347 		toNetHandler.getLooper().quit();
   347         toNetHandler.getLooper().quit();
   348 		sendFromNet(MSG_DISCONNECTED, Pair.create(error, message));
   348         sendFromNet(MSG_DISCONNECTED, Pair.create(error, message));
   349 	}
   349     }
   350 	
   350 
   351 	private final IntStrCallback disconnectCb = new IntStrCallback() {
   351     private final IntStrCallback disconnectCb = new IntStrCallback() {
   352 		public void callback(Pointer context, int reason, String message) {
   352         public void callback(Pointer context, int reason, String message) {
   353 			Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
   353             Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
   354 			String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
   354             String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
   355 			shutdown(error, messageForUser);
   355             shutdown(error, messageForUser);
   356 		}
   356         }
   357 	};
   357     };
   358 	
   358 
   359 	private static String createDisconnectUserMessage(Resources res, int reason, String message) {
   359     private static String createDisconnectUserMessage(Resources res, int reason, String message) {
   360 		switch(reason) {
   360         switch(reason) {
   361 		case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
   361         case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
   362 			return res.getString(R.string.error_auth_failed);
   362             return res.getString(R.string.error_auth_failed);
   363 		case Frontlib.NETCONN_DISCONNECT_CONNLOST:
   363         case Frontlib.NETCONN_DISCONNECT_CONNLOST:
   364 			return res.getString(R.string.error_connection_lost);
   364             return res.getString(R.string.error_connection_lost);
   365 		case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
   365         case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
   366 			return res.getString(R.string.error_unexpected, message);
   366             return res.getString(R.string.error_unexpected, message);
   367 		case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
   367         case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
   368 			return res.getString(R.string.error_server_too_old);
   368             return res.getString(R.string.error_server_too_old);
   369 		default:
   369         default:
   370 			return message;
   370             return message;
   371 		}
   371         }
   372 	}
   372     }
   373 	
   373 
   374 	private boolean sendFromNet(FromNetMsgType what, Object obj) {
   374     private boolean sendFromNet(FromNetMsgType what, Object obj) {
   375 		return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), obj));
   375         return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), obj));
   376 	}
   376     }
   377 	
   377 
   378 	private boolean sendFromNet(FromNetMsgType what, int arg1, Object obj) {
   378     private boolean sendFromNet(FromNetMsgType what, int arg1, Object obj) {
   379 		return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), arg1, 0, obj));
   379         return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), arg1, 0, obj));
   380 	}
   380     }
   381 	
   381 
   382 	static enum ToNetMsgType {
   382     static enum ToNetMsgType {
   383 		MSG_SEND_NICK,
   383         MSG_SEND_NICK,
   384 		MSG_SEND_PASSWORD,
   384         MSG_SEND_PASSWORD,
   385 		MSG_SEND_QUIT,
   385         MSG_SEND_QUIT,
   386 		MSG_SEND_ROOMLIST_REQUEST,
   386         MSG_SEND_ROOMLIST_REQUEST,
   387 		MSG_SEND_PLAYER_INFO_REQUEST,
   387         MSG_SEND_PLAYER_INFO_REQUEST,
   388 		MSG_SEND_CHAT,
   388         MSG_SEND_CHAT,
   389 		MSG_SEND_TEAMCHAT,
   389         MSG_SEND_TEAMCHAT,
   390 		MSG_SEND_FOLLOW_PLAYER,
   390         MSG_SEND_FOLLOW_PLAYER,
   391 		MSG_SEND_JOIN_ROOM,
   391         MSG_SEND_JOIN_ROOM,
   392 		MSG_SEND_CREATE_ROOM,
   392         MSG_SEND_CREATE_ROOM,
   393 		MSG_SEND_LEAVE_ROOM,
   393         MSG_SEND_LEAVE_ROOM,
   394 		MSG_SEND_KICK,
   394         MSG_SEND_KICK,
   395 		MSG_SEND_ADD_TEAM,
   395         MSG_SEND_ADD_TEAM,
   396 		MSG_SEND_REMOVE_TEAM,
   396         MSG_SEND_REMOVE_TEAM,
   397 		MSG_DISCONNECT,
   397         MSG_DISCONNECT,
   398 		MSG_SEND_TEAM_COLOR_INDEX,
   398         MSG_SEND_TEAM_COLOR_INDEX,
   399 		MSG_SEND_TEAM_HOG_COUNT,
   399         MSG_SEND_TEAM_HOG_COUNT,
   400 		MSG_SEND_ENGINE_MESSAGE,
   400         MSG_SEND_ENGINE_MESSAGE,
   401 		MSG_SEND_ROUND_FINISHED,
   401         MSG_SEND_ROUND_FINISHED,
   402 		MSG_SEND_TOGGLE_READY,
   402         MSG_SEND_TOGGLE_READY,
   403 		MSG_SEND_START_GAME,
   403         MSG_SEND_START_GAME,
   404 		MSG_SEND_WEAPONSET,
   404         MSG_SEND_WEAPONSET,
   405 		MSG_SEND_MAP,
   405         MSG_SEND_MAP,
   406 		MSG_SEND_MAP_NAME,
   406         MSG_SEND_MAP_NAME,
   407 		MSG_SEND_MAP_GENERATOR,
   407         MSG_SEND_MAP_GENERATOR,
   408 		MSG_SEND_MAP_TEMPLATE,
   408         MSG_SEND_MAP_TEMPLATE,
   409 		MSG_SEND_MAZE_SIZE,
   409         MSG_SEND_MAZE_SIZE,
   410 		MSG_SEND_MAP_SEED,
   410         MSG_SEND_MAP_SEED,
   411 		MSG_SEND_MAP_THEME,
   411         MSG_SEND_MAP_THEME,
   412 		MSG_SEND_MAP_DRAWDATA,
   412         MSG_SEND_MAP_DRAWDATA,
   413 		MSG_SEND_GAMESTYLE,
   413         MSG_SEND_GAMESTYLE,
   414 		MSG_SEND_SCHEME;
   414         MSG_SEND_SCHEME;
   415 		
   415 
   416 		static final List<ThreadedNetConnection.ToNetMsgType> values = Collections.unmodifiableList(Arrays.asList(ToNetMsgType.values()));
   416         static final List<ThreadedNetConnection.ToNetMsgType> values = Collections.unmodifiableList(Arrays.asList(ToNetMsgType.values()));
   417 	}
   417     }
   418 	
   418 
   419 	/**
   419     /**
   420 	 * Processes messages to the networking system. Runs on a non-main thread.
   420      * Processes messages to the networking system. Runs on a non-main thread.
   421 	 */
   421      */
   422 	@SuppressLint("HandlerLeak")
   422     @SuppressLint("HandlerLeak")
   423 	public final class ToNetHandler extends Handler {
   423     public final class ToNetHandler extends Handler {
   424 		
   424 
   425 		public ToNetHandler(Looper looper) {
   425         public ToNetHandler(Looper looper) {
   426 			super(looper);
   426             super(looper);
   427 		}
   427         }
   428 		
   428 
   429 		@Override
   429         @Override
   430 		public void handleMessage(Message msg) {
   430         public void handleMessage(Message msg) {
   431 			switch(ToNetMsgType.values.get(msg.what)) {
   431             switch(ToNetMsgType.values.get(msg.what)) {
   432 			case MSG_SEND_NICK: {
   432             case MSG_SEND_NICK: {
   433 				FLIB.flib_netconn_send_nick(conn, (String)msg.obj);
   433                 FLIB.flib_netconn_send_nick(conn, (String)msg.obj);
   434 				break;
   434                 break;
   435 			}
   435             }
   436 			case MSG_SEND_PASSWORD: {
   436             case MSG_SEND_PASSWORD: {
   437 				FLIB.flib_netconn_send_password(conn, (String)msg.obj);
   437                 FLIB.flib_netconn_send_password(conn, (String)msg.obj);
   438 				break;
   438                 break;
   439 			}
   439             }
   440 			case MSG_SEND_QUIT: {
   440             case MSG_SEND_QUIT: {
   441 				FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
   441                 FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
   442 				break;
   442                 break;
   443 			}
   443             }
   444 			case MSG_SEND_ROOMLIST_REQUEST: {
   444             case MSG_SEND_ROOMLIST_REQUEST: {
   445 				FLIB.flib_netconn_send_request_roomlist(conn);
   445                 FLIB.flib_netconn_send_request_roomlist(conn);
   446 				break;
   446                 break;
   447 			}
   447             }
   448 			case MSG_SEND_PLAYER_INFO_REQUEST: {
   448             case MSG_SEND_PLAYER_INFO_REQUEST: {
   449 				FLIB.flib_netconn_send_playerInfo(conn, (String)msg.obj);
   449                 FLIB.flib_netconn_send_playerInfo(conn, (String)msg.obj);
   450 				break;
   450                 break;
   451 			}
   451             }
   452 			case MSG_SEND_CHAT: {
   452             case MSG_SEND_CHAT: {
   453 				if(FLIB.flib_netconn_send_chat(conn, (String)msg.obj) == 0) {
   453                 if(FLIB.flib_netconn_send_chat(conn, (String)msg.obj) == 0) {
   454 					sendFromNet(MSG_CHAT, Pair.create(playerName, (String)msg.obj));
   454                     sendFromNet(MSG_CHAT, Pair.create(playerName, (String)msg.obj));
   455 				}
   455                 }
   456 				break;
   456                 break;
   457 			}
   457             }
   458 			case MSG_SEND_TEAMCHAT: {
   458             case MSG_SEND_TEAMCHAT: {
   459 				FLIB.flib_netconn_send_teamchat(conn, (String)msg.obj);
   459                 FLIB.flib_netconn_send_teamchat(conn, (String)msg.obj);
   460 				break;
   460                 break;
   461 			}
   461             }
   462 			case MSG_SEND_FOLLOW_PLAYER: {
   462             case MSG_SEND_FOLLOW_PLAYER: {
   463 				FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj);
   463                 FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj);
   464 				break;
   464                 break;
   465 			}
   465             }
   466 			case MSG_SEND_JOIN_ROOM: {
   466             case MSG_SEND_JOIN_ROOM: {
   467 				FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj);
   467                 FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj);
   468 				break;
   468                 break;
   469 			}
   469             }
   470 			case MSG_SEND_CREATE_ROOM: {
   470             case MSG_SEND_CREATE_ROOM: {
   471 				FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj);
   471                 FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj);
   472 				break;
   472                 break;
   473 			}
   473             }
   474 			case MSG_SEND_LEAVE_ROOM: {
   474             case MSG_SEND_LEAVE_ROOM: {
   475 				if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) {
   475                 if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) {
   476 					sendFromNet(MSG_LEAVE_ROOM, -1, "");
   476                     sendFromNet(MSG_LEAVE_ROOM, -1, "");
   477 				}
   477                 }
   478 				break;
   478                 break;
   479 			}
   479             }
   480 			case MSG_SEND_KICK: {
   480             case MSG_SEND_KICK: {
   481 				FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
   481                 FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
   482 				break;
   482                 break;
   483 			}
   483             }
   484 			case MSG_SEND_ADD_TEAM: {
   484             case MSG_SEND_ADD_TEAM: {
   485 				FLIB.flib_netconn_send_addTeam(conn, TeamPtr.createJavaOwned((TeamInGame)msg.obj));
   485                 FLIB.flib_netconn_send_addTeam(conn, TeamPtr.createJavaOwned((TeamInGame)msg.obj));
   486 				break;
   486                 break;
   487 			}
   487             }
   488 			case MSG_SEND_REMOVE_TEAM: {
   488             case MSG_SEND_REMOVE_TEAM: {
   489 				if(FLIB.flib_netconn_send_removeTeam(conn, (String)msg.obj)==0) {
   489                 if(FLIB.flib_netconn_send_removeTeam(conn, (String)msg.obj)==0) {
   490 					sendFromNet(MSG_TEAM_DELETED, msg.obj);
   490                     sendFromNet(MSG_TEAM_DELETED, msg.obj);
   491 				}
   491                 }
   492 				break;
   492                 break;
   493 			}
   493             }
   494 			case MSG_DISCONNECT: {
   494             case MSG_DISCONNECT: {
   495 				FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
   495                 FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
   496 				shutdown(false, "User quit");
   496                 shutdown(false, "User quit");
   497 				break;
   497                 break;
   498 			}
   498             }
   499 			case MSG_SEND_TEAM_COLOR_INDEX: {
   499             case MSG_SEND_TEAM_COLOR_INDEX: {
   500 				FLIB.flib_netconn_send_teamColor(conn, (String)msg.obj, msg.arg1);
   500                 FLIB.flib_netconn_send_teamColor(conn, (String)msg.obj, msg.arg1);
   501 				break;
   501                 break;
   502 			}
   502             }
   503 			case MSG_SEND_TEAM_HOG_COUNT: {
   503             case MSG_SEND_TEAM_HOG_COUNT: {
   504 				FLIB.flib_netconn_send_teamHogCount(conn, (String)msg.obj, msg.arg1);
   504                 FLIB.flib_netconn_send_teamHogCount(conn, (String)msg.obj, msg.arg1);
   505 				break;
   505                 break;
   506 			}
   506             }
   507 			case MSG_SEND_ENGINE_MESSAGE: {
   507             case MSG_SEND_ENGINE_MESSAGE: {
   508 				byte[] message = (byte[])msg.obj;
   508                 byte[] message = (byte[])msg.obj;
   509 				ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
   509                 ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
   510 				FLIB.flib_netconn_send_engineMessage(conn, ptr, NativeSizeT.valueOf(message.length));
   510                 FLIB.flib_netconn_send_engineMessage(conn, ptr, NativeSizeT.valueOf(message.length));
   511 				break;
   511                 break;
   512 			}
   512             }
   513 			case MSG_SEND_ROUND_FINISHED: {
   513             case MSG_SEND_ROUND_FINISHED: {
   514 				FLIB.flib_netconn_send_roundfinished(conn, (Boolean)msg.obj);
   514                 FLIB.flib_netconn_send_roundfinished(conn, (Boolean)msg.obj);
   515 				break;
   515                 break;
   516 			}
   516             }
   517 			case MSG_SEND_TOGGLE_READY: {
   517             case MSG_SEND_TOGGLE_READY: {
   518 				FLIB.flib_netconn_send_toggleReady(conn);
   518                 FLIB.flib_netconn_send_toggleReady(conn);
   519 				break;
   519                 break;
   520 			}
   520             }
   521 			case MSG_SEND_START_GAME: {
   521             case MSG_SEND_START_GAME: {
   522 				FLIB.flib_netconn_send_startGame(conn);
   522                 FLIB.flib_netconn_send_startGame(conn);
   523 				break;
   523                 break;
   524 			}
   524             }
   525 			case MSG_SEND_WEAPONSET: {
   525             case MSG_SEND_WEAPONSET: {
   526 				FLIB.flib_netconn_send_weaponset(conn, WeaponsetPtr.createJavaOwned((Weaponset)msg.obj));
   526                 FLIB.flib_netconn_send_weaponset(conn, WeaponsetPtr.createJavaOwned((Weaponset)msg.obj));
   527 				break;
   527                 break;
   528 			}
   528             }
   529 			case MSG_SEND_MAP: {
   529             case MSG_SEND_MAP: {
   530 				FLIB.flib_netconn_send_map(conn, MapRecipePtr.createJavaOwned((MapRecipe)msg.obj));
   530                 FLIB.flib_netconn_send_map(conn, MapRecipePtr.createJavaOwned((MapRecipe)msg.obj));
   531 				break;
   531                 break;
   532 			}
   532             }
   533 			case MSG_SEND_MAP_NAME: {
   533             case MSG_SEND_MAP_NAME: {
   534 				FLIB.flib_netconn_send_mapName(conn, (String)msg.obj);
   534                 FLIB.flib_netconn_send_mapName(conn, (String)msg.obj);
   535 				break;
   535                 break;
   536 			}
   536             }
   537 			case MSG_SEND_MAP_GENERATOR: {
   537             case MSG_SEND_MAP_GENERATOR: {
   538 				FLIB.flib_netconn_send_mapGen(conn, msg.arg1);
   538                 FLIB.flib_netconn_send_mapGen(conn, msg.arg1);
   539 				break;
   539                 break;
   540 			}
   540             }
   541 			case MSG_SEND_MAP_TEMPLATE: {
   541             case MSG_SEND_MAP_TEMPLATE: {
   542 				FLIB.flib_netconn_send_mapTemplate(conn, msg.arg1);
   542                 FLIB.flib_netconn_send_mapTemplate(conn, msg.arg1);
   543 				break;
   543                 break;
   544 			}
   544             }
   545 			case MSG_SEND_MAZE_SIZE: {
   545             case MSG_SEND_MAZE_SIZE: {
   546 				FLIB.flib_netconn_send_mapMazeSize(conn, msg.arg1);
   546                 FLIB.flib_netconn_send_mapMazeSize(conn, msg.arg1);
   547 				break;
   547                 break;
   548 			}
   548             }
   549 			case MSG_SEND_MAP_SEED: {
   549             case MSG_SEND_MAP_SEED: {
   550 				FLIB.flib_netconn_send_mapSeed(conn, (String) msg.obj);
   550                 FLIB.flib_netconn_send_mapSeed(conn, (String) msg.obj);
   551 				break;
   551                 break;
   552 			}
   552             }
   553 			case MSG_SEND_MAP_THEME: {
   553             case MSG_SEND_MAP_THEME: {
   554 				FLIB.flib_netconn_send_mapTheme(conn, (String) msg.obj);
   554                 FLIB.flib_netconn_send_mapTheme(conn, (String) msg.obj);
   555 				break;
   555                 break;
   556 			}
   556             }
   557 			case MSG_SEND_MAP_DRAWDATA: {
   557             case MSG_SEND_MAP_DRAWDATA: {
   558 				byte[] message = (byte[])msg.obj;
   558                 byte[] message = (byte[])msg.obj;
   559 				ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
   559                 ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
   560 				FLIB.flib_netconn_send_mapDrawdata(conn, ptr, NativeSizeT.valueOf(message.length));
   560                 FLIB.flib_netconn_send_mapDrawdata(conn, ptr, NativeSizeT.valueOf(message.length));
   561 				break;
   561                 break;
   562 			}
   562             }
   563 			case MSG_SEND_GAMESTYLE: {
   563             case MSG_SEND_GAMESTYLE: {
   564 				FLIB.flib_netconn_send_script(conn, (String) msg.obj);
   564                 FLIB.flib_netconn_send_script(conn, (String) msg.obj);
   565 				break;
   565                 break;
   566 			}
   566             }
   567 			case MSG_SEND_SCHEME: {
   567             case MSG_SEND_SCHEME: {
   568 				FLIB.flib_netconn_send_scheme(conn, SchemePtr.createJavaOwned((Scheme) msg.obj));
   568                 FLIB.flib_netconn_send_scheme(conn, SchemePtr.createJavaOwned((Scheme) msg.obj));
   569 				break;
   569                 break;
   570 			}
   570             }
   571 			default: {
   571             default: {
   572 				Log.e("ToNetHandler", "Unknown message type: "+msg.what);
   572                 Log.e("ToNetHandler", "Unknown message type: "+msg.what);
   573 				break;
   573                 break;
   574 			}
   574             }
   575 			}
   575             }
   576 		}
   576         }
   577 	}
   577     }
   578 }
   578 }