summaryrefslogtreecommitdiff
path: root/src/pw
diff options
context:
space:
mode:
Diffstat (limited to 'src/pw')
-rw-r--r--src/pw/cloudef/rpg/Base.java127
-rw-r--r--src/pw/cloudef/rpg/Button.java60
-rw-r--r--src/pw/cloudef/rpg/Easyrpg.java30
-rw-r--r--src/pw/cloudef/rpg/Launcher.java104
-rw-r--r--src/pw/cloudef/rpg/Mkxp.java18
-rw-r--r--src/pw/cloudef/rpg/Nodeweb.java58
6 files changed, 397 insertions, 0 deletions
diff --git a/src/pw/cloudef/rpg/Base.java b/src/pw/cloudef/rpg/Base.java
new file mode 100644
index 0000000..ed56bda
--- /dev/null
+++ b/src/pw/cloudef/rpg/Base.java
@@ -0,0 +1,127 @@
+package pw.cloudef.rpg;
+import org.libsdl.app.SDLActivity;
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.Integer;
+import java.lang.Boolean;
+import java.lang.String;
+import android.os.Bundle;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.view.KeyEvent;
+import android.view.InputDevice;
+import com.andretietz.android.controller.ActionView;
+import com.andretietz.android.controller.InputView;
+import android.system.Os;
+
+public class Base extends SDLActivity {
+ private boolean gamepadHidden;
+ private ActionView av;
+ private ActionView dv;
+ private Button hider;
+
+ protected int mainLayout() {
+ return R.layout.base;
+ }
+
+ protected boolean hideFully() {
+ return false;
+ }
+
+ protected String gameId() {
+ return getIntent().getExtras().getString("id");
+ }
+
+ protected String baseDir() {
+ return getApplicationContext().getFilesDir().toPath().toString() + "/data/" + gameId();
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ try { Os.setenv("COMPAT_CHDIR", baseDir(), true); } catch (Exception e) {}
+ super.onCreate(savedInstanceState);
+ final LayoutInflater li = LayoutInflater.from(getApplicationContext());
+ mLayout.addView((ViewGroup)li.inflate(mainLayout(), mLayout, false));
+
+ final Map<Integer, Boolean> state = new HashMap<Integer, Boolean>();
+ state.put(KeyEvent.KEYCODE_C, false);
+ state.put(KeyEvent.KEYCODE_CTRL_LEFT, false);
+ state.put(KeyEvent.KEYCODE_X, false);
+ state.put(KeyEvent.KEYCODE_Z, false);
+ state.put(KeyEvent.KEYCODE_DPAD_RIGHT, false);
+ state.put(KeyEvent.KEYCODE_DPAD_LEFT, false);
+ state.put(KeyEvent.KEYCODE_DPAD_DOWN, false);
+ state.put(KeyEvent.KEYCODE_DPAD_UP, false);
+
+ final Map<Integer, Integer> bcode = new HashMap<Integer, Integer>();
+ bcode.put(0, KeyEvent.KEYCODE_Z);
+ bcode.put(1, KeyEvent.KEYCODE_X);
+ bcode.put(2, KeyEvent.KEYCODE_CTRL_LEFT);
+ bcode.put(3, KeyEvent.KEYCODE_C);
+
+ av = (ActionView)findViewById(R.id.viewAction);
+ av.setOnButtonListener(new InputView.InputEventListener() {
+ @Override public void onInputEvent(View view, int buttons) {
+ for (int i = 0; i < 4; ++i) {
+ if (((0x01 << i) & buttons) > 0 && !state.get(bcode.get(i))) {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, bcode.get(i)));
+ state.put(bcode.get(i), true);
+ } else if (state.get(bcode.get(i))) {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, bcode.get(i)));
+ state.put(bcode.get(i), false);
+ }
+ }
+ }
+ });
+
+ final Map<Integer, Integer> dcode = new HashMap<Integer, Integer>();
+ dcode.put(0, KeyEvent.KEYCODE_DPAD_RIGHT);
+ dcode.put(1, KeyEvent.KEYCODE_DPAD_DOWN);
+ dcode.put(2, KeyEvent.KEYCODE_DPAD_LEFT);
+ dcode.put(3, KeyEvent.KEYCODE_DPAD_UP);
+
+ dv = (ActionView)findViewById(R.id.viewDirection);
+ dv.setOnButtonListener(new InputView.InputEventListener() {
+ @Override public void onInputEvent(View view, int buttons) {
+ for (int i = 0; i < 4; ++i) {
+ if (((0x01 << i) & buttons) > 0 && !state.get(dcode.get(i))) {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, dcode.get(i)));
+ state.put(dcode.get(i), true);
+ } else if (state.get(dcode.get(i))) {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, dcode.get(i)));
+ state.put(dcode.get(i), false);
+ }
+ }
+ }
+ });
+
+ hider = (Button)findViewById(R.id.hider);
+ hider.setOnButtonListener(new InputView.InputEventListener() {
+ @Override public void onInputEvent(View view, int buttons) {
+ if (((0x01 << 0) & buttons) > 0) {
+ gamepadHidden = !gamepadHidden;
+ if (gamepadHidden) {
+ if (hideFully()) {
+ dv.setVisibility(View.GONE);
+ av.setVisibility(View.GONE);
+ } else {
+ dv.setAlpha(0.f);
+ av.setAlpha(0.f);
+ }
+ hider.setAlpha((hideFully() ? 0.f : 0.25f));
+ } else {
+ if (hideFully()) {
+ dv.setVisibility(View.VISIBLE);
+ av.setVisibility(View.VISIBLE);
+ } else {
+ dv.setAlpha(0.5f);
+ av.setAlpha(0.5f);
+ }
+ hider.setAlpha(0.5f);
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/src/pw/cloudef/rpg/Button.java b/src/pw/cloudef/rpg/Button.java
new file mode 100644
index 0000000..5d444a4
--- /dev/null
+++ b/src/pw/cloudef/rpg/Button.java
@@ -0,0 +1,60 @@
+package pw.cloudef.rpg;
+import com.andretietz.android.controller.InputView;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.v7.content.res.AppCompatResources;
+import android.util.AttributeSet;
+
+public class Button extends InputView {
+ private static final int BUTTON_COUNT = 1;
+ private Drawable[][] drawables = new Drawable[BUTTON_COUNT][2];
+ private int[][] resources = new int[BUTTON_COUNT][2];
+
+ public Button(Context context) {
+ super(context);
+ }
+
+ public Button(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public Button(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs);
+ }
+
+ protected void init(Context context, AttributeSet attrs) {
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ActionView, 0, R.style.default_actionview);
+ super.init(context, attrs, R.style.default_actionview);
+ try {
+ resources[0][0] = a.getResourceId(R.styleable.ActionView_button1_enabled, R.drawable.action_usual);
+ resources[0][1] = a.getResourceId(R.styleable.ActionView_button1_pressed, R.drawable.action_pressed);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ @Override
+ protected Drawable getStateDrawable(int buttonIndex, ButtonState state) {
+ if (null == drawables[buttonIndex][state.ordinal()]) {
+ drawables[buttonIndex][state.ordinal()] = AppCompatResources
+ .getDrawable(getContext(), resources[buttonIndex][state.ordinal()]);
+ }
+ return drawables[buttonIndex][state.ordinal()];
+ }
+
+ @Override
+ protected int getButtonCount() {
+ return BUTTON_COUNT;
+ }
+}
diff --git a/src/pw/cloudef/rpg/Easyrpg.java b/src/pw/cloudef/rpg/Easyrpg.java
new file mode 100644
index 0000000..6c8d3de
--- /dev/null
+++ b/src/pw/cloudef/rpg/Easyrpg.java
@@ -0,0 +1,30 @@
+package pw.cloudef.rpg;
+import android.os.Bundle;
+import android.system.Os;
+
+public class Easyrpg extends Base {
+ protected String[] getLibraries() {
+ return new String[] {
+ "easyrpg"
+ };
+ }
+
+ protected String[] getArguments() {
+ return new String[] {
+ "--fullscreen",
+ "--encoding", "932"
+ };
+ }
+
+ protected String getRtpPath() {
+ return "rtp";
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ Os.setenv("COMPAT_PHYSFS_FILE", "game.zip", true);
+ Os.setenv("COMPAT_PHYSFS_FIND", "RPG_RT.exe", true);
+ } catch (Exception e) {}
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/src/pw/cloudef/rpg/Launcher.java b/src/pw/cloudef/rpg/Launcher.java
new file mode 100644
index 0000000..626ac14
--- /dev/null
+++ b/src/pw/cloudef/rpg/Launcher.java
@@ -0,0 +1,104 @@
+package pw.cloudef.rpg;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.net.Uri;
+import android.util.Log;
+import android.system.Os;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.nio.charset.Charset;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.util.Enumeration;
+
+public class Launcher extends Activity {
+ protected String gameId() {
+ return getIntent().getExtras().getString("id");
+ }
+
+ protected String zipPath() {
+ return getApplicationContext().getCacheDir().toPath().toString() + "/" + gameId() + ".zip";
+ }
+
+ protected String baseDir() {
+ return getApplicationContext().getFilesDir().toPath().toString() + "/data/" + gameId();
+ }
+
+ protected String rtpDir() {
+ return getApplicationContext().getFilesDir().toPath().toString() + "/rtp";
+ }
+
+ enum GameType {
+ UNKNOWN,
+ EASYRPG,
+ MKXP,
+ NODEWEB,
+ };
+
+ protected Class getActivityForZip(File file) {
+ ZipFile zipFile;
+ try {
+ zipFile = new ZipFile(file, java.util.zip.ZipFile.OPEN_READ, Charset.forName("Windows-31J"));
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ return null;
+ }
+
+ try {
+ Enumeration zipEntries = zipFile.entries();
+ GameType type = GameType.UNKNOWN;
+ while (zipEntries.hasMoreElements()) {
+ String fname = ((ZipEntry)zipEntries.nextElement()).getName();
+ try {
+ String base = fname.split(".+?/(?=[^/]+$)")[1];
+ String name = base.split("\\.(?=[^\\.]+$)")[0];
+ if (name.toUpperCase().equals("RPG_RT")) type = GameType.EASYRPG;
+ else if (name.toUpperCase().equals("GAME")) type = GameType.MKXP;
+ else if (base.toUpperCase().equals("RPG_CORE.JS")) type = GameType.NODEWEB;
+ } catch (Exception e2) {}
+ if (type == GameType.EASYRPG || type == GameType.NODEWEB) break;
+ }
+ switch (type) {
+ case EASYRPG: return Easyrpg.class;
+ case MKXP: return Mkxp.class;
+ case NODEWEB: return Nodeweb.class;
+ }
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ }
+
+ try { zipFile.close(); } catch (Exception e) {}
+ return null;
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ InputStream input = getContentResolver().openInputStream(getIntent().getData());
+ File file = new File(zipPath());
+ OutputStream output = new FileOutputStream(file);
+ byte[] buf = new byte[8 * 1024];
+ for (int read = 0; (read = input.read(buf)) != -1;) output.write(buf, 0, read);
+ Class activity = getActivityForZip(file);
+ if (activity == null) throw new Exception("Can't handle this game");
+ new File(baseDir()).mkdirs();
+ new File(rtpDir()).mkdirs();
+ try { Os.remove(baseDir() + "/game.zip"); } catch (Exception e2) {}
+ Os.symlink(zipPath(), baseDir() + "/game.zip");
+ try { Os.remove(baseDir() + "/rtp"); } catch (Exception e2) {}
+ Os.symlink(rtpDir(), baseDir() + "/rtp");
+ Intent intent = new Intent(this, activity);
+ intent.putExtra("id", gameId());
+ startActivity(intent);
+ finish();
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ try { Os.remove(zipPath()); } catch (Exception e2) {}
+ try { Os.remove(baseDir() + "/game.zip"); } catch (Exception e2) {}
+ }
+ finishAndRemoveTask();
+ }
+}
diff --git a/src/pw/cloudef/rpg/Mkxp.java b/src/pw/cloudef/rpg/Mkxp.java
new file mode 100644
index 0000000..f221917
--- /dev/null
+++ b/src/pw/cloudef/rpg/Mkxp.java
@@ -0,0 +1,18 @@
+package pw.cloudef.rpg;
+import android.os.Bundle;
+import android.system.Os;
+
+public class Mkxp extends Base {
+ protected String[] getLibraries() {
+ return new String[] {
+ "mkxp"
+ };
+ }
+
+ protected String[] getArguments() {
+ return new String[] {
+ "--RTP", "rtp/vxace.zip",
+ "--zip", "game.zip",
+ };
+ }
+}
diff --git a/src/pw/cloudef/rpg/Nodeweb.java b/src/pw/cloudef/rpg/Nodeweb.java
new file mode 100644
index 0000000..ba79f60
--- /dev/null
+++ b/src/pw/cloudef/rpg/Nodeweb.java
@@ -0,0 +1,58 @@
+package pw.cloudef.rpg;
+import android.os.Bundle;
+import android.webkit.WebView;
+import android.webkit.WebSettings;
+import android.webkit.WebViewClient;
+import android.view.KeyEvent;
+import android.util.Log;
+
+public class Nodeweb extends Base {
+ private WebView web;
+
+ protected String[] getLibraries() {
+ return new String[] {
+ "physfs-serve"
+ };
+ }
+
+ protected String[] getArguments() {
+ return new String[] {
+ "-p", "1337",
+ "-i", "localhost",
+ "game.zip",
+ "mv-overlay.zip",
+ };
+ }
+
+ protected int mainLayout() {
+ return R.layout.webview;
+ }
+
+ protected boolean hideFully() {
+ return true;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return web.dispatchKeyEvent(event);
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ web = (WebView)findViewById(R.id.web);
+ web.loadUrl("http://127.0.0.1:1337?webgl");
+ web.getSettings().setJavaScriptEnabled(true);
+ web.setWebContentsDebuggingEnabled(true);
+ web.getSettings().setDomStorageEnabled(true);
+ web.getSettings().setDatabaseEnabled(true);
+ web.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
+ web.setWebViewClient(new WebViewClient(){
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ Log.v("nodeweb", "error: " + errorCode);
+ view.loadUrl(failingUrl);
+ };
+ });
+ setWindowStyle(true);
+ setOrientation(0, 0, true, "");
+ }
+}