project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java
changeset 7476 2fb781bbdd51
parent 7461 38acbfdb484f
child 7485 0481bd74267c
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java	Mon Aug 06 22:33:07 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java	Mon Aug 06 22:39:36 2012 +0200
@@ -5,19 +5,29 @@
 
 import org.hedgewars.hedgeroid.R;
 import org.hedgewars.hedgeroid.Utils;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.BoolCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.IntStrCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.MetaschemePtr;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.NetconnPtr;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomArrayPtr;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomListCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomPtr;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrRoomCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrStrCallback;
-import org.hedgewars.hedgeroid.netplay.JnaFrontlib.VoidCallback;
+import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.IntStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MetaschemePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.NetconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomListCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrIntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrRoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -58,31 +68,32 @@
 	private final LocalBroadcastManager broadcastManager;
 	private final FromNetHandler fromNetHandler = new FromNetHandler();
 	
-	private State state;
+	private State state = State.NOT_CONNECTED;
 	private int foregroundUsers = 0;	// Reference counter of clients requesting foreground tick speed (fast ticks)
 	private boolean chief;				// Do we control the current room?
+	private String playerName;
 	
 	// null if there is no running connection (==state is NOT_CONNECTED)
 	private ThreadedNetConnection connection;
 	
-	public final Playerlist playerList = new Playerlist();
+	public final LobbyPlayerlist lobbyPlayerlist = new LobbyPlayerlist();
+	public final RoomPlayerlist roomPlayerlist = new RoomPlayerlist();
 	public final Roomlist roomList = new Roomlist();
 	public final MessageLog lobbyChatlog;
 	public final MessageLog roomChatlog;
+	public final Teamlist roomTeamlist = new Teamlist();
 	
 	public Netplay(Context appContext) {
 		this.appContext = appContext;
 		broadcastManager = LocalBroadcastManager.getInstance(appContext);
 		lobbyChatlog = new MessageLog(appContext);
 		roomChatlog = new MessageLog(appContext);
-		state = State.NOT_CONNECTED;
 	}
 	
 	private void clearState() {
-		playerList.clear();
+		lobbyPlayerlist.clear();
 		roomList.clear();
 		lobbyChatlog.clear();
-		roomChatlog.clear();
 	}
 	
 	public void connectToDefaultServer(String playerName) {
@@ -97,6 +108,7 @@
 	 * will change back to NOT_CONNECTED and an ACTION_DISCONNECTED broadcast is sent.
 	 */
 	public void connect(String name, String host, int port) {
+		playerName = name;
 		if(state != State.NOT_CONNECTED) {
 			throw new IllegalStateException("Attempt to start a new connection while the old one was still running.");
 		}
@@ -107,7 +119,10 @@
 		connection.setFastTickRate(foregroundUsers > 0);
 	}
 	
-	public void sendNick(String nick) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_NICK, nick); }
+	public void sendNick(String nick) {
+		playerName = nick;
+		sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_NICK, nick);
+	}
 	public void sendPassword(String password) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_PASSWORD, password); }
 	public void sendQuit(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_QUIT, message); }
 	public void sendRoomlistRequest() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_ROOMLIST_REQUEST); }
@@ -117,6 +132,7 @@
 	public void sendJoinRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_JOIN_ROOM, name); }
 	public void sendCreateRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CREATE_ROOM, name); }
 	public void sendLeaveRoom(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_LEAVE_ROOM, message); }
+	public void sendKick(String player) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_KICK, player); }
 	
 	public void disconnect() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_DISCONNECT, "User Quit"); }
 	
@@ -155,6 +171,10 @@
 		return chief;
 	}
 	
+	public String getPlayerName() {
+		return playerName;
+	}
+	
 	/**
 	 * Indicate that you want network messages to be checked regularly (several times per second).
 	 * As long as nobody requests fast ticks, the network is only checked once every few seconds
@@ -210,6 +230,7 @@
 	/**
 	 * Processes messages from the networking system. Always runs on the main thread.
 	 */
+	@SuppressLint("HandlerLeak")
 	final class FromNetHandler extends Handler {
 		public static final int MSG_LOBBY_JOIN = 0;
 		public static final int MSG_LOBBY_LEAVE = 1;
@@ -226,6 +247,12 @@
 		public static final int MSG_PASSWORD_REQUEST = 12;
 		public static final int MSG_ENTER_ROOM_FROM_LOBBY = 13;
 		public static final int MSG_LEAVE_ROOM = 14;
+		public static final int MSG_READYSTATE = 15;
+		public static final int MSG_TEAM_ADDED = 16;
+		public static final int MSG_TEAM_DELETED = 17;
+		public static final int MSG_TEAM_ACCEPTED = 18;
+		public static final int MSG_TEAM_COLOR_CHANGED = 19;
+		public static final int MSG_HOG_COUNT_CHANGED = 20;
 		
 		public FromNetHandler() {
 			super(Looper.getMainLooper());
@@ -237,25 +264,25 @@
 			switch(msg.what) {
 			case MSG_LOBBY_JOIN: {
 				String name = (String)msg.obj;
-				playerList.addPlayerWithNewId(name);
+				lobbyPlayerlist.addPlayerWithNewId(name);
 				lobbyChatlog.appendPlayerJoin(name);
 				break;
 			}
 			case MSG_LOBBY_LEAVE: {
 				Pair<String, String> args = (Pair<String, String>)msg.obj;
-				playerList.removePlayer(args.first);
+				lobbyPlayerlist.remove(args.first);
 				lobbyChatlog.appendPlayerLeave(args.first, args.second);
 				break;
 			}
 			case MSG_ROOM_JOIN: {
 				String name = (String)msg.obj;
-				// TODO roomPlayerList.addPlayerWithNewId(name);
+				roomPlayerlist.addPlayerWithNewId(name);
 				roomChatlog.appendPlayerJoin(name);
 				break;
 			}
 			case MSG_ROOM_LEAVE: {
 				Pair<String, String> args = (Pair<String, String>)msg.obj;
-				// TODO roomPlayerList.removePlayer(args.first);
+				roomPlayerlist.remove(args.first);
 				roomChatlog.appendPlayerLeave(args.first, args.second);
 				break;
 			}
@@ -269,23 +296,24 @@
 				break;
 			}
 			case MSG_ROOM_ADD: {
-				roomList.addRoomWithNewId((Room)msg.obj);
+				roomList.addRoomWithNewId((RoomlistRoom)msg.obj);
 				break;
 			}
 			case MSG_ROOM_UPDATE: {
-				Pair<String, Room> args = (Pair<String, Room>)msg.obj;
+				Pair<String, RoomlistRoom> args = (Pair<String, RoomlistRoom>)msg.obj;
 				roomList.updateRoom(args.first, args.second);
 				break;
 			}
 			case MSG_ROOM_DELETE: {
-				roomList.removeRoom((String)msg.obj);
+				roomList.remove((String)msg.obj);
 				break;
 			}
 			case MSG_ROOMLIST: {
-				roomList.updateList((Room[])msg.obj);
+				roomList.updateList((RoomlistRoom[])msg.obj);
 				break;
 			}
 			case MSG_CONNECTED: {
+				playerName = (String)msg.obj;
 				changeState(State.LOBBY);
 				broadcastManager.sendBroadcast(new Intent(ACTION_CONNECTED));
 				break;
@@ -308,6 +336,8 @@
 			}
 			case MSG_ENTER_ROOM_FROM_LOBBY: {
 				roomChatlog.clear();
+				roomPlayerlist.clear();
+				roomTeamlist.clear();
 				changeState(State.ROOM);
 				chief = (Boolean)msg.obj;
 				Intent intent = new Intent(ACTION_ENTERED_ROOM_FROM_LOBBY);
@@ -322,6 +352,45 @@
 				broadcastManager.sendBroadcastSync(intent);
 				break;
 			}
+			case MSG_READYSTATE: {
+				Pair<String, Boolean> args = (Pair<String, Boolean>)msg.obj;
+				roomPlayerlist.setReady(args.first, args.second);
+				break;
+			}
+			case MSG_TEAM_ADDED: {
+				roomTeamlist.addTeamWithNewId((TeamInGame)msg.obj);
+				break;
+			}
+			case MSG_TEAM_DELETED: {
+				roomTeamlist.remove((String)msg.obj);
+				break;
+			}
+			case MSG_TEAM_ACCEPTED: {
+				// TODO depends: adding teams
+				break;
+			}
+			case MSG_TEAM_COLOR_CHANGED: {
+				Pair<TeamInGame, Long> oldEntry = roomTeamlist.get((String)msg.obj);
+				if(oldEntry != null) {
+					TeamInGame tig = oldEntry.first;
+					TeamIngameAttributes tiga = tig.ingameAttribs.withColorIndex(msg.arg1);
+					roomTeamlist.put(tig.team.name, Pair.create(tig.withAttribs(tiga), oldEntry.second));
+				} else {
+					Log.e("Netplay", "Color update for unknown team "+msg.obj);
+				}
+				break;
+			}
+			case MSG_HOG_COUNT_CHANGED: {
+				Pair<TeamInGame, Long> oldEntry = roomTeamlist.get((String)msg.obj);
+				if(oldEntry != null) {
+					TeamInGame tig = oldEntry.first;
+					TeamIngameAttributes tiga = tig.ingameAttribs.withHogCount(msg.arg1);
+					roomTeamlist.put(tig.team.name, Pair.create(tig.withAttribs(tiga), oldEntry.second));
+				} else {
+					Log.e("Netplay", "Hog count update for unknown team "+msg.obj);
+				}
+				break;
+			}
 			default: {
 				Log.e("FromNetHandler", "Unknown message type: "+msg.what);
 				break;
@@ -336,7 +405,7 @@
 	private static class ThreadedNetConnection {
 		private static final long TICK_INTERVAL_FAST = 100;
 		private static final long TICK_INTERVAL_SLOW = 5000;
-		private static final JnaFrontlib FLIB = Flib.INSTANCE;
+		private static final Frontlib FLIB = Flib.INSTANCE;
 		
 		public final ToNetHandler toNetHandler;
 		
@@ -399,6 +468,12 @@
 					FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
 					FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
 					FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
+					FLIB.flib_netconn_onReadyState(conn, readyStateCb, null);
+					FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
+					FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
+					FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
+					FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
+					FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
 					
 					FLIB.flib_metascheme_release(meta);
 					tickHandler.start();
@@ -496,7 +571,7 @@
 		
 		private final BoolCallback enterRoomCb = new BoolCallback() {
 			public void callback(Pointer context, boolean isChief) {
-				sendFromNet(FromNetHandler.MSG_ENTER_ROOM_FROM_LOBBY, Boolean.TRUE);
+				sendFromNet(FromNetHandler.MSG_ENTER_ROOM_FROM_LOBBY, isChief);
 			}
 		};
 		
@@ -506,6 +581,42 @@
 			}
 		};
 		
+		private final StrBoolCallback readyStateCb = new StrBoolCallback() {
+			public void callback(Pointer context, String player, boolean ready) {
+				sendFromNet(FromNetHandler.MSG_READYSTATE, Pair.create(player, ready));
+			}
+		};
+		
+		private final TeamCallback teamAddedCb = new TeamCallback() {
+			public void callback(Pointer context, TeamPtr team) {
+				sendFromNet(FromNetHandler.MSG_TEAM_ADDED, team.deref());
+			}
+		};
+		
+		private final StrCallback teamDeletedCb = new StrCallback() {
+			public void callback(Pointer context, String teamName) {
+				sendFromNet(FromNetHandler.MSG_TEAM_DELETED, teamName);
+			}
+		};
+		
+		private final StrCallback teamAcceptedCb = new StrCallback() {
+			public void callback(Pointer context, String teamName) {
+				sendFromNet(FromNetHandler.MSG_TEAM_ACCEPTED, teamName);
+			}
+		};
+		
+		private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
+			public void callback(Pointer context, String teamName, int colorIndex) {
+				sendFromNet(FromNetHandler.MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
+			}
+		};
+		
+		private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
+			public void callback(Pointer context, String teamName, int hogCount) {
+				sendFromNet(FromNetHandler.MSG_HOG_COUNT_CHANGED, hogCount, teamName);
+			}
+		};
+		
 		private void shutdown(boolean error, String message) {
 			if(conn != null) {
 				FLIB.flib_netconn_destroy(conn);
@@ -518,7 +629,7 @@
 		
 		private final IntStrCallback disconnectCb = new IntStrCallback() {
 			public void callback(Pointer context, int reason, String message) {
-				Boolean error = reason != JnaFrontlib.NETCONN_DISCONNECT_NORMAL;
+				Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
 				String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
 				shutdown(error, messageForUser);
 			}
@@ -526,13 +637,13 @@
 		
 		private static String createDisconnectUserMessage(Resources res, int reason, String message) {
 			switch(reason) {
-			case JnaFrontlib.NETCONN_DISCONNECT_AUTH_FAILED:
+			case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
 				return res.getString(R.string.error_auth_failed);
-			case JnaFrontlib.NETCONN_DISCONNECT_CONNLOST:
+			case Frontlib.NETCONN_DISCONNECT_CONNLOST:
 				return res.getString(R.string.error_connection_lost);
-			case JnaFrontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
+			case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
 				return res.getString(R.string.error_unexpected, message);
-			case JnaFrontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
+			case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
 				return res.getString(R.string.error_server_too_old);
 			default:
 				return message;
@@ -550,6 +661,7 @@
 		/**
 		 * Processes messages to the networking system. Runs on a non-main thread.
 		 */
+		@SuppressLint("HandlerLeak")
 		public final class ToNetHandler extends Handler {
 			public static final int MSG_SEND_NICK = 0;
 			public static final int MSG_SEND_PASSWORD = 1;
@@ -561,8 +673,9 @@
 			public static final int MSG_SEND_JOIN_ROOM = 7;
 			public static final int MSG_SEND_CREATE_ROOM = 8;
 			public static final int MSG_SEND_LEAVE_ROOM = 9;
+			public static final int MSG_SEND_KICK = 10;
 			
-			public static final int MSG_DISCONNECT = 10;
+			public static final int MSG_DISCONNECT = 11;
 			
 			public ToNetHandler(Looper looper) {
 				super(looper);
@@ -615,6 +728,10 @@
 					}
 					break;
 				}
+				case MSG_SEND_KICK: {
+					FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
+					break;
+				}
 				case MSG_DISCONNECT: {
 					FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
 					shutdown(false, "User quit");