46 |
46 |
47 /** |
47 /** |
48 * This class handles both talking to the engine (IPC) for running a game, and |
48 * This class handles both talking to the engine (IPC) for running a game, and |
49 * coordinating with the netconn if it is a netgame, using the frontlib for the |
49 * coordinating with the netconn if it is a netgame, using the frontlib for the |
50 * actual IPC networking communication. |
50 * actual IPC networking communication. |
51 * |
51 * |
52 * After creating the GameConnection object, it will communicate with the engine |
52 * After creating the GameConnection object, it will communicate with the engine |
53 * on its own thread. It shuts itself down as soon as the connection to the engine |
53 * on its own thread. It shuts itself down as soon as the connection to the engine |
54 * is lost. |
54 * is lost. |
55 */ |
55 */ |
56 public final class GameConnection { |
56 public final class GameConnection { |
57 private static final Handler mainHandler = new Handler(Looper.getMainLooper()); |
57 private static final Handler mainHandler = new Handler(Looper.getMainLooper()); |
58 |
58 |
59 public final int port; |
59 public final int port; |
60 private final HandlerThread thread; |
60 private final HandlerThread thread; |
61 private final Handler handler; |
61 private final Handler handler; |
62 private TickHandler tickHandler; |
62 private TickHandler tickHandler; |
63 private final Netplay netplay; // ==null if not a netgame |
63 private final Netplay netplay; // ==null if not a netgame |
64 private GameconnPtr conn; |
64 private GameconnPtr conn; |
65 |
65 |
66 private GameConnection(GameconnPtr conn, Netplay netplay) { |
66 private GameConnection(GameconnPtr conn, Netplay netplay) { |
67 this.conn = conn; |
67 this.conn = conn; |
68 this.port = Flib.INSTANCE.flib_gameconn_getport(conn); |
68 this.port = Flib.INSTANCE.flib_gameconn_getport(conn); |
69 this.netplay = netplay; |
69 this.netplay = netplay; |
70 this.thread = new HandlerThread("IPCThread"); |
70 this.thread = new HandlerThread("IPCThread"); |
71 thread.start(); |
71 thread.start(); |
72 this.handler = new Handler(thread.getLooper()); |
72 this.handler = new Handler(thread.getLooper()); |
73 } |
73 } |
74 |
74 |
75 private void setupConnection() { |
75 private void setupConnection() { |
76 tickHandler = new TickHandler(thread.getLooper(), 50, tickCb); |
76 tickHandler = new TickHandler(thread.getLooper(), 50, tickCb); |
77 tickHandler.start(); |
77 tickHandler.start(); |
78 |
78 |
79 if(netplay != null) { |
79 if(netplay != null) { |
80 mainHandler.post(new Runnable() { |
80 mainHandler.post(new Runnable() { |
81 public void run() { |
81 public void run() { |
82 netplay.registerGameMessageListener(gameMessageListener); |
82 netplay.registerGameMessageListener(gameMessageListener); |
83 } |
83 } |
84 }); |
84 }); |
85 Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null); |
85 Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null); |
86 Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null); |
86 Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null); |
87 } |
87 } |
88 Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null); |
88 Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null); |
89 Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null); |
89 Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null); |
90 Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null); |
90 Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null); |
91 } |
91 } |
92 |
92 |
93 /** |
93 /** |
94 * Start a new IPC server to communicate with the engine. |
94 * Start a new IPC server to communicate with the engine. |
95 * Performs networking operations, don't run on the UI thread. |
95 * Performs networking operations, don't run on the UI thread. |
96 * @throws ConnectException if we can't set up the IPC server |
96 * @throws ConnectException if we can't set up the IPC server |
97 */ |
97 */ |
98 public static GameConnection forNetgame(final GameConfig config, Netplay netplay) throws ConnectException { |
98 public static GameConnection forNetgame(final GameConfig config, Netplay netplay) throws ConnectException { |
99 final String playerName = netplay.getPlayerName(); |
99 final String playerName = netplay.getPlayerName(); |
100 GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true); |
100 GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true); |
101 if(conn == null) { |
101 if(conn == null) { |
102 throw new ConnectException(); |
102 throw new ConnectException(); |
103 } |
103 } |
104 GameConnection result = new GameConnection(conn, netplay); |
104 GameConnection result = new GameConnection(conn, netplay); |
105 result.setupConnection(); |
105 result.setupConnection(); |
106 return result; |
106 return result; |
107 } |
107 } |
108 |
108 |
109 /** |
109 /** |
110 * Start a new IPC server to communicate with the engine. |
110 * Start a new IPC server to communicate with the engine. |
111 * Performs networking operations, don't run on the UI thread. |
111 * Performs networking operations, don't run on the UI thread. |
112 * @throws ConnectException if we can't set up the IPC server |
112 * @throws ConnectException if we can't set up the IPC server |
113 */ |
113 */ |
114 public static GameConnection forLocalGame(final GameConfig config) throws ConnectException { |
114 public static GameConnection forLocalGame(final GameConfig config) throws ConnectException { |
115 GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false); |
115 GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false); |
116 if(conn == null) { |
116 if(conn == null) { |
117 throw new ConnectException(); |
117 throw new ConnectException(); |
118 } |
118 } |
119 GameConnection result = new GameConnection(conn, null); |
119 GameConnection result = new GameConnection(conn, null); |
120 result.setupConnection(); |
120 result.setupConnection(); |
121 return result; |
121 return result; |
122 } |
122 } |
123 |
123 |
124 private final Runnable tickCb = new Runnable() { |
124 private final Runnable tickCb = new Runnable() { |
125 public void run() { |
125 public void run() { |
126 Flib.INSTANCE.flib_gameconn_tick(conn); |
126 Flib.INSTANCE.flib_gameconn_tick(conn); |
127 } |
127 } |
128 }; |
128 }; |
129 |
129 |
130 // runs on the IPCThread |
130 // runs on the IPCThread |
131 private void shutdown() { |
131 private void shutdown() { |
132 tickHandler.stop(); |
132 tickHandler.stop(); |
133 thread.quit(); |
133 thread.quit(); |
134 Flib.INSTANCE.flib_gameconn_destroy(conn); |
134 Flib.INSTANCE.flib_gameconn_destroy(conn); |
135 conn = null; |
135 conn = null; |
136 if(netplay != null) { |
136 if(netplay != null) { |
137 mainHandler.post(new Runnable() { |
137 mainHandler.post(new Runnable() { |
138 public void run() { |
138 public void run() { |
139 netplay.unregisterGameMessageListener(gameMessageListener); |
139 netplay.unregisterGameMessageListener(gameMessageListener); |
140 } |
140 } |
141 }); |
141 }); |
142 } |
142 } |
143 } |
143 } |
144 |
144 |
145 // runs on the IPCThread |
145 // runs on the IPCThread |
146 private final StrBoolCallback chatCb = new StrBoolCallback() { |
146 private final StrBoolCallback chatCb = new StrBoolCallback() { |
147 public void callback(Pointer context, String message, boolean teamChat) { |
147 public void callback(Pointer context, String message, boolean teamChat) { |
148 if(teamChat) { |
148 if(teamChat) { |
149 netplay.sendTeamChat(message); |
149 netplay.sendTeamChat(message); |
150 } else { |
150 } else { |
151 netplay.sendChat(message); |
151 netplay.sendChat(message); |
152 } |
152 } |
153 } |
153 } |
154 }; |
154 }; |
155 |
155 |
156 // runs on the IPCThread |
156 // runs on the IPCThread |
157 private final VoidCallback connectCb = new VoidCallback() { |
157 private final VoidCallback connectCb = new VoidCallback() { |
158 public void callback(Pointer context) { |
158 public void callback(Pointer context) { |
159 Log.i("GameConnection", "Connected"); |
159 Log.i("GameConnection", "Connected"); |
160 } |
160 } |
161 }; |
161 }; |
162 |
162 |
163 // runs on the IPCThread |
163 // runs on the IPCThread |
164 private final IntCallback disconnectCb = new IntCallback() { |
164 private final IntCallback disconnectCb = new IntCallback() { |
165 public void callback(Pointer context, int reason) { |
165 public void callback(Pointer context, int reason) { |
166 if(netplay != null) { |
166 if(netplay != null) { |
167 netplay.sendRoundFinished(reason==Frontlib.GAME_END_FINISHED); |
167 netplay.sendRoundFinished(reason==Frontlib.GAME_END_FINISHED); |
168 } |
168 } |
169 shutdown(); |
169 shutdown(); |
170 } |
170 } |
171 }; |
171 }; |
172 |
172 |
173 // runs on the IPCThread |
173 // runs on the IPCThread |
174 private final BytesCallback engineMessageCb = new BytesCallback() { |
174 private final BytesCallback engineMessageCb = new BytesCallback() { |
175 public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) { |
175 public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) { |
176 netplay.sendEngineMessage(buffer.deref(size.intValue())); |
176 netplay.sendEngineMessage(buffer.deref(size.intValue())); |
177 } |
177 } |
178 }; |
178 }; |
179 |
179 |
180 // runs on the IPCThread |
180 // runs on the IPCThread |
181 private final StrCallback errorMessageCb = new StrCallback() { |
181 private final StrCallback errorMessageCb = new StrCallback() { |
182 public void callback(Pointer context, String message) { |
182 public void callback(Pointer context, String message) { |
183 Log.e("GameConnection", message); |
183 Log.e("GameConnection", message); |
184 } |
184 } |
185 }; |
185 }; |
186 |
186 |
187 // runs on any thread |
187 // runs on any thread |
188 private final GameMessageListener gameMessageListener = new GameMessageListener() { |
188 private final GameMessageListener gameMessageListener = new GameMessageListener() { |
189 public void onNetDisconnected() { |
189 public void onNetDisconnected() { |
190 handler.post(new Runnable() { |
190 handler.post(new Runnable() { |
191 public void run() { |
191 public void run() { |
192 Flib.INSTANCE.flib_gameconn_send_quit(conn); |
192 Flib.INSTANCE.flib_gameconn_send_quit(conn); |
193 } |
193 } |
194 }); |
194 }); |
195 } |
195 } |
196 |
196 |
197 public void onMessage(final int type, final String message) { |
197 public void onMessage(final int type, final String message) { |
198 handler.post(new Runnable() { |
198 handler.post(new Runnable() { |
199 public void run() { |
199 public void run() { |
200 Flib.INSTANCE.flib_gameconn_send_textmsg(conn, type, message); |
200 Flib.INSTANCE.flib_gameconn_send_textmsg(conn, type, message); |
201 } |
201 } |
202 }); |
202 }); |
203 } |
203 } |
204 |
204 |
205 public void onEngineMessage(final byte[] em) { |
205 public void onEngineMessage(final byte[] em) { |
206 handler.post(new Runnable() { |
206 handler.post(new Runnable() { |
207 public void run() { |
207 public void run() { |
208 ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(em); |
208 ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(em); |
209 Flib.INSTANCE.flib_gameconn_send_enginemsg(conn, ptr, NativeSizeT.valueOf(em.length)); |
209 Flib.INSTANCE.flib_gameconn_send_enginemsg(conn, ptr, NativeSizeT.valueOf(em.length)); |
210 } |
210 } |
211 }); |
211 }); |
212 } |
212 } |
213 |
213 |
214 public void onChatMessage(final String nick, final String message) { |
214 public void onChatMessage(final String nick, final String message) { |
215 handler.post(new Runnable() { |
215 handler.post(new Runnable() { |
216 public void run() { |
216 public void run() { |
217 Flib.INSTANCE.flib_gameconn_send_chatmsg(conn, nick, message); |
217 Flib.INSTANCE.flib_gameconn_send_chatmsg(conn, nick, message); |
218 } |
218 } |
219 }); |
219 }); |
220 } |
220 } |
221 }; |
221 }; |
222 } |
222 } |