diff options
Diffstat (limited to 'src/pw/cloudef')
-rw-r--r-- | src/pw/cloudef/rpg/Base.java | 127 | ||||
-rw-r--r-- | src/pw/cloudef/rpg/Button.java | 60 | ||||
-rw-r--r-- | src/pw/cloudef/rpg/Easyrpg.java | 30 | ||||
-rw-r--r-- | src/pw/cloudef/rpg/Launcher.java | 104 | ||||
-rw-r--r-- | src/pw/cloudef/rpg/Mkxp.java | 18 | ||||
-rw-r--r-- | src/pw/cloudef/rpg/Nodeweb.java | 58 |
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, ""); + } +} |