diff -r ed1d52c5aa94 -r 763d3961400b project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java Sat Aug 18 00:47:51 2012 +0200 @@ -0,0 +1,214 @@ +package org.hedgewars.hedgeroid; + +import org.hedgewars.hedgeroid.Datastructures.GameConfig; +import org.hedgewars.hedgeroid.frontlib.Flib; +import org.hedgewars.hedgeroid.frontlib.Frontlib; +import org.hedgewars.hedgeroid.frontlib.Frontlib.BytesCallback; +import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr; +import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr; +import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback; +import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback; +import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback; +import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback; +import org.hedgewars.hedgeroid.netplay.GameMessageListener; +import org.hedgewars.hedgeroid.netplay.Netplay; +import org.hedgewars.hedgeroid.util.TickHandler; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.util.Log; + +import com.sun.jna.Memory; +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; + +public final class GameConnection { + private static final Handler mainHandler = new Handler(Looper.getMainLooper()); + + private final HandlerThread thread; + private final Handler handler; + private final TickHandler tickHandler; + private final Netplay netplay; // ==null if not a netgame + private GameconnPtr conn; + + /** + * The actual connection has to be set up on a separate thread because networking + * is not allowed on the UI thread, so the port can't be queried immediately after + * creating the GameConnection object. Instead, one of these interface methods is + * called once we know which port we are listening on (or once we fail to set this up). + * Methods will be called on the UI thread. + */ + public static interface Listener { + /** + * We are listening for the engine at $port, go start the engine. + */ + void gameConnectionReady(int port); + + /** + * The connection has stopped, either because the game has ended or was interrupted, + * or maybe we failed to create the connection at all (in that case gameConnectionReady wasn't called). + */ + void gameConnectionDisconnected(int reason); + } + + private GameConnection(Netplay netplay) { + this.netplay = netplay; + thread = new HandlerThread("IPCThread"); + thread.start(); + handler = new Handler(thread.getLooper()); + tickHandler = new TickHandler(thread.getLooper(), 50, new Runnable() { + public void run() { + if(conn != null) { + Flib.INSTANCE.flib_gameconn_tick(conn); + } + } + }); + tickHandler.start(); + } + + public static GameConnection forNetgame(final GameConfig config, Netplay netplay, final Listener listener) { + final GameConnection result = new GameConnection(netplay); + final String playerName = netplay.getPlayerName(); + result.handler.post(new Runnable() { + public void run() { + GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true); + result.setupConnection(conn, true, listener); + } + }); + return result; + } + + public static GameConnection forLocalGame(final GameConfig config, final Listener listener) { + final GameConnection result = new GameConnection(null); + result.handler.post(new Runnable() { + public void run() { + GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false); + result.setupConnection(conn, false, listener); + } + }); + return result; + } + + // runs on the IPCThread + private void setupConnection(GameconnPtr conn, final boolean netgame, final Listener listener) { + if(conn == null) { + mainHandler.post(new Runnable() { + public void run() { listener.gameConnectionDisconnected(Frontlib.GAME_END_ERROR); } + }); + shutdown(); + } else { + this.conn = conn; + final int port = Flib.INSTANCE.flib_gameconn_getport(conn); + mainHandler.post(new Runnable() { + public void run() { + listener.gameConnectionReady(port); + if(netgame) { + netplay.registerGameMessageListener(gameMessageListener); + } + } + }); + Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null); + Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null); + Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null); + if(netgame) { + Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null); + Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null); + } + } + } + + // runs on the IPCThread + private void shutdown() { + tickHandler.stop(); + thread.quit(); + Flib.INSTANCE.flib_gameconn_destroy(conn); + if(netplay != null) { + mainHandler.post(new Runnable() { + public void run() { + netplay.unregisterGameMessageListener(gameMessageListener); + } + }); + } + } + + // runs on the IPCThread + private final StrBoolCallback chatCb = new StrBoolCallback() { + public void callback(Pointer context, String message, boolean teamChat) { + if(teamChat) { + netplay.sendTeamChat(message); + } else { + netplay.sendChat(message); + } + } + }; + + // runs on the IPCThread + private final VoidCallback connectCb = new VoidCallback() { + public void callback(Pointer context) { + Log.i("GameConnection", "Connected"); + } + }; + + // runs on the IPCThread + private final IntCallback disconnectCb = new IntCallback() { + public void callback(Pointer context, int reason) { + if(netplay != null) { + netplay.sendRoundFinished(reason==Frontlib.GAME_END_FINISHED); + } + shutdown(); + } + }; + + // runs on the IPCThread + private final BytesCallback engineMessageCb = new BytesCallback() { + public void callback(Pointer context, Pointer buffer, NativeLong size) { + netplay.sendEngineMessage(buffer.getByteArray(0, size.intValue())); + } + }; + + // runs on the IPCThread + private final StrCallback errorMessageCb = new StrCallback() { + public void callback(Pointer context, String message) { + Log.e("GameConnection", message); + } + }; + + // runs on any thread + private final GameMessageListener gameMessageListener = new GameMessageListener() { + public void onNetDisconnected() { + handler.post(new Runnable() { + public void run() { + shutdown(); + } + }); + } + + public void onMessage(final int type, final String message) { + handler.post(new Runnable() { + public void run() { + Flib.INSTANCE.flib_gameconn_send_textmsg(conn, type, message); + } + }); + } + + public void onEngineMessage(final byte[] em) { + handler.post(new Runnable() { + public void run() { + Memory mem = new Memory(em.length); + mem.write(0, em, 0, em.length); + Flib.INSTANCE.flib_gameconn_send_enginemsg(conn, mem, new NativeLong(em.length)); + } + }); + + } + + public void onChatMessage(final String nick, final String message) { + handler.post(new Runnable() { + public void run() { + Flib.INSTANCE.flib_gameconn_send_chatmsg(conn, nick, message); + } + }); + } + }; +}