project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetplayService.java
changeset 7358 57a508884052
parent 7355 5673e95ef647
child 7439 0a494f951dcf
equal deleted inserted replaced
7355:5673e95ef647 7358:57a508884052
     1 package org.hedgewars.hedgeroid.netplay;
       
     2 
       
     3 import java.io.File;
       
     4 import java.io.FileNotFoundException;
       
     5 
       
     6 import org.hedgewars.hedgeroid.R;
       
     7 import org.hedgewars.hedgeroid.Utils;
       
     8 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.IntStrCallback;
       
     9 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.MetaschemePtr;
       
    10 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.NetconnPtr;
       
    11 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomArrayPtr;
       
    12 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomCallback;
       
    13 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomListCallback;
       
    14 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomPtr;
       
    15 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrCallback;
       
    16 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrRoomCallback;
       
    17 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrStrCallback;
       
    18 import org.hedgewars.hedgeroid.netplay.JnaFrontlib.VoidCallback;
       
    19 
       
    20 import com.sun.jna.Pointer;
       
    21 
       
    22 import android.app.Service;
       
    23 import android.content.Intent;
       
    24 import android.os.Binder;
       
    25 import android.os.IBinder;
       
    26 import android.support.v4.content.LocalBroadcastManager;
       
    27 import android.util.Log;
       
    28 
       
    29 public class NetplayService extends Service {
       
    30 	// Parameter extras for starting the service
       
    31 	public static final String EXTRA_PLAYERNAME = "playername";
       
    32 	public static final String EXTRA_PORT = "port";
       
    33 	public static final String EXTRA_HOST = "host";
       
    34 	
       
    35 	// Extras in broadcasts
       
    36 	public static final String EXTRA_MESSAGE = "message";
       
    37 	public static final String EXTRA_HAS_ERROR = "hasError";
       
    38 	
       
    39 	
       
    40 	private static final String ACTIONPREFIX = "org.hedgewars.hedgeroid.netconn.";
       
    41 	public static final String ACTION_DISCONNECTED = ACTIONPREFIX+"DISCONNECTED";
       
    42 	public static final String ACTION_CONNECTED = ACTIONPREFIX+"CONNECTED";
       
    43 	
       
    44 	private static final JnaFrontlib FLIB = Flib.INSTANCE;
       
    45 	public static final String DEFAULT_SERVER = "netserver.hedgewars.org";
       
    46 	public static final int DEFAULT_PORT = 46631;
       
    47 	
       
    48 	private static final long TICK_INTERVAL_MS_BOUND = 100;
       
    49 	private static final long TICK_INTERVAL_MS_UNBOUND = 2000;
       
    50 	
       
    51 	// null if the service is not active. Only updated from the main thread.
       
    52 	public static NetplayService instance;
       
    53 	
       
    54 	private final NetplayBinder binder = new NetplayBinder();
       
    55 	private TickHandler tickHandler;
       
    56 	private LocalBroadcastManager broadcastManager;
       
    57 	
       
    58 	private String playerName;
       
    59 	private NetconnPtr conn;
       
    60 	private boolean joined; // True once we have been admitted to the lobby
       
    61 	
       
    62 	public final PlayerList playerList = new PlayerList();
       
    63 	public final RoomList roomList = new RoomList();
       
    64 	public MessageLog lobbyChatlog;
       
    65 	public MessageLog roomChatlog;
       
    66 	
       
    67 	@Override
       
    68 	public IBinder onBind(Intent intent) {
       
    69 		Log.d("NetplayService", "onBind");
       
    70 		tickHandler.setInterval(TICK_INTERVAL_MS_BOUND);
       
    71 		return binder;
       
    72 	}
       
    73 	
       
    74 	@Override
       
    75 	public void onRebind(Intent intent) {
       
    76 		Log.d("NetplayService", "onRebind");
       
    77 		tickHandler.setInterval(TICK_INTERVAL_MS_BOUND);
       
    78 	}
       
    79 	
       
    80 	@Override
       
    81 	public boolean onUnbind(Intent intent) {
       
    82 		Log.d("NetplayService", "onUnbind");
       
    83 		tickHandler.setInterval(TICK_INTERVAL_MS_UNBOUND);
       
    84 		return true;
       
    85 	}
       
    86 	
       
    87 	@Override
       
    88 	public int onStartCommand(Intent intent, int flags, int startId) {
       
    89 		Log.d("NetplayService", "onStartCommand");
       
    90 		if(conn != null) {
       
    91 			Log.e("NetplayService", "Attempt to start while running");
       
    92 			return START_NOT_STICKY;
       
    93 		}
       
    94 		joined = false;
       
    95 		playerList.clear();
       
    96 		roomList.clear();
       
    97 		lobbyChatlog.clear();
       
    98 		roomChatlog.clear();
       
    99 		
       
   100 		playerName = intent.getStringExtra(EXTRA_PLAYERNAME);
       
   101 		if(playerName == null) playerName = "Player";
       
   102 		int port = intent.getIntExtra(EXTRA_PORT, DEFAULT_PORT);
       
   103 		String host = intent.getStringExtra(EXTRA_HOST);
       
   104 		if(host==null) host = DEFAULT_SERVER;
       
   105 		
       
   106 		MetaschemePtr meta = null;
       
   107 		File dataPath;
       
   108 		try {
       
   109 			dataPath = Utils.getDataPathFile(getApplicationContext());
       
   110 		} catch (FileNotFoundException e) {
       
   111 			stopWithError(getString(R.string.sdcard_not_mounted));
       
   112 			return START_NOT_STICKY;
       
   113 		}
       
   114 		String metaschemePath = new File(dataPath, "metasettings.ini").getAbsolutePath();
       
   115 		meta = FLIB.flib_metascheme_from_ini(metaschemePath);
       
   116 		if(meta == null) {
       
   117 			stopWithError(getString(R.string.error_unexpected, "Missing metasettings.ini"));
       
   118 			return START_NOT_STICKY;
       
   119 		}
       
   120 		conn = FLIB.flib_netconn_create(playerName, meta, dataPath.getAbsolutePath(), host, port);
       
   121 		if(conn == null) {
       
   122 			stopWithError(getString(R.string.error_connection_failed));
       
   123 			return START_NOT_STICKY;
       
   124 		}
       
   125 		FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
       
   126 		FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
       
   127 		FLIB.flib_netconn_onChat(conn, chatCb, null);
       
   128 		FLIB.flib_netconn_onMessage(conn, messageCb, null);
       
   129 		FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
       
   130 		FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
       
   131 		FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
       
   132 		FLIB.flib_netconn_onConnected(conn, connectedCb, null);
       
   133 		FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
       
   134 		FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
       
   135 		FLIB.flib_metascheme_release(meta);
       
   136 		tickHandler.start();
       
   137 		instance = this;
       
   138 		return START_NOT_STICKY;
       
   139 	}
       
   140 	
       
   141 	private void stopWithoutError() {
       
   142 		Intent intent = new Intent(ACTION_DISCONNECTED);
       
   143 		intent.putExtra(EXTRA_HAS_ERROR, false);
       
   144 		broadcastManager.sendBroadcast(intent);
       
   145 		stopSelf();
       
   146 	}
       
   147 	
       
   148 	private void stopWithError(String userMessage) {
       
   149 		Intent intent = new Intent(ACTION_DISCONNECTED);
       
   150 		intent.putExtra(EXTRA_MESSAGE, userMessage);
       
   151 		intent.putExtra(EXTRA_HAS_ERROR, true);
       
   152 		broadcastManager.sendBroadcast(intent);
       
   153 		stopSelf();
       
   154 	}
       
   155 	
       
   156 	@Override
       
   157 	public void onCreate() {
       
   158 		Log.d("NetplayService", "onCreate");
       
   159 		broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext());
       
   160 		lobbyChatlog = new MessageLog(getApplicationContext());
       
   161 		roomChatlog = new MessageLog(getApplicationContext());
       
   162 		tickHandler = new TickHandler(getMainLooper(), TICK_INTERVAL_MS_UNBOUND, new Runnable() {
       
   163 			public void run() {
       
   164 				if(conn != null) {
       
   165 					FLIB.flib_netconn_tick(conn);
       
   166 				}
       
   167 			}
       
   168 		});
       
   169 		if(Flib.INSTANCE.flib_init() != 0) {
       
   170 			stopWithError(getString(R.string.error_unexpected, "Unable to start frontlib"));
       
   171 		}
       
   172 	}
       
   173 	
       
   174 	@Override
       
   175 	public void onDestroy() {
       
   176 		instance = null;
       
   177 		Log.d("NetplayService", "onDestroy");
       
   178 		tickHandler.stop();
       
   179 		if(conn != null) {
       
   180 			FLIB.flib_netconn_destroy(conn);
       
   181 			conn = null;
       
   182 		}
       
   183 		Flib.INSTANCE.flib_quit();
       
   184 	}
       
   185 
       
   186 	public class NetplayBinder extends Binder {
       
   187 		NetplayService getService() {
       
   188             return NetplayService.this;
       
   189         }
       
   190 	}
       
   191 	
       
   192 	private StrCallback lobbyJoinCb = new StrCallback() {
       
   193 		public void callback(Pointer context, String arg1) {
       
   194 			playerList.addPlayerWithNewId(arg1);
       
   195 			lobbyChatlog.appendPlayerJoin(arg1);
       
   196 		}
       
   197 	};
       
   198 	
       
   199 	private StrStrCallback lobbyLeaveCb = new StrStrCallback() {
       
   200 		public void callback(Pointer context, String name, String msg) {
       
   201 			playerList.removePlayer(name);
       
   202 			lobbyChatlog.appendPlayerLeave(name, msg);
       
   203 		}
       
   204 	};
       
   205 	
       
   206 	private StrStrCallback chatCb = new StrStrCallback() {
       
   207 		public void callback(Pointer context, String name, String msg) {
       
   208 			getCurrentLog().appendChat(name, msg);
       
   209 		}
       
   210 	};
       
   211 	
       
   212 	private IntStrCallback messageCb = new IntStrCallback() {
       
   213 		public void callback(Pointer context, int type, String msg) {
       
   214 			getCurrentLog().appendMessage(type, msg);
       
   215 		}
       
   216 	};
       
   217 	
       
   218 	private RoomCallback roomAddCb = new RoomCallback() {
       
   219 		public void callback(Pointer context, RoomPtr roomPtr) {
       
   220 			roomList.addRoomWithNewId(roomPtr);
       
   221 		}
       
   222 	};
       
   223 	
       
   224 	private StrRoomCallback roomUpdateCb = new StrRoomCallback() {
       
   225 		public void callback(Pointer context, String name, RoomPtr roomPtr) {
       
   226 			roomList.updateRoom(name, roomPtr);
       
   227 		}
       
   228 	};
       
   229 	
       
   230 	private StrCallback roomDeleteCb = new StrCallback() {
       
   231 		public void callback(Pointer context, String name) {
       
   232 			roomList.removeRoom(name);
       
   233 		}
       
   234 	};
       
   235 	
       
   236 	private VoidCallback connectedCb = new VoidCallback() {
       
   237 		public void callback(Pointer context) {
       
   238 			broadcastManager.sendBroadcast(new Intent(ACTION_CONNECTED));
       
   239 			joined = true;
       
   240 			FLIB.flib_netconn_send_request_roomlist(conn);
       
   241 		}
       
   242 	};
       
   243 	
       
   244 	private RoomListCallback roomlistCb = new RoomListCallback() {
       
   245 		public void callback(Pointer context, RoomArrayPtr arg1, int count) {
       
   246 			roomList.updateList(arg1.getRooms(count));
       
   247 		}
       
   248 	};
       
   249 	
       
   250 	private IntStrCallback disconnectCb = new IntStrCallback() {
       
   251 		public void callback(Pointer context, int reason, String arg2) {
       
   252 			switch(reason) {
       
   253 			case JnaFrontlib.NETCONN_DISCONNECT_AUTH_FAILED:
       
   254 				stopWithError(getString(R.string.error_auth_failed));
       
   255 				break;
       
   256 			case JnaFrontlib.NETCONN_DISCONNECT_CONNLOST:
       
   257 				stopWithError(getString(R.string.error_connection_lost));
       
   258 				break;
       
   259 			case JnaFrontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
       
   260 				stopWithError(getString(R.string.error_unexpected, arg2));
       
   261 				break;
       
   262 			case JnaFrontlib.NETCONN_DISCONNECT_NORMAL:
       
   263 				stopWithoutError();
       
   264 				break;
       
   265 			case JnaFrontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
       
   266 				stopWithError(getString(R.string.error_server_too_old));
       
   267 				break;
       
   268 			default:
       
   269 				stopWithError(arg2);
       
   270 				break;
       
   271 			}
       
   272 			FLIB.flib_netconn_destroy(conn);
       
   273 			conn = null;
       
   274 		}
       
   275 	};
       
   276 	
       
   277 	public void disconnect() {
       
   278 		if(conn != null) {
       
   279 			FLIB.flib_netconn_send_quit(conn, "User quit");
       
   280 			FLIB.flib_netconn_destroy(conn);
       
   281 			conn = null;
       
   282 		}
       
   283 		stopWithoutError();
       
   284 	}
       
   285 	
       
   286 	public void sendChat(String s) {
       
   287 		FLIB.flib_netconn_send_chat(conn, s);
       
   288 		if(FLIB.flib_netconn_is_in_room_context(conn)) {
       
   289 			roomChatlog.appendChat(playerName, s);
       
   290 		} else {
       
   291 			lobbyChatlog.appendChat(playerName, s);
       
   292 		}
       
   293 	}
       
   294 	
       
   295 	private MessageLog getCurrentLog() {
       
   296 		if(FLIB.flib_netconn_is_in_room_context(conn)) {
       
   297 			return roomChatlog;
       
   298 		} else {
       
   299 			return lobbyChatlog;
       
   300 		}
       
   301 	}
       
   302 	
       
   303 	public void sendNick(String nick) { FLIB.flib_netconn_send_nick(conn, nick); }
       
   304 	public void sendPassword(String password) { FLIB.flib_netconn_send_password(conn, password); }
       
   305 	public void sendQuit(String message) { FLIB.flib_netconn_send_quit(conn, message); }
       
   306 	public void sendRoomlistRequest() { if(joined) FLIB.flib_netconn_send_request_roomlist(conn); }
       
   307 	public void sendPlayerInfoQuery(String name) { FLIB.flib_netconn_send_playerInfo(conn, name); }
       
   308 	
       
   309 	public boolean isConnected() {
       
   310 		return conn != null;
       
   311 	}
       
   312 
       
   313 	public static boolean isActive() {
       
   314 		return instance!=null;
       
   315 	}
       
   316 }
       
   317