10 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports; |
13 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports; |
11 import org.hedgewars.hedgeroid.frontlib.Flib; |
14 import org.hedgewars.hedgeroid.frontlib.Flib; |
12 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr; |
15 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr; |
13 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr; |
16 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr; |
14 import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback; |
17 import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback; |
15 import org.hedgewars.hedgeroid.netplay.TickHandler; |
18 import org.hedgewars.hedgeroid.netplay.Netplay; |
|
19 import org.hedgewars.hedgeroid.util.FileUtils; |
|
20 import org.hedgewars.hedgeroid.util.TickHandler; |
16 |
21 |
17 import com.sun.jna.Pointer; |
22 import com.sun.jna.Pointer; |
18 |
23 |
19 import android.app.Activity; |
24 import android.app.Activity; |
20 import android.content.Context; |
25 import android.content.Context; |
29 import android.media.AudioTrack; |
34 import android.media.AudioTrack; |
30 import android.os.Bundle; |
35 import android.os.Bundle; |
31 import android.os.Handler; |
36 import android.os.Handler; |
32 import android.os.HandlerThread; |
37 import android.os.HandlerThread; |
33 import android.os.Message; |
38 import android.os.Message; |
|
39 import android.util.Base64; |
34 import android.util.DisplayMetrics; |
40 import android.util.DisplayMetrics; |
35 import android.util.Log; |
41 import android.util.Log; |
36 import android.view.KeyEvent; |
42 import android.view.KeyEvent; |
37 import android.view.MotionEvent; |
43 import android.view.MotionEvent; |
38 import android.view.SurfaceHolder; |
44 import android.view.SurfaceHolder; |
48 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all |
54 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all |
49 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended |
55 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended |
50 * way to do this (http://developer.android.com/guide/faq/framework.html#3) |
56 * way to do this (http://developer.android.com/guide/faq/framework.html#3) |
51 */ |
57 */ |
52 public static volatile GameConfig startConfig; |
58 public static volatile GameConfig startConfig; |
|
59 public static volatile boolean startNetgame; |
53 |
60 |
54 // Main components |
61 // Main components |
55 public static SDLActivity mSingleton; |
62 public static SDLActivity mSingleton; |
56 private static SDLSurface mSurface; |
63 private static SDLSurface mSurface; |
57 |
64 |
148 msg.arg1 = command; |
155 msg.arg1 = command; |
149 msg.obj = data; |
156 msg.obj = data; |
150 commandHandler.sendMessage(msg); |
157 commandHandler.sendMessage(msg); |
151 } |
158 } |
152 |
159 |
|
160 public static void synchronizedNativeInit(String...args) { |
|
161 synchronized(PascalExports.engineMutex) { |
|
162 nativeInit(args); |
|
163 } |
|
164 } |
|
165 |
153 // C functions we call |
166 // C functions we call |
154 public static native void nativeInit(String...args); |
167 private static native void nativeInit(String...args); |
155 public static native void nativeQuit(); |
168 public static native void nativeQuit(); |
156 public static native void nativePause(); |
169 public static native void nativePause(); |
157 public static native void nativeResume(); |
170 public static native void nativeResume(); |
158 public static native void onNativeResize(int x, int y, int format); |
171 public static native void onNativeResize(int x, int y, int format); |
159 public static native void onNativeKeyDown(int keycode); |
172 public static native void onNativeKeyDown(int keycode); |
182 |
195 |
183 public static Context getContext() { |
196 public static Context getContext() { |
184 return mSingleton; |
197 return mSingleton; |
185 } |
198 } |
186 |
199 |
187 public static void startApp(int width, int height, GameConfig config) { |
200 public static void startApp(final int width, final int height, GameConfig config, boolean netgame) { |
188 synchronized(SDLActivity.class) { |
201 synchronized(SDLActivity.class) { |
189 // Start up the C app thread |
202 // Start up the C app thread TODO this is silly code |
190 if (mSDLThread == null) { |
203 if (mSDLThread == null) { |
191 mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread"); |
204 final AtomicBoolean gameconnStartDone = new AtomicBoolean(false); |
192 mSDLThread.start(); |
205 GameConnection.Listener listener = new GameConnection.Listener() { |
|
206 public void gameConnectionReady(int port) { |
|
207 mSDLThread = new Thread(new SDLMain(width, height, port, "Medo")); |
|
208 mSDLThread.start(); |
|
209 gameconnStartDone.set(true); |
|
210 } |
|
211 |
|
212 public void gameConnectionDisconnected(int reason) { |
|
213 Log.e("startApp", "disconnected: "+reason); |
|
214 gameconnStartDone.set(true); |
|
215 } |
|
216 }; |
|
217 if(netgame) { |
|
218 Netplay netplay = Netplay.getAppInstance(mSingleton.getApplicationContext()); |
|
219 GameConnection.forNetgame(config, netplay, listener); |
|
220 } else { |
|
221 GameConnection.forLocalGame(config, listener); |
|
222 } |
193 } else { |
223 } else { |
194 SDLActivity.nativeResume(); |
224 SDLActivity.nativeResume(); |
195 } |
225 } |
196 } |
226 } |
197 } |
227 } |
424 Simple nativeInit() runnable |
454 Simple nativeInit() runnable |
425 */ |
455 */ |
426 class SDLMain implements Runnable { |
456 class SDLMain implements Runnable { |
427 |
457 |
428 private final int surfaceWidth, surfaceHeight; |
458 private final int surfaceWidth, surfaceHeight; |
429 private final GameConfig config; |
459 private final int port; |
430 private GameconnPtr conn; |
460 private final String playerName; |
431 HandlerThread thread = new HandlerThread("IPC thread"); |
461 HandlerThread thread = new HandlerThread("IPC thread"); |
432 |
462 |
433 private final IntCallback dccb = new IntCallback() { |
463 public SDLMain(int width, int height, int port, String playerName) { |
434 public void callback(Pointer context, int arg1) { |
|
435 Log.d("SDLMain", "Disconnected: "+arg1); |
|
436 Flib.INSTANCE.flib_gameconn_destroy(conn); |
|
437 conn = null; |
|
438 thread.quit(); |
|
439 } |
|
440 }; |
|
441 |
|
442 public SDLMain(int width, int height, GameConfig _config) { |
|
443 config = _config; |
|
444 surfaceWidth = width; |
464 surfaceWidth = width; |
445 surfaceHeight = height; |
465 surfaceHeight = height; |
|
466 this.port = port; |
|
467 this.playerName = playerName; |
446 } |
468 } |
447 |
469 |
448 public void run() { |
470 public void run() { |
449 //Set up the IPC socket server to communicate with the engine |
471 //Set up the IPC socket server to communicate with the engine |
450 |
472 String path = FileUtils.getDataPath(SDLActivity.mSingleton);//This represents the data directory |
451 final GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Xeli", GameSetupPtr.createJavaOwned(config), false); |
|
452 if(conn == null) { |
|
453 throw new AssertionError(); |
|
454 } |
|
455 Flib.INSTANCE.flib_gameconn_onDisconnect(conn, dccb, null); |
|
456 int port = Flib.INSTANCE.flib_gameconn_getport(conn); |
|
457 |
|
458 String path = Utils.getDataPath(SDLActivity.mSingleton);//This represents the data directory |
|
459 path = path.substring(0, path.length()-1);//remove the trailing '/' |
473 path = path.substring(0, path.length()-1);//remove the trailing '/' |
460 |
474 |
461 thread.start(); // TODO ensure it gets stopped |
|
462 new TickHandler(thread.getLooper(), 500, new Runnable() { |
|
463 public void run() { |
|
464 Log.d("SDLMain", "pre-tick"); |
|
465 Flib.INSTANCE.flib_gameconn_tick(conn); |
|
466 Log.d("SDLMain", "post-tick"); |
|
467 } |
|
468 }).start(); |
|
469 |
|
470 Log.d("SDLMain", "Starting engine"); |
475 Log.d("SDLMain", "Starting engine"); |
471 // Runs SDL_main() with added parameters |
476 // Runs SDL_main() with added parameters |
472 SDLActivity.nativeInit(new String[] { String.valueOf(port), |
477 try { |
473 String.valueOf(surfaceWidth), String.valueOf(surfaceHeight), |
478 SDLActivity.synchronizedNativeInit(new String[] { String.valueOf(port), |
474 "0", "en.txt", "xeli", "1", "1", "1", path, "" }); |
479 String.valueOf(surfaceWidth), String.valueOf(surfaceHeight), |
|
480 "0", "en.txt", Base64.encodeToString(playerName.getBytes("UTF-8"), 0), "1", "1", "1", path, "" }); |
|
481 } catch (UnsupportedEncodingException e) { |
|
482 throw new AssertionError(e); // never happens |
|
483 } |
475 Log.d("SDLMain", "Engine stopped"); |
484 Log.d("SDLMain", "Engine stopped"); |
476 try { |
|
477 thread.join(); |
|
478 } catch (InterruptedException e) { |
|
479 throw new AssertionError(); |
|
480 } |
|
481 Log.v("SDLMain", "thread joined"); |
|
482 Flib.INSTANCE.flib_gameconn_destroy(conn); |
|
483 Log.v("SDLMain", "SDL thread terminated"); |
|
484 } |
485 } |
485 } |
486 } |
486 |
487 |
487 |
488 |
488 /** |
489 /** |
493 */ |
494 */ |
494 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, |
495 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, |
495 View.OnKeyListener, View.OnTouchListener, SensorEventListener { |
496 View.OnKeyListener, View.OnTouchListener, SensorEventListener { |
496 |
497 |
497 private GameConfig config; |
498 private GameConfig config; |
498 |
499 private boolean netgame; |
|
500 |
499 // Sensors |
501 // Sensors |
500 private static SensorManager mSensorManager; |
502 private static SensorManager mSensorManager; |
501 |
503 |
502 // Startup |
504 // Startup |
503 public SDLSurface(Context context, GameConfig _config) { |
505 public SDLSurface(Context context, GameConfig _config, boolean netgame) { |
504 super(context); |
506 super(context); |
505 getHolder().addCallback(this); |
507 getHolder().addCallback(this); |
506 |
508 |
507 setFocusable(true); |
509 setFocusable(true); |
508 setFocusableInTouchMode(true); |
510 setFocusableInTouchMode(true); |