package net.zhuoweizhang.mcpelauncher; import java.io.FileReader; import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.List; import java.util.Map; import java.util.UUID; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Environment; import android.util.Log; import org.mozilla.javascript.*; import org.mozilla.javascript.annotations.JSFunction; import org.mozilla.javascript.annotations.JSStaticFunction; import com.mojang.minecraftpe.MainActivity; import net.zhuoweizhang.mcpelauncher.api.modpe.*; import static net.zhuoweizhang.mcpelauncher.PatchManager.join; import static net.zhuoweizhang.mcpelauncher.PatchManager.blankArray; public class ScriptManager { public static final String SCRIPTS_DIR = "modscripts"; public static final int MAX_NUM_ERRORS = 5; public static List<ScriptState> scripts = new ArrayList<ScriptState>(); public static android.content.Context androidContext; public static Set<String> enabledScripts = new HashSet<String>(); public static String worldName; public static String worldDir; /** Is the currently loaded world a multiplayer world? */ public static boolean isRemote = false; private static final int AXIS_X = 0; private static final int AXIS_Y = 1; private static final int AXIS_Z = 2; private static final int ITEMID = 0; private static final int DAMAGE = 1; private static final int AMOUNT = 2; private static String currentScript = "Unknown"; private static boolean requestedGraphicsReset = false; public static boolean sensorEnabled = false; public static float newPlayerYaw = 0; public static float newPlayerPitch = 0; private static SelectLevelRequest requestSelectLevel = null; private static boolean requestLeaveGame = false; private static JoinServerRequest requestJoinServer = null; /** Is ModPE script currently enabled? Set to false by multiplayer world */ private static boolean scriptingEnabled = true; private static boolean scriptingInitialized = false; public static String screenshotFileName = ""; // public static Queue<Runnable> mainThreadRunnableQueue = new // ArrayDeque<Runnable>(); private static ModernWrapFactory modernWrapFactory = new ModernWrapFactory(); private static boolean requestReloadAllScripts = false; private static List<Runnable> runOnMainThreadList = new ArrayList<Runnable>(); /*About get all*/ public static List<Integer> allentities = new ArrayList<Integer>(); public static List<Integer> allplayers = new ArrayList<Integer>(); /**/ private static NativeArray entityList; private static String serverAddress = null; private static int serverPort = 0; private static Map<Integer, String> entityUUIDMap = new HashMap<Integer, String>(); public static void loadScript(Reader in, String sourceName) throws IOException { if (!scriptingInitialized) return; if (!scriptingEnabled) throw new RuntimeException("Not available in multiplayer"); // Rhino needs lots of recursion depth to parse nested else ifs // dalvik vm/Thread.h specifies 256K as maximum stack size // default thread depth is 16K (8K on old devices, 1K on super-low-end // devices) ParseThread parseRunner = new ParseThread(in, sourceName); Thread t = new Thread(Thread.currentThread().getThreadGroup(), parseRunner, "BlockLauncher parse thread", 256 * 1024); t.start(); try { t.join(); // block on this thread } catch (InterruptedException ie) { // shouldn't happen } if (parseRunner.error != null) { RuntimeException back; if (parseRunner.error instanceof RuntimeException) { back = (RuntimeException) parseRunner.error; } else { back = new RuntimeException(parseRunner.error); } throw back; // Thursdays } } private static class ParseThread implements Runnable { private Reader in; private String sourceName; public Exception error = null; public ParseThread(Reader in, String sourceName) { this.in = in; this.sourceName = sourceName; } public void run() { try { Context ctx = Context.enter(); setupContext(ctx); Script script = ctx.compileReader(in, sourceName, 0, null); initJustLoadedScript(ctx, script, sourceName); Context.exit(); } catch (Exception e) { e.printStackTrace(); error = e; } } } public static void loadScript(File file) throws IOException { if (isClassGenMode()) { if (!scriptingInitialized) return; if (!scriptingEnabled) throw new RuntimeException("Not available in multiplayer"); loadScriptFromInstance(ScriptTranslationCache.get(androidContext, file), file.getName()); return; } Reader in = null; try { in = new FileReader(file); loadScript(in, file.getName()); } finally { if (in != null) in.close(); } } public static void loadScriptFromInstance(Script script, String sourceName) { Context ctx = Context.enter(); setupContext(ctx); initJustLoadedScript(ctx, script, sourceName); Context.exit(); } public static void initJustLoadedScript(Context ctx, Script script, String sourceName) { Scriptable scope = ctx.initStandardObjects(new BlockHostObject(), false); ScriptState state = new ScriptState(script, scope, sourceName); String[] names = getAllJsFunctions(BlockHostObject.class); ((ScriptableObject) scope).defineFunctionProperties(names, BlockHostObject.class, ScriptableObject.DONTENUM); try { // NativeLevelApi levelApi = new NativeLevelApi(); // levelApi.defineFunctionProperties(getAllJsFunctions(NativeLevelApi.class), // NativeLevelApi.class, ScriptableObject.DONTENUM); // ScriptableObject.defineProperty(scope, "Level", levelApi, // ScriptableObject.DONTENUM); ScriptableObject.defineClass(scope, NativePlayerApi.class); ScriptableObject.defineClass(scope, NativeLevelApi.class); ScriptableObject.defineClass(scope, NativeEntityApi.class); ScriptableObject.defineClass(scope, NativeModPEApi.class); ScriptableObject.defineClass(scope, NativeItemApi.class); ScriptableObject.putProperty(scope, "ChatColor", classConstantsToJSObject(ChatColor.class)); ScriptableObject.putProperty(scope, "ItemCategory", classConstantsToJSObject(ItemCategory.class)); ScriptableObject.defineClass(scope, NativeBlockApi.class); ScriptableObject.defineClass(scope, NativeServerApi.class); RendererManager.defineClasses(scope); ScriptableObject.putProperty(scope, "ParticleType", classConstantsToJSObject(ParticleType.class)); } catch (Exception e) { e.printStackTrace(); reportScriptError(state, e); } script.exec(ctx, scope); scripts.add(state); } public static void callScriptMethod(String functionName, Object... args) { if (!scriptingEnabled) return; // No script loading/callbacks when in a remote world Context ctx = Context.enter(); setupContext(ctx); for (ScriptState state : scripts) { if (state.errors >= MAX_NUM_ERRORS) continue; // Too many errors, skip currentScript = state.name; Scriptable scope = state.scope; Object obj = scope.get(functionName, scope); if (obj != null && obj instanceof Function) { try { ((Function) obj).call(ctx, scope, scope, args); } catch (Exception e) { e.printStackTrace(); reportScriptError(state, e); } } } } public static void useItemOnCallback(int x, int y, int z, int itemid, int blockid, int side, int itemDamage, int blockDamage) { callScriptMethod("useItem", x, y, z, itemid, blockid, side, itemDamage, blockDamage); } public static void destroyBlockCallback(int x, int y, int z, int side) { callScriptMethod("destroyBlock", x, y, z, side); } public static void startDestroyBlockCallback(int x, int y, int z, int side) { callScriptMethod("startDestroyBlock", x, y, z, side); } public static void setLevelCallback(boolean hasLevel, boolean isRemote) { System.out.println("Level: " + hasLevel); ScriptManager.isRemote = isRemote; if (!isRemote) ScriptManager.scriptingEnabled = true; // all local worlds get ModPE // support nativeSetGameSpeed(20.0f); allentities.clear(); allplayers.clear(); entityUUIDMap.clear(); callScriptMethod("newLevel", hasLevel); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.setLevelCallback(!ScriptManager.scriptingEnabled); } } } public static void selectLevelCallback(String wName, String wDir) { System.out.println("World name: " + wName); System.out.println("World dir: " + wDir); worldName = wName; worldDir = wDir; callScriptMethod("selectLevelHook"); } public static void leaveGameCallback(boolean thatboolean) { ScriptManager.isRemote = false; ScriptManager.scriptingEnabled = true; callScriptMethod("leaveGame"); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.leaveGameCallback(); } } serverAddress = null; serverPort = 0; } public static void attackCallback(int attacker, int victim) { callScriptMethod("attackHook", attacker, victim); } public static void tickCallback() { callScriptMethod("modTick"); // do we have any requests for graphics reset? if (requestedGraphicsReset) { nativeOnGraphicsReset(); requestedGraphicsReset = false; } // any takers for rotating the player? if (sensorEnabled) updatePlayerOrientation(); if (requestLeaveGame) { nativeLeaveGame(false); requestLeaveGame = false; } if (requestSelectLevel != null) { nativeSelectLevel(requestSelectLevel.dir); requestSelectLevel = null; } if (requestJoinServer != null) { nativeJoinServer(requestJoinServer.serverAddress, requestJoinServer.serverPort); requestJoinServer = null; } if (runOnMainThreadList.size() > 0) { synchronized (runOnMainThreadList) { for (Runnable r : runOnMainThreadList) { r.run(); } runOnMainThreadList.clear(); } } // runDownloadCallbacks(); } private static void updatePlayerOrientation() { nativeSetRot(nativeGetPlayerEnt(), newPlayerYaw, newPlayerPitch); } public static void chatCallback(String str) { if (isRemote) nameAndShame(str); if (str == null || str.length() < 1) return; callScriptMethod("chatHook", str); if (str.charAt(0) != '/') return; callScriptMethod("procCmd", str.substring(1)); if (!isRemote) { nativePreventDefault(); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.updateTextboxText(""); } } } if (BuildConfig.DEBUG) { processDebugCommand(str.substring(1)); } } // KsyMC's additions public static void mobDieCallback(int attacker, int victim) { callScriptMethod("deathHook", attacker == -1 ? null : attacker, victim); } // Other nonstandard callbacks public static void entityRemovedCallback(int entity) { if (nativeIsPlayer(entity)) { playerRemovedHandler(entity); } int entityIndex = allentities.indexOf(entity); if (entityIndex >= 0) allentities.remove(entityIndex); callScriptMethod("entityRemovedHook", entity); // entityList.remove(Integer.valueOf(entity)); } public static void entityAddedCallback(int entity) { // check if entity is player if (nativeIsPlayer(entity)) { playerAddedHandler(entity); } allentities.add(entity); callScriptMethod("entityAddedHook", entity); // entityList.put(entityList.getLength(), entityList, entity); } public static void levelEventCallback(int player, int eventType, int x, int y, int z, int data) { callScriptMethod("levelEventHook", player, eventType, x, y, z, data); } public static void blockEventCallback(int x, int y, int z, int type, int data) { callScriptMethod("blockEventHook", x, y, z, type, data); } public static void rakNetConnectCallback(String hostname, int port) { Log.i("BlockLauncher", "Connecting to " + hostname + ":" + port); ScriptManager.scriptingEnabled = ScriptManager.isLocalAddress(hostname); Log.i("BlockLauncher", "Scripting is now " + (scriptingEnabled? "enabled" : "disabled")); serverAddress = hostname; serverPort = port; } public static void frameCallback() { if (requestReloadAllScripts) { requestReloadAllScripts = false; try { loadEnabledScripts(); } catch (Exception e) { e.printStackTrace(); reportScriptError(null, e); } return; } ScreenshotHelper.takeScreenshot(screenshotFileName); } public static void handleChatPacketCallback(String str) { if (str == null || str.length() < 1) return; callScriptMethod("serverMessageReceiveHook", str); if (BuildConfig.DEBUG) { System.out.println(str); } } public static void handleMessagePacketCallback(String sender, String str) { if (str == null || str.length() < 1) return; callScriptMethod("chatReceiveHook", str, sender); if (BuildConfig.DEBUG) { System.out.println(sender + ": " + str); } if (str.equals("BlockLauncher, enable scripts, please and thank you") && sender.length() == 0) { scriptingEnabled = true; nativePreventDefault(); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.scriptPrintCallback("Scripts have been re-enabled", ""); } } } } public static void init(android.content.Context cxt) throws IOException { scriptingInitialized = true; // set up hooks int versionCode = 0; try { versionCode = cxt.getPackageManager().getPackageInfo("com.mojang.minecraftpe", 0).versionCode; } catch (PackageManager.NameNotFoundException e) { // impossible, as if the package isn't installed, the app would've // quit before loading scripts } if (MinecraftVersion.isAmazon()) { versionCode = 0xaaaa; } nativeSetupHooks(versionCode); scripts.clear(); entityList = new NativeArray(0); androidContext = cxt.getApplicationContext(); // loadEnabledScripts(); Minecraft blocks wouldn't be initialized when // this is called // call it before the first frame renders requestReloadAllScripts = true; nativeRequestFrameCallback(); } public static void destroy() { scriptingInitialized = false; androidContext = null; scripts.clear(); runOnMainThreadList.clear(); } public static void removeScript(String scriptId) { /* * Don't clear data here - user can clear data by hand if needed * SharedPreferences sPrefs = * androidContext.getSharedPreferences("BlockLauncherModPEScript" * +scriptId+"Data", 0); SharedPreferences.Editor prefsEditor = * sPrefs.edit(); prefsEditor.clear(); prefsEditor.commit(); */ for (int i = scripts.size() - 1; i >= 0; i--) { if (scripts.get(i).name.equals(scriptId)) { scripts.remove(i); break; } } } public static void reloadScript(File file) throws IOException { removeScript(file.getName()); loadScript(file); } public static void reportScriptError(ScriptState state, Throwable t) { if (state != null) state.errors++; if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.scriptErrorCallback(state == null ? "Unknown script" : state.name, t); if (state != null && state.errors >= MAX_NUM_ERRORS) { // too // many // errors main.scriptTooManyErrorsCallback(state.name); } } } } private static void scriptPrint(String str) { System.out.println(str); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.scriptPrintCallback(str, currentScript); } } } public static void requestGraphicsReset() { requestedGraphicsReset = true; } // following taken from the patch manager public static Set<String> getEnabledScripts() { return enabledScripts; } private static void setEnabled(String name, boolean state) throws IOException { if (state) { reloadScript(getScriptFile(name)); enabledScripts.add(name); } else { enabledScripts.remove(name); removeScript(name); } saveEnabledScripts(); } public static void setEnabled(File[] files, boolean state) throws IOException { for (File file : files) { String name = file.getAbsolutePath(); if (name == null || name.length() <= 0) continue; if (state) { reloadScript(getScriptFile(name)); enabledScripts.add(name); } else { enabledScripts.remove(name); removeScript(name); } } saveEnabledScripts(); } public static void setEnabled(File file, boolean state) throws IOException { setEnabled(file.getName(), state); } private static boolean isEnabled(String name) { return enabledScripts.contains(name); } public static boolean isEnabled(File file) { return isEnabled(file.getName()); } public static void removeDeadEntries(Collection<String> allPossibleFiles) { enabledScripts.retainAll(allPossibleFiles); saveEnabledScripts(); } public static void loadEnabledScriptsNames(android.content.Context androidContext) { enabledScripts = Utils.getEnabledScripts(); } protected static void loadEnabledScripts() throws IOException { loadEnabledScriptsNames(androidContext); for (String name : enabledScripts) { // load all scripts into the script interpreter File file = getScriptFile(name); if (!file.exists() || !file.isFile()) { Log.i("BlockLauncher", "ModPE script " + file.toString() + " doesn't exist"); continue; } loadScript(file); } } protected static void saveEnabledScripts() { SharedPreferences sharedPrefs = Utils.getPrefs(1); SharedPreferences.Editor edit = sharedPrefs.edit(); edit.putString("enabledScripts", join(enabledScripts.toArray(blankArray), ";")); edit.putInt("scriptManagerVersion", 1); edit.apply(); } public static File getScriptFile(String scriptId) { File scriptsFolder = androidContext.getDir(SCRIPTS_DIR, 0); return new File(scriptsFolder, scriptId); } // end script manager controls private static String[] getAllJsFunctions(Class<? extends ScriptableObject> clazz) { List<String> allList = new ArrayList<String>(); for (Method met : clazz.getMethods()) { if (met.getAnnotation(JSFunction.class) != null) { allList.add(met.getName()); } } return allList.toArray(blankArray); } private static boolean invalidTexName(String tex) { return tex == null || tex.equals("undefined") || tex.equals("null"); } private static boolean isValidStringParameter(String tex) { return !invalidTexName(tex); } private static void wordWrapClientMessage(String msg) { String[] portions = msg.split("\n"); for (int i = 0; i < portions.length; i++) { String line = portions[i]; if (msg.indexOf(ChatColor.BEGIN) >= 0) { // TODO: properly word wrap colour codes nativeClientMessage(line); continue; } while (line.length() > 40) { String newStr = line.substring(0, 40);// colorCodeSubstring(line, // 0, 40); nativeClientMessage(newStr); line = line.substring(newStr.length()); } if (line.length() > 0) { nativeClientMessage(line); } } } /* * private static String colorCodeSubstring(String line, int begin, int end) * { int charsCounted = 0; int i; for (i = begin; i < line.length(); i++) { * char myChar = line.charAt(i); if (myChar == ChatColor.BEGIN) { i++; * //skip the next character as well } else { charsCounted++; if * (charsCounted == requiredChars) { return line.substring(begin, i + 1); } * } } } */ /** Returns a description of ALL the methods this ModPE runtime supports. */ public static String getAllApiMethodsDescriptions() { StringBuilder builder = new StringBuilder(); appendApiMethods(builder, BlockHostObject.class, null); appendApiMethods(builder, NativeModPEApi.class, "ModPE"); appendApiMethods(builder, NativeLevelApi.class, "Level"); appendApiMethods(builder, NativePlayerApi.class, "Player"); appendApiMethods(builder, NativeEntityApi.class, "Entity"); appendApiMethods(builder, NativeItemApi.class, "Item"); appendApiMethods(builder, NativeBlockApi.class, "Block"); appendApiMethods(builder, NativeServerApi.class, "Server"); return builder.toString(); } private static void appendApiMethods(StringBuilder builder, Class<?> clazz, String namespace) { for (Method met : clazz.getMethods()) { if (met.getAnnotation(JSFunction.class) != null || met.getAnnotation(JSStaticFunction.class) != null) { appendApiMethodDescription(builder, met, namespace); } } builder.append("\n"); } private static void appendApiMethodDescription(StringBuilder builder, Method met, String namespace) { if (namespace != null) { builder.append(namespace); builder.append('.'); } builder.append(met.getName()); builder.append('('); Class<?>[] params = met.getParameterTypes(); for (int i = 0; i < params.length; i++) { builder.append("par"); builder.append(i + 1); builder.append(params[i].getSimpleName().replaceAll("Native", "")); if (i < params.length - 1) { builder.append(", "); } } builder.append(");\n"); } // end method dumping code private static boolean isLocalAddress(String str) { // Use Java's built-in support for this try { InetAddress address = InetAddress.getByName(str); Log.i("BlockLauncher", str); boolean retval = address.isLoopbackAddress() || address.isLinkLocalAddress() || address.isSiteLocalAddress(); return retval; } catch (UnknownHostException e) { e.printStackTrace(); return false; } } public static void takeScreenshot(String fileName) { screenshotFileName = fileName.replace("/", "").replace("\\", ""); nativeRequestFrameCallback(); } /* * private static void runDownloadCallbacks() { Runnable message; while * ((message = mainThreadRunnableQueue.poll()) != null) { message.run(); } } */ private static void overrideTexture(String urlString, String textureName) { if (androidContext == null) return; // download from URL // saves it to ext storage's texture folder // then, schedule callback if (urlString == "") { // clear this texture override clearTextureOverride(textureName); return; } try { URL url = new URL(urlString); new Thread(new ScriptTextureDownloader(url, getTextureOverrideFile(textureName))) .start(); } catch (Exception e) { throw new RuntimeException(e); } } public static File getTextureOverrideFile(String textureName) { if (androidContext == null) return null; File stagingTextures = new File(androidContext.getExternalFilesDir(null), "textures"); return new File(stagingTextures, textureName.replace("..", "")); } public static void clearTextureOverrides() { if (androidContext == null) return; File stagingTextures = new File(androidContext.getExternalFilesDir(null), "textures"); Utils.clearDirectory(stagingTextures); requestedGraphicsReset = true; } private static void clearTextureOverride(String texture) { File file = getTextureOverrideFile(texture); if (file != null && file.exists()) { file.delete(); } requestedGraphicsReset = true; } public static ScriptableObject classConstantsToJSObject(Class<?> clazz) { ScriptableObject obj = new NativeObject(); for (Field field : clazz.getFields()) { int fieldModifiers = field.getModifiers(); if (!Modifier.isStatic(fieldModifiers) || !Modifier.isPublic(fieldModifiers)) continue; try { obj.putConst(field.getName(), obj, field.get(null)); } catch (Exception e) { e.printStackTrace(); } } return obj; } public static void setupContext(Context ctx) { ctx.setOptimizationLevel(-1); // No dynamic translation; we interpret // and/or precompile /* * if (android.preference.PreferenceManager.getDefaultSharedPreferences( * androidContext).getBoolean("zz_script_paranoid_mode", false)) { * ctx.setWrapFactory(modernWrapFactory); } */ } public static TextureRequests expandTexturesArray(Object inArrayObj) { int[] endArray = new int[16 * 6]; String[] stringArray = new String[16 * 6]; TextureRequests retval = new TextureRequests(); retval.coords = endArray; retval.names = stringArray; if (inArrayObj instanceof String) { String fillVal = ((String) inArrayObj); Arrays.fill(stringArray, fillVal); return retval; } Scriptable inArrayScriptable = (Scriptable) inArrayObj; // if the in array count is a multiple of 6, // copy 6 at a time until we run out, then copy 6 from the first // element. int inArrayLength = ((Number) ScriptableObject.getProperty(inArrayScriptable, "length")) .intValue(); int wrap = inArrayLength % 6 == 0 ? 6 : 1; Object firstObj = ScriptableObject.getProperty(inArrayScriptable, 0); if ((inArrayLength == 1 || inArrayLength == 2) && firstObj instanceof String) { // all blocks have same tex String fillVal = ((String) firstObj); Arrays.fill(stringArray, fillVal); if (inArrayLength == 2) { int fillVal2 = ((Number) ScriptableObject.getProperty(inArrayScriptable, 1)) .intValue(); Arrays.fill(endArray, fillVal2); } return retval; } for (int i = 0; i < endArray.length; i++) { Object myObj; if (i < inArrayLength) { myObj = ScriptableObject.getProperty(inArrayScriptable, i); } else { myObj = ScriptableObject.getProperty(inArrayScriptable, i % wrap); } Scriptable myScriptable = (Scriptable) myObj; String texName = ((String) ScriptableObject.getProperty(myScriptable, 0)); int texCoord = ((Number) ScriptableObject.getProperty(myScriptable, 1)).intValue(); endArray[i] = texCoord; stringArray[i] = texName; } return retval; } /* * public static int expandTextureCoordinate(Object myObj) { if (myObj * instanceof Number) { return ((Number) myObj).intValue(); } else if (myObj * instanceof Scriptable) { Scriptable myScriptable = (Scriptable) myObj; * int texRow = ((Number) ScriptableObject.getProperty(myScriptable, * 0)).intValue(); int texCol = ((Number) * ScriptableObject.getProperty(myScriptable, 1)).intValue(); return (texRow * * 16) + texCol; } throw new * IllegalArgumentException("Invalid texture coordinate input: " + myObj); } */ public static int[] expandColorsArray(Scriptable inArrayScriptable) { int inArrayLength = ((Number) ScriptableObject.getProperty(inArrayScriptable, "length")) .intValue(); int[] endArray = new int[16]; for (int i = 0; i < endArray.length; i++) { if (i < inArrayLength) { endArray[i] = (int) ((Number) ScriptableObject.getProperty(inArrayScriptable, i)) .longValue(); } else { endArray[i] = (int) ((Number) ScriptableObject.getProperty(inArrayScriptable, 0)) .longValue(); } } Log.i("BlockLauncher", Arrays.toString(endArray)); return endArray; } public static void processDebugCommand(String cmd) { try { if (cmd.equals("dumpitems")) { debugDumpItems(); } } catch (Exception e) { e.printStackTrace(); } } private static void debugDumpItems() throws IOException { PrintWriter out = new PrintWriter(new File(Environment.getExternalStorageDirectory(), "/items.csv")); float[] textureUVbuf = new float[6]; for (int i = 0; i < 512; i++) { String itemName = nativeGetItemName(i, 0, true); if (itemName == null) continue; boolean success = nativeGetTextureCoordinatesForItem(i, 0, textureUVbuf); String itemIcon = Arrays.toString(textureUVbuf).replace("[", "").replace("]", "") .replace(",", "|"); out.println(i + "," + itemName + "," + itemIcon); } out.close(); } private static void playerAddedHandler(int entityId) { allplayers.add(entityId); if (!shouldLoadSkin()) return; // load skin for player String playerName = nativeGetPlayerName(entityId); // in the real // service, this // would be // normalized String skinName = "mob/" + playerName + ".png"; File skinFile = getTextureOverrideFile("images/" + skinName); if (skinFile == null) return; String urlString = "http://s3.amazonaws.com/MinecraftSkins/" + playerName + ".png"; try { URL url = new URL(urlString); new Thread(new ScriptTextureDownloader(url, skinFile, new AfterSkinDownloadAction( entityId, skinName))).start(); } catch (Exception e) { e.printStackTrace(); } } private static void playerRemovedHandler(int entityId) { int entityIndex = allplayers.indexOf(entityId); if (entityIndex >= 0) allplayers.remove(entityIndex); } public static void runOnMainThread(Runnable run) { synchronized (runOnMainThreadList) { runOnMainThreadList.add(run); } } private static boolean shouldLoadSkin() { return Utils.getPrefs(0).getString("zz_skin_download_source", "mojang_pc") .equals("mojang_pc"); } private static boolean isClassGenMode() { return false; } private static int[] expandShapelessRecipe(Scriptable inArrayScriptable) { int inArrayLength = ((Number) ScriptableObject.getProperty(inArrayScriptable, "length")) .intValue(); Object firstObj = ScriptableObject.getProperty(inArrayScriptable, 0); int[] endArray = null; if (firstObj instanceof Number) { if (inArrayLength % 3 != 0) { throw new IllegalArgumentException( "Array length must be multiple of 3 (this was changed in 1.6.8): [itemid, itemCount, itemdamage, ...]"); } else { endArray = new int[inArrayLength]; for (int i = 0; i < endArray.length; i++) { endArray[i] = ((Number) ScriptableObject.getProperty(inArrayScriptable, i)) .intValue(); } } } else { throw new IllegalArgumentException( "Method takes in an array of [itemid, itemCount, itemdamage, ...]"); // TODO: more types } return endArray; } private static void nameAndShame(String str) { if (str == null || str.length() < 1 || str.charAt(0) == '/') return; String playerName = NativePlayerApi.getName(nativeGetPlayerEnt()); if (playerName == null) return; boolean hasShamed = true; if (playerName.equalsIgnoreCase("geoffrey5787")) { nativeSendChat("I steal mods and claim them as my own"); } else if (playerName.equalsIgnoreCase("doggerhero20011") || playerName.equalsIgnoreCase("dogger20011")) { nativeSendChat("I stole from app developers, so you should steal from me!"); } else { hasShamed = false; } if (hasShamed) { nativePreventDefault(); if (MainActivity.currentMainActivity != null) { MainActivity main = MainActivity.currentMainActivity.get(); if (main != null) { main.updateTextboxText(""); } } } } private static String getEntityUUID(int entityId) { String uuid = entityUUIDMap.get(entityId); if (uuid != null) return uuid; long[] uuidParts = nativeEntityGetUUID(entityId); if (uuidParts == null) return null; long lsb = Long.reverseBytes(uuidParts[0]); long msb = Long.reverseBytes(uuidParts[1]); UUID uuidObj = new UUID(lsb, msb); System.out.println(uuidObj); if (uuidObj.version() != 4) throw new RuntimeException("Invalid entity UUID"); uuid = uuidObj.toString(); entityUUIDMap.put(entityId, uuid); return uuid; } public static native float nativeGetPlayerLoc(int axis); public static native int nativeGetPlayerEnt(); public static native long nativeGetLevel(); public static native void nativeSetPosition(int entity, float x, float y, float z); public static native void nativeSetVel(int ent, float vel, int axis); public static native void nativeExplode(float x, float y, float z, float radius); public static native void nativeAddItemInventory(int id, int amount, int damage); public static native void nativeRideAnimal(int rider, int mount); public static native int nativeGetCarriedItem(int type); public static native void nativePreventDefault(); public static native void nativeSetTile(int x, int y, int z, int id, int damage); public static native int nativeSpawnEntity(float x, float y, float z, int entityType, String skinPath); public static native void nativeClientMessage(String msg); public static native void nativeSetNightMode(boolean isNight); public static native int nativeGetTile(int x, int y, int z); public static native void nativeSetPositionRelative(int entity, float x, float y, float z); public static native void nativeSetRot(int ent, float yaw, float pitch); public static native float nativeGetYaw(int ent); public static native float nativeGetPitch(int ent); public static native void nativeSetCarriedItem(int ent, int id, int count, int damage); public static native void nativeOnGraphicsReset(); public static native void nativeDefineItem(int itemId, String iconName, int iconId, String name, int maxStackSize); public static native void nativeDefineFoodItem(int itemId, String iconName, int iconId, int hearts, String name, int maxStackSize); // nonstandard public static native void nativeSetFov(float degrees); public static native void nativeSetMobSkin(int ent, String str); public static native float nativeGetEntityLoc(int entity, int axis); public static native void nativeRemoveEntity(int entityId); public static native int nativeGetEntityTypeId(int entityId); public static native void nativeSetAnimalAge(int entityId, int age); public static native int nativeGetAnimalAge(int entityId); public static native void nativeSelectLevel(String levelName); public static native void nativeLeaveGame(boolean saveMultiplayerWorld); public static native void nativeJoinServer(String serverAddress, int serverPort); public static native void nativeSetGameSpeed(float ticksPerSecond); public static native void nativeGetAllEntities(); public static native int nativeGetSelectedSlotId(); public static native int nativeGetMobHealth(int entityId); public static native void nativeSetMobHealth(int entityId, int halfhearts); public static native void nativeSetEntityRenderType(int entityId, int renderType); public static native void nativeRequestFrameCallback(); public static native String nativeGetSignText(int x, int y, int z, int line); public static native void nativeSetSignText(int x, int y, int z, int line, String text); public static native void nativeSetSneaking(int entityId, boolean doIt); public static native String nativeGetPlayerName(int entityId); public static native String nativeGetItemName(int itemId, int itemDamage, boolean raw); public static native boolean nativeGetTextureCoordinatesForItem(int itemId, int itemDamage, float[] output); public static native void nativeDefineBlock(int blockId, String name, String[] textureNames, int[] textureCoords, int materialSourceId, boolean opaque, int renderType); public static native void nativeBlockSetDestroyTime(int blockId, float amount); public static native void nativeBlockSetExplosionResistance(int blockId, float amount); public static native void nativeBlockSetStepSound(int blockId, int sourceBlockId); public static native void nativeBlockSetLightLevel(int blockId, int level); public static native void nativeBlockSetColor(int blockId, int[] colors); public static native void nativeBlockSetShape(int blockId, float v1, float v2, float v3, float v4, float v5, float v6); public static native void nativeBlockSetRenderLayer(int blockId, int renderLayer); public static native void nativeSetInventorySlot(int slot, int id, int count, int damage); public static native boolean nativeIsPlayer(int entityId); public static native float nativeGetEntityVel(int entity, int axis); public static native void nativeSetI18NString(String key, String value); public static native void nativeAddShapelessRecipe(int id, int count, int damage, int[] ingredients); public static native void nativeShowTipMessage(String msg); public static native void nativeEntitySetNameTag(int id, String msg); public static native void nativeSetStonecutterItem(int id, int status); public static native void nativeSetItemCategory(int id, int category, int status); public static native void nativeSendChat(String message); public static native String nativeEntityGetNameTag(int entityId); public static native int nativeEntityGetRiding(int entityId); public static native int nativeEntityGetRider(int entityId); public static native String nativeEntityGetMobSkin(int entityId); public static native int nativeEntityGetRenderType(int entityId); public static native void nativeSetCameraEntity(int entityId); public static native long[] nativeEntityGetUUID(int entityId); public static native void nativeLevelAddParticle(int type, float x, float y, float z, float xVel, float yVel, float zVel, int data); // MrARM's additions public static native int nativeGetData(int x, int y, int z); public static native void nativeHurtTo(int to); public static native void nativeDestroyBlock(int x, int y, int z); public static native long nativeGetTime(); public static native void nativeSetTime(long time); public static native int nativeGetGameType(); public static native void nativeSetGameType(int type); public static native void nativeSetOnFire(int entity, int howLong); public static native void nativeSetSpawn(int x, int y, int z); public static native void nativeAddItemChest(int x, int y, int z, int slot, int id, int damage, int amount); public static native int nativeGetItemChest(int x, int y, int z, int slot); public static native int nativeGetItemDataChest(int x, int y, int z, int slot); public static native int nativeGetItemCountChest(int x, int y, int z, int slot); public static native int nativeDropItem(float x, float y, float z, float range, int id, int count, int damage); // KsyMC's additions public static native void nativePlaySound(float x, float y, float z, String sound, float volume, float pitch); public static native void nativeClearSlotInventory(int slot); public static native int nativeGetSlotInventory(int slot, int type); public static native void nativeAddItemCreativeInv(int id, int count, int damage); // InusualZ's additions public static native void nativeExtinguishFire(int x, int y, int z, int side); public static native int nativeGetSlotArmor(int slot, int type); public static native void nativeSetArmorSlot(int slot, int id, int damage); // Byteandahalf's additions public static native int nativeGetBrightness(int x, int y, int z); public static native void nativeAddFurnaceRecipe(int inputId, int outputId, int outputDamage); public static native void nativeAddItemFurnace(int x, int y, int z, int slot, int id, int damage, int amount); public static native int nativeGetItemFurnace(int x, int y, int z, int slot); public static native int nativeGetItemDataFurnace(int x, int y, int z, int slot); public static native int nativeGetItemCountFurnace(int x, int y, int z, int slot); public static native void nativeSetItemMaxDamage(int id, int maxDamage); public static native int nativeGetBlockRenderShape(int blockId); public static native void nativeSetBlockRenderShape(int blockId, int renderType); // setup public static native void nativeSetupHooks(int versionCode); public static native void nativeRemoveItemBackground(); public static native void nativeSetTextParseColorCodes(boolean doIt); public static native void nativePrePatch(); public static class ScriptState { public Script script; public Scriptable scope; public String name; public int errors = 0; protected ScriptState(Script script, Scriptable scope, String name) { this.script = script; this.scope = scope; this.name = name; } } // To contributors: if you are adding a BlockLauncher-specific method, // please add it to one of the namespaces (Entity, Level, ModPE, Player) // instead of the top-level namespace. thanks. // e.g. Entity.fireLaz0rs = good, fireLaz0rs = bad, bl_fireLaz0rs = bad private static class BlockHostObject extends ImporterTopLevel { private int playerEnt = 0; @Override public String getClassName() { return "BlockHostObject"; } @JSFunction public void print(String str) { scriptPrint(str); } @JSFunction public double getPlayerX() { return nativeGetPlayerLoc(AXIS_X); } @JSFunction public double getPlayerY() { return nativeGetPlayerLoc(AXIS_Y); } @JSFunction public double getPlayerZ() { return nativeGetPlayerLoc(AXIS_Z); } @JSFunction public int getPlayerEnt() { playerEnt = nativeGetPlayerEnt(); return playerEnt; } @JSFunction public NativePointer getLevel() { return new NativePointer(nativeGetLevel()); // TODO: WTF does this do? } @JSFunction public void setPosition(int ent, double x, double y, double z) { nativeSetPosition(ent, (float) x, (float) y, (float) z); } @JSFunction public void setVelX(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_X); } @JSFunction public void setVelY(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_Y); } @JSFunction public void setVelZ(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_Z); } @JSFunction public void explode(double x, double y, double z, double radius) { nativeExplode((float) x, (float) y, (float) z, (float) radius); } @JSFunction public void addItemInventory(int id, int amount, int damage) { nativeAddItemInventory(id, amount, damage); } @JSFunction public void rideAnimal(int /* Flynn */rider, int mount) { nativeRideAnimal(rider, mount); } @JSFunction public int spawnChicken(double x, double y, double z, String tex) { if (invalidTexName(tex)) { tex = "mob/chicken.png"; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, 10, tex); return entityId; } @JSFunction public int spawnCow(double x, double y, double z, String tex) { if (invalidTexName(tex)) { tex = "mob/cow.png"; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, 11, tex); return entityId; } @JSFunction public int getCarriedItem() { return nativeGetCarriedItem(ITEMID); } @JSFunction public void preventDefault() { nativePreventDefault(); } @JSFunction public void setTile(int x, int y, int z, int id, int damage) { nativeSetTile(x, y, z, id, damage); } @JSFunction public void clientMessage(String text) { wordWrapClientMessage(text); } @JSFunction public void setNightMode(boolean isNight) { nativeSetNightMode(isNight); } @JSFunction public int getTile(int x, int y, int z) { return nativeGetTile(x, y, z); } @JSFunction public void setPositionRelative(int ent, double x, double y, double z) { nativeSetPositionRelative(ent, (float) x, (float) y, (float) z); } @JSFunction public void setRot(int ent, double yaw, double pitch) { nativeSetRot(ent, (float) yaw, (float) pitch); } @JSFunction public double getPitch(Object entObj) { int ent; if (entObj == null || !(entObj instanceof Number)) { ent = getPlayerEnt(); } else { ent = ((Number) entObj).intValue(); } return nativeGetPitch(ent); } @JSFunction public double getYaw(Object entObj) { int ent; if (entObj == null || !(entObj instanceof Number)) { ent = getPlayerEnt(); } else { ent = ((Number) entObj).intValue(); } return nativeGetYaw(ent); } @JSFunction public int spawnPigZombie(double x, double y, double z, int item, String tex) { if (invalidTexName(tex)) { tex = "mob/pigzombie.png"; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, 36, tex); nativeSetCarriedItem(entityId, item, 1, 0); return entityId; } // nonstandard methods @JSFunction public int bl_spawnMob(double x, double y, double z, int typeId, String tex) { print("Deprecated: use Level.spawnMob, to be removed in 1.7"); if (invalidTexName(tex)) { tex = null; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, typeId, tex); return entityId; } @JSFunction public void bl_setMobSkin(int entity, String tex) { print("Deprecated: use Entity.setMobSkin, to be removed in 1.7"); nativeSetMobSkin(entity, tex); } } private static class NativePointer extends ScriptableObject { public long value; public NativePointer(long value) { this.value = value; } @Override public String getClassName() { return "NativePointer"; } } private static class NativeLevelApi extends ScriptableObject { public NativeLevelApi() { super(); } @JSStaticFunction public static void setNightMode(boolean isNight) { nativeSetNightMode(isNight); } @JSStaticFunction public static int getTile(int x, int y, int z) { return nativeGetTile(x, y, z); } @JSStaticFunction public static void explode(double x, double y, double z, double radius) { nativeExplode((float) x, (float) y, (float) z, (float) radius); } @JSStaticFunction public static void setTile(int x, int y, int z, int id, int damage) { nativeSetTile(x, y, z, id, damage); } @JSStaticFunction public static NativePointer getAddress() { // TODO: I still don't know WTF this does. scriptPrint("Deprecated: unknown aim"); return new NativePointer(nativeGetLevel()); } @JSStaticFunction public static int spawnChicken(double x, double y, double z, String tex) { if (invalidTexName(tex)) { tex = "mob/chicken.png"; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, 10, tex); return entityId; } @JSStaticFunction public static int spawnCow(double x, double y, double z, String tex) { if (invalidTexName(tex)) { tex = "mob/cow.png"; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, 11, tex); return entityId; } // nonstandard methods @JSStaticFunction public static int spawnMob(double x, double y, double z, int typeId, String tex) { if (invalidTexName(tex)) { tex = null; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, typeId, tex); return entityId; } @JSStaticFunction public static String getSignText(int x, int y, int z, int line) { if (line < 0 || line >= 4) throw new RuntimeException("Invalid line for sign: must be in the range of 0 to 3"); return nativeGetSignText(x, y, z, line); } @JSStaticFunction public static void setSignText(int x, int y, int z, int line, String newText) { if (line < 0 || line >= 4) throw new RuntimeException("Invalid line for sign: must be in the range of 0 to 3"); nativeSetSignText(x, y, z, line, newText); } // thanks to MrARM @JSStaticFunction public static int getData(int x, int y, int z) { return nativeGetData(x, y, z); } @JSStaticFunction public static String getWorldName() { return worldName; } @JSStaticFunction public static String getWorldDir() { return worldDir; } @JSStaticFunction public static int dropItem(double x, double y, double z, double range, int id, int count, int damage) { return nativeDropItem((float) x, (float) y, (float) z, (float) range, id, count, damage); } @JSStaticFunction public static void setGameMode(int type) { nativeSetGameType(type); } @JSStaticFunction public static int getGameMode() { return nativeGetGameType(); } @JSStaticFunction public static int getTime() { return (int) nativeGetTime(); } @JSStaticFunction public static void setTime(int time) { nativeSetTime((long) time); } @JSStaticFunction public static void setSpawn(int x, int y, int z) { nativeSetSpawn(x, y, z); } @JSStaticFunction public static void destroyBlock(int x, int y, int z, boolean shouldDrop) { int itmId = getTile(x, y, z); int itmDmg = getData(x, y, z); nativeDestroyBlock(x, y, z); if (shouldDrop) dropItem(((double) x) + 0.5, y, ((double) z) + 0.5, 1, itmId, 1, itmDmg); } @JSStaticFunction public static void setChestSlot(int x, int y, int z, int slot, int id, int damage, int amount) { nativeAddItemChest(x, y, z, slot, id, damage, amount); } @JSStaticFunction public static int getChestSlot(int x, int y, int z, int slot) { return nativeGetItemChest(x, y, z, slot); } @JSStaticFunction public static int getChestSlotData(int x, int y, int z, int slot) { return nativeGetItemDataChest(x, y, z, slot); } @JSStaticFunction public static int getChestSlotCount(int x, int y, int z, int slot) { return nativeGetItemCountChest(x, y, z, slot); } // KsyMC's additions @JSStaticFunction public static void playSound(double x, double y, double z, String sound, double volume, double pitch) { nativePlaySound((float) x, (float) y, (float) z, sound, (float) volume, (float) pitch); } @JSStaticFunction public static void playSoundEnt(int ent, String sound, double volume, double pitch) { float x = nativeGetEntityLoc(ent, AXIS_X); float y = nativeGetEntityLoc(ent, AXIS_Y); float z = nativeGetEntityLoc(ent, AXIS_Z); nativePlaySound(x, y, z, sound, (float) volume, (float) pitch); } // Byteandahalf's additions @JSStaticFunction public static int getBrightness(int x, int y, int z) { return nativeGetBrightness(x, y, z); } @JSStaticFunction public static void setFurnaceSlot(int x, int y, int z, int slot, int id, int damage, int amount) { nativeAddItemFurnace(x, y, z, slot, id, damage, amount); } @JSStaticFunction public static int getFurnaceSlot(int x, int y, int z, int slot) { return nativeGetItemFurnace(x, y, z, slot); } @JSStaticFunction public static int getFurnaceSlotData(int x, int y, int z, int slot) { return nativeGetItemDataFurnace(x, y, z, slot); } @JSStaticFunction public static int getFurnaceSlotCount(int x, int y, int z, int slot) { return nativeGetItemCountFurnace(x, y, z, slot); } @JSStaticFunction public static void addParticle(int type, double x, double y, double z, double xVel, double yVel, double zVel, int size) { if (type < 0 || type > 15) throw new RuntimeException("Invalid particle type " + type + ": should be between 0 and 15"); nativeLevelAddParticle(type, (float) x, (float) y, (float) z, (float) xVel, (float) yVel, (float) zVel, size); } @Override public String getClassName() { return "Level"; } } private static class NativePlayerApi extends ScriptableObject { private static int playerEnt = 0; public NativePlayerApi() { super(); } @JSStaticFunction public static double getX() { return nativeGetPlayerLoc(AXIS_X); } @JSStaticFunction public static double getY() { return nativeGetPlayerLoc(AXIS_Y); } @JSStaticFunction public static double getZ() { return nativeGetPlayerLoc(AXIS_Z); } @JSStaticFunction public static int getEntity() { playerEnt = nativeGetPlayerEnt(); return playerEnt; } @JSStaticFunction public static int getCarriedItem() { return nativeGetCarriedItem(ITEMID); } @JSStaticFunction public static void addItemInventory(int id, int amount, int damage) { nativeAddItemInventory(id, amount, damage); } // nonstandard @JSStaticFunction public static void setHealth(int value) { nativeHurtTo(value); } @JSStaticFunction public static int getSelectedSlotId() { return nativeGetSelectedSlotId(); } // KsyMC's additions @JSStaticFunction public static void clearInventorySlot(int slot) { nativeClearSlotInventory(slot); } @JSStaticFunction public static int getInventorySlot(int slot) { return nativeGetSlotInventory(slot, ITEMID); } @JSStaticFunction public static int getInventorySlotData(int slot) { return nativeGetSlotInventory(slot, DAMAGE); } @JSStaticFunction public static int getInventorySlotCount(int slot) { return nativeGetSlotInventory(slot, AMOUNT); } @JSStaticFunction public static int getCarriedItemData() { return nativeGetCarriedItem(DAMAGE); } @JSStaticFunction public static int getCarriedItemCount() { return nativeGetCarriedItem(AMOUNT); } @JSStaticFunction public static void addItemCreativeInv(int id, int count, int damage) { nativeAddItemCreativeInv(id, count, damage); } // InusualZ's additions @JSStaticFunction public static int getArmorSlot(int slot) { return nativeGetSlotArmor(slot, ITEMID); } @JSStaticFunction public static int getArmorSlotDamage(int slot) { return nativeGetSlotArmor(slot, DAMAGE); } @JSStaticFunction public static void setArmorSlot(int slot, int id, int damage) { nativeSetArmorSlot(slot, id, damage); } @JSStaticFunction public static String getName(int ent) { if (!nativeIsPlayer(ent)) return "Not a player"; return nativeGetPlayerName(ent); } @JSStaticFunction public static boolean isPlayer(int ent) { return nativeIsPlayer(ent); } /* * @JSStaticFunction public static void setInventorySlot(int slot, int * itemId, int count, int damage) { nativeSetInventorySlot(slot, itemId, * count, damage); } */ @Override public String getClassName() { return "Player"; } } private static class NativeEntityApi extends ScriptableObject { public NativeEntityApi() { super(); } @JSStaticFunction public static void setVelX(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_X); } @JSStaticFunction public static void setVelY(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_Y); } @JSStaticFunction public static void setVelZ(int ent, double amount) { nativeSetVel(ent, (float) amount, AXIS_Z); } @JSStaticFunction public static void setRot(int ent, double yaw, double pitch) { nativeSetRot(ent, (float) yaw, (float) pitch); } @JSStaticFunction public static void rideAnimal(int /* insert funny reference */rider, int mount) { nativeRideAnimal(rider, mount); } @JSStaticFunction public static void setPosition(int ent, double x, double y, double z) { nativeSetPosition(ent, (float) x, (float) y, (float) z); } @JSStaticFunction public static void setPositionRelative(int ent, double x, double y, double z) { nativeSetPositionRelative(ent, (float) x, (float) y, (float) z); } @JSStaticFunction public static double getPitch(int ent) { return nativeGetPitch(ent); } @JSStaticFunction public static double getYaw(int ent) { return nativeGetYaw(ent); } // nonstandard @JSStaticFunction public static void setFireTicks(int ent, int howLong) { nativeSetOnFire(ent, howLong); } @JSStaticFunction public static double getX(int ent) { return nativeGetEntityLoc(ent, AXIS_X); } @JSStaticFunction public static double getY(int ent) { return nativeGetEntityLoc(ent, AXIS_Y); } @JSStaticFunction public static double getZ(int ent) { return nativeGetEntityLoc(ent, AXIS_Z); } @JSStaticFunction public static void setCarriedItem(int ent, int id, int count, int damage) { nativeSetCarriedItem(ent, id, count, damage); } @JSStaticFunction public static int getEntityTypeId(int ent) { return nativeGetEntityTypeId(ent); } @JSStaticFunction public static int spawnMob(double x, double y, double z, int typeId, String tex) { scriptPrint("Deprecated: use Level.spawnMob, to be removed in 1.7"); if (invalidTexName(tex)) { tex = null; } int entityId = nativeSpawnEntity((float) x, (float) y, (float) z, typeId, tex); return entityId; } @JSStaticFunction public static void setAnimalAge(int animal, int age) { nativeSetAnimalAge(animal, age); } @JSStaticFunction public static int getAnimalAge(int animal) { return nativeGetAnimalAge(animal); } @JSStaticFunction public static void setMobSkin(int entity, String tex) { nativeSetMobSkin(entity, tex); } @JSStaticFunction public static void remove(int ent) { nativeRemoveEntity(ent); } @JSStaticFunction public static int getHealth(int ent) { return nativeGetMobHealth(ent); } @JSStaticFunction public static void setHealth(int ent, int halfhearts) { nativeSetMobHealth(ent, halfhearts); } @JSStaticFunction public static void setRenderType(int ent, int renderType) { nativeSetEntityRenderType(ent, renderType); } @JSStaticFunction public static void setSneaking(int ent, boolean doIt) { nativeSetSneaking(ent, doIt); } @JSStaticFunction public static double getVelX(int ent) { return nativeGetEntityVel(ent, AXIS_X); } @JSStaticFunction public static double getVelY(int ent) { return nativeGetEntityVel(ent, AXIS_Y); } @JSStaticFunction public static double getVelZ(int ent) { return nativeGetEntityVel(ent, AXIS_Z); } @JSStaticFunction public static void setNameTag(int entity, String name) { int entityType = nativeGetEntityTypeId(entity); if (entityType >= 64 || (entityType == 0 && !NativePlayerApi.isPlayer(entity))) throw new IllegalArgumentException("setNameTag only works on mobs"); nativeEntitySetNameTag(entity, name); } // KMCPE's additions @JSStaticFunction public static int[] getAll() { int[] entities = new int[allentities.size()]; for(int n=0;entities.length>n;n++){ entities[n]=allentities.get(n); } return entities; } @JSStaticFunction public static String getNameTag(int entity) { return nativeEntityGetNameTag(entity); } @JSStaticFunction public static int getRiding(int entity) { return nativeEntityGetRiding(entity); } @JSStaticFunction public static int getRider(int entity) { return nativeEntityGetRider(entity); } @JSStaticFunction public static String getMobSkin(int entity) { return nativeEntityGetMobSkin(entity); } @JSStaticFunction public static int getRenderType(int entity) { return nativeEntityGetRenderType(entity); } @JSStaticFunction public static String getUniqueId(int entity) { return getEntityUUID(entity); } @Override public String getClassName() { return "Entity"; } } private static class NativeModPEApi extends ScriptableObject { public NativeModPEApi() { super(); } @JSStaticFunction public static void log(String str) { Log.i("MCPELauncherLog", str); } @JSStaticFunction public static void setTerrain(String url) { overrideTexture("images/terrain-atlas.tga", url); } @JSStaticFunction public static void setItems(String url) { overrideTexture("images/items-opaque.png", url); } @JSStaticFunction public static void setGuiBlocks(String url) { overrideTexture("gui/gui_blocks.png", url); } @JSStaticFunction public static void overrideTexture(String theOverridden, String url) { ScriptManager.overrideTexture(url, theOverridden); } @JSStaticFunction public static void resetImages() { ScriptManager.clearTextureOverrides(); } @JSStaticFunction public static void setItem(int id, String iconName, int iconSubindex, String name, int maxStackSize) { try { Integer.parseInt(iconName); Log.i("MCPELauncher", "The item icon for " + name.trim() + " is not updated for 0.8.0. Please ask the script author to update"); } catch (NumberFormatException e) { } if (id < 0 || id >= 512) { throw new IllegalArgumentException("Item IDs must be >= 0 and < 512"); } nativeDefineItem(id, iconName, iconSubindex, name, maxStackSize); } @JSStaticFunction public static void setFoodItem(int id, String iconName, int iconSubindex, int halfhearts, String name, int maxStackSize) { try { Integer.parseInt(iconName); Log.i("MCPELauncher", "The item icon for " + name.trim() + " is not updated for 0.8.0. Please ask the script author to update"); } catch (NumberFormatException e) { } if (id < 0 || id >= 512) { throw new IllegalArgumentException("Item IDs must be >= 0 and < 512"); } nativeDefineFoodItem(id, iconName, iconSubindex, halfhearts, name, maxStackSize); } // nonstandard @JSStaticFunction public static void selectLevel(String levelDir, String levelName, String levelSeed, int gamemode) { if (levelDir.equals(ScriptManager.worldDir)) { System.err.println("Attempted to load level that is already loaded - ignore"); return; } requestLeaveGame = true; // nativeSelectLevel(levelDir); requestSelectLevel = new SelectLevelRequest(); requestSelectLevel.dir = levelDir; if (isValidStringParameter(levelName)) { requestSelectLevel.name = levelName; requestSelectLevel.seed = levelSeed; requestSelectLevel.gameMode = gamemode; } } @JSStaticFunction public static String readData(String prefName) { SharedPreferences sPrefs = androidContext.getSharedPreferences( "BlockLauncherModPEScript" + currentScript, 0); return sPrefs.getString(prefName, ""); } @JSStaticFunction public static void saveData(String prefName, String prefValue) { SharedPreferences sPrefs = androidContext.getSharedPreferences( "BlockLauncherModPEScript" + currentScript, 0); SharedPreferences.Editor prefsEditor = sPrefs.edit(); prefsEditor.putString(prefName, prefValue); prefsEditor.commit(); } @JSStaticFunction public static void removeData(String prefName) { SharedPreferences sPrefs = androidContext.getSharedPreferences( "BlockLauncherModPEScript" + currentScript, 0); SharedPreferences.Editor prefsEditor = sPrefs.edit(); prefsEditor.remove(prefName); prefsEditor.commit(); } @JSStaticFunction public static void leaveGame() { requestLeaveGame = true; } @JSStaticFunction public static void setGameSpeed(double ticksPerSecond) { nativeSetGameSpeed((float) ticksPerSecond); } @JSStaticFunction public static void takeScreenshot(String fileName) { screenshotFileName = fileName.replace("/", "").replace("\\", ""); nativeRequestFrameCallback(); } @JSStaticFunction public static void langEdit(String key, String value) { nativeSetI18NString(key, value); } @JSStaticFunction public static void showTipMessage(String msg) { nativeShowTipMessage(msg); } /* * disabled since Substrate cannot hook the relevant method * * @JSStaticFunction public static void setStonecutterItem(int id, * boolean status) { //1: nope; 2: yep. nativeSetStonecutterItem(id, * status? 2: 1); } */ @JSStaticFunction public static void setCamera(int entityId) { nativeSetCameraEntity(entityId); } @Override public String getClassName() { return "ModPE"; } } private static class NativeItemApi extends ScriptableObject { public NativeItemApi() { } @JSStaticFunction public static String getName(int id, int damage, boolean raw) { return nativeGetItemName(id, damage, raw); } @JSStaticFunction public static void addCraftRecipe(int id, int count, int damage, Scriptable ingredients) { int[] expanded = expandShapelessRecipe(ingredients); nativeAddShapelessRecipe(id, count, damage, expanded); } @JSStaticFunction public static void addFurnaceRecipe(int inputId, int outputId, int outputDamage) { // Do I need a count? If not, should I just fill it with null, or // skip it completely? nativeAddFurnaceRecipe(inputId, outputId, outputDamage); } @JSStaticFunction public static void setMaxDamage(int id, int maxDamage) { nativeSetItemMaxDamage(id, maxDamage); } /* This doesn't actually work, and has never worked, but people wanted it to be re-added. I dunno why. */ @JSStaticFunction public static void setCategory(int id, int category, int whatever) { nativeSetItemCategory(id, category, whatever); } @Override public String getClassName() { return "Item"; } } private static class NativeBlockApi extends ScriptableObject { public NativeBlockApi() { } @JSStaticFunction public static void defineBlock(int blockId, String name, Object textures, Object materialSourceIdSrc, Object opaqueSrc, Object renderTypeSrc) { if (blockId < 0 || blockId >= 256) { throw new IllegalArgumentException("Block IDs must be >= 0 and < 256"); } int materialSourceId = 1; boolean opaque = true; int renderType = 0; if (materialSourceIdSrc != null && materialSourceIdSrc instanceof Number) { materialSourceId = ((Number) materialSourceIdSrc).intValue(); Log.i("BlockLauncher", "setting material source to " + materialSourceId); } if (opaqueSrc != null && opaqueSrc instanceof Boolean) { opaque = (Boolean) opaqueSrc; Log.i("BlockLauncher", "setting opaque to " + opaque); } if (renderTypeSrc != null && renderTypeSrc instanceof Number) { renderType = ((Number) renderTypeSrc).intValue(); Log.i("BlockLauncher", "setting renderType to " + renderType); } TextureRequests finalTextures = expandTexturesArray(textures); nativeDefineBlock(blockId, name, finalTextures.names, finalTextures.coords, materialSourceId, opaque, renderType); } @JSStaticFunction public static void setDestroyTime(int blockId, double time) { nativeBlockSetDestroyTime(blockId, (float) time); } @JSStaticFunction public static int getRenderType(int blockId) { return nativeGetBlockRenderShape(blockId); } @JSStaticFunction public static void setRenderType(int blockId, int renderType) { nativeSetBlockRenderShape(blockId, renderType); } @JSStaticFunction public static void setExplosionResistance(int blockId, double resist) { nativeBlockSetExplosionResistance(blockId, (float) resist); } @JSStaticFunction public static void setShape(int blockId, double v1, double v2, double v3, double v4, double v5, double v6) { nativeBlockSetShape(blockId, (float) v1, (float) v2, (float) v3, (float) v4, (float) v5, (float) v6); } /* * @JSStaticFunction public static void setStepSound(int blockId, int * sourceId) { nativeBlockSetStepSound(blockId, sourceId); } */ @JSStaticFunction public static void setLightLevel(int blockId, int lightLevel) { nativeBlockSetLightLevel(blockId, lightLevel); } @JSStaticFunction public static void setColor(int blockId, Scriptable colorArray) { int[] finalColors = expandColorsArray(colorArray); nativeBlockSetColor(blockId, finalColors); } @JSStaticFunction public static void setRenderLayer(int blockId, int layer) { nativeBlockSetRenderLayer(blockId, layer); } @Override public String getClassName() { return "Block"; } } private static class NativeServerApi extends ScriptableObject { public NativeServerApi() { } @JSStaticFunction public static void joinServer(String serverAddress, int port) { requestLeaveGame = true; requestJoinServer = new JoinServerRequest(); String resolvedAddress; try { InetAddress address = InetAddress.getByName(serverAddress); resolvedAddress = address.getHostAddress(); } catch (UnknownHostException e) { throw new RuntimeException(e); } requestJoinServer.serverAddress = resolvedAddress; requestJoinServer.serverPort = port; } @JSStaticFunction public static void sendChat(String message) { if (!isRemote) return; nativeSendChat(message); } @JSStaticFunction public static String getAddress() { return serverAddress; } @JSStaticFunction public static int getPort() { return serverPort; } // KMCPE's additions @JSStaticFunction public static int[] getAllPlayers() { int[] players = new int[allplayers.size()]; for(int n=0;players.length>n;n++){ players[n]=allplayers.get(n); } return players; } @JSStaticFunction public static String[] getAllPlayerNames() { String[] players = new String[allplayers.size()]; for(int n=0;players.length>n;n++){ players[n]=nativeGetPlayerName(allplayers.get(n)); } return players; } @Override public String getClassName() { return "Server"; } } private static class NativeGuiApi extends ScriptableObject { public NativeGuiApi() { } @JSStaticFunction public static int getScreenWidth() { return 0; } @JSStaticFunction public static int getScreenHeight() { return 0; } @Override public String getClassName() { return "Gui"; } } private static class SelectLevelRequest { public String dir; public String name, seed; public int gameMode = 0; } private static class JoinServerRequest { public String serverAddress; public int serverPort; } private static class AfterSkinDownloadAction implements Runnable { private int entityId; private String skinPath; public AfterSkinDownloadAction(int entityId, String skinPath) { this.entityId = entityId; this.skinPath = skinPath; } public void run() { File skinFile = getTextureOverrideFile("images/" + skinPath); if (skinFile == null || !skinFile.exists()) return; NativeEntityApi.setMobSkin(entityId, skinPath); } } private static class TextureRequests { public String[] names; public int[] coords; } }