+ Redstone input (working)

This commit is contained in:
Nicolas BARBOTIN 2018-02-01 00:07:26 +01:00
parent 18b2aa5ac3
commit fbfae32c84
16 changed files with 629 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.server.FMLServerHandler;
import net.montoyo.mcef.utilities.Log;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
@ -65,4 +66,12 @@ public class SharedProxy {
Log.error("Called SharedProxy.openMinePadGui() on server side...");
}
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
Log.error("Called SharedProxy.handleJSResponseSuccess() on server side...");
}
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
Log.error("Called SharedProxy.handleJSResponseError() on server side...");
}
}

View File

@ -192,7 +192,7 @@ public class BlockScreen extends WDBlockContainer {
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos source) {
if(block != this && !world.isRemote) { //I'm worried this could blow up, hopefully this won't create a bug or something
if(block != this && !world.isRemote) {
for(BlockSide side: BlockSide.values()) {
Vector3i vec = new Vector3i(pos);
Multiblock.findOrigin(world, vec, side, null);

View File

@ -42,6 +42,7 @@ import net.montoyo.wd.client.gui.WDScreen;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.renderers.*;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.SMessagePadCtrl;
@ -200,6 +201,29 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
mc.displayGuiScreen(new GuiMinePad(pd));
}
@Override
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
if(q == null)
Log.warning("Received success response for invalid query ID %d of type %s", reqId, type.toString());
else {
if(type == JSServerRequest.WHATEVER) {
} else
Log.warning("Received success response for query ID %d, but type is invalid", reqId);
}
}
@Override
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
if(q == null)
Log.warning("Received error response for invalid query ID %d of type %s", reqId, type.toString());
else
q.error(errCode, err);
}
/**************************************** RESOURCE MANAGER METHODS ****************************************/
@Override

View File

@ -4,13 +4,22 @@
package net.montoyo.wd.client;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.mcef.api.IBrowser;
import net.montoyo.mcef.api.IJSQueryCallback;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IScreenQueryHandler;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.SMessageScreenCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector2i;
import net.montoyo.wd.utilities.Vector3i;
import java.util.ArrayDeque;
import java.util.ArrayList;
@ -35,10 +44,49 @@ public final class JSQueryDispatcher {
}
public static final class ServerQuery {
private static int lastId = 0;
private final TileEntityScreen tes;
private final BlockSide side;
private final IJSQueryCallback callback;
private final int id;
private ServerQuery(TileEntityScreen t, BlockSide s, IJSQueryCallback cb) {
tes = t;
side = s;
callback = cb;
id = lastId++;
}
public TileEntityScreen getTileEntity() {
return tes;
}
public BlockSide getSide() {
return side;
}
public TileEntityScreen.Screen getScreen() {
return tes.getScreen(side);
}
public void success(String resp) {
callback.success(resp);
}
public void error(int errId, String errStr) {
callback.failure(errId, errStr);
}
}
private final ClientProxy proxy;
private final ArrayDeque<QueryData> queue = new ArrayDeque<>();
private final ClientProxy.ScreenSidePair lookupResult = new ClientProxy.ScreenSidePair();
private final HashMap<String, IScreenQueryHandler> handlers = new HashMap<>();
private final ArrayList<ServerQuery> serverQueries = new ArrayList<>();
public JSQueryDispatcher(ClientProxy proxy) {
this.proxy = proxy;
@ -71,6 +119,7 @@ public final class JSQueryDispatcher {
handlers.get(next.query).handleQuery(next.callback, lookupResult.tes, lookupResult.side, args);
} catch(Throwable t) {
Log.warningEx("Could not execute JS query %s(%s)", t, next.query, (next.args == null) ? "" : next.args);
next.callback.failure(500, "Internal error");
}
}
} else
@ -143,11 +192,86 @@ public final class JSQueryDispatcher {
handlers.put(query.toLowerCase(), handler);
}
public ServerQuery fulfillQuery(int id) {
int toRemove = -1;
for(int i = 0; i < serverQueries.size(); i++) {
ServerQuery sq = serverQueries.get(i);
if(sq.id == id) {
toRemove = i;
break;
}
}
if(toRemove < 0)
return null;
else
return serverQueries.remove(toRemove);
}
private void makeServerQuery(TileEntityScreen tes, BlockSide side, IJSQueryCallback cb, JSServerRequest type, Object ... data) {
ServerQuery ret = new ServerQuery(tes, side, cb);
serverQueries.add(ret);
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.jsRequest(tes, side, ret.id, type, data));
}
private void registerDefaults() {
register("getSize", (cb, tes, side, args) -> {
register("GetSize", (cb, tes, side, args) -> {
Vector2i size = tes.getScreen(side).size;
cb.success("{\"x\":" + size.x + ",\"y\":" + size.y + "}");
});
register("GetRedstoneAt", (cb, tes, side, args) -> {
if(!tes.hasUpgrade(side, WebDisplays.INSTANCE.itemUpgrade, DefaultUpgrade.REDSTONE_INPUT.ordinal())) {
cb.failure(403, "Missing upgrade");
return;
}
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
TileEntityScreen.Screen scr = tes.getScreen(side);
int x = ((Double) args[0]).intValue();
int y = ((Double) args[1]).intValue();
if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
cb.failure(403, "Out of range");
else {
int level = tes.getWorld().getRedstonePower((new Vector3i(tes.getPos())).addMul(side.right, x).addMul(side.up, y).toBlock(), EnumFacing.VALUES[side.reverse().ordinal()]);
cb.success("{\"level\":" + level + "}");
}
} else
cb.failure(400, "Wrong arguments");
});
register("GetRedstoneArray", (cb, tes, side, args) -> {
if(tes.hasUpgrade(side, WebDisplays.INSTANCE.itemUpgrade, DefaultUpgrade.REDSTONE_INPUT.ordinal())) {
final Vector2i size = tes.getScreen(side).size;
final EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()];
final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos();
final Vector3i vec1 = new Vector3i(tes.getPos());
final Vector3i vec2 = new Vector3i();
final StringBuilder resp = new StringBuilder("{\"levels\":[");
for(int y = 0; y < size.y; y++) {
vec2.set(vec1);
for(int x = 0; x < size.x; x++) {
if(x > 0 || y > 0)
resp.append(',');
vec2.toBlock(mbp);
resp.append(tes.getWorld().getRedstonePower(mbp, facing));
vec2.add(side.right.x, side.right.y, side.right.z);
}
vec1.add(side.up.x, side.up.y, side.up.z);
}
cb.success(resp.append("]}").toString());
} else
cb.failure(403, "Missing upgrade");
});
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import io.netty.buffer.ByteBuf;
import net.montoyo.wd.utilities.Util;
public enum JSServerRequest {
WHATEVER;
private final Class[] requestTypes;
JSServerRequest(Class<?> ... requestTypes) {
this.requestTypes = requestTypes;
}
public static JSServerRequest fromID(int id) {
JSServerRequest[] values = values();
return (id >= 0 && id < values.length) ? values[id] : null;
}
public boolean serialize(ByteBuf buf, Object[] data) {
if(data.length != requestTypes.length)
return false;
for(int i = 0; i < data.length; i++) {
if(data[i].getClass() != requestTypes[i])
return false;
Util.serialize(buf, data[i]);
}
return true;
}
public Object[] deserialize(ByteBuf buf) {
Object[] ret = new Object[requestTypes.length];
try {
for(int i = 0; i < requestTypes.length; i++)
ret[i] = Util.unserialize(buf, requestTypes[i]);
} catch(Throwable t) {
t.printStackTrace();
return null;
}
return ret;
}
}

View File

@ -4,7 +4,7 @@
package net.montoyo.wd.core;
public class ScreenRights {
public abstract class ScreenRights {
public static final int CHANGE_URL = 1;
public static final int CLICK = 2;

View File

@ -12,21 +12,21 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.montoyo.mcef.api.IBrowser;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.data.ScreenConfigData;
import net.montoyo.wd.net.CMessageAddScreen;
import net.montoyo.wd.net.CMessageJSResponse;
import net.montoyo.wd.net.CMessageScreenUpdate;
import net.montoyo.wd.net.SMessageRequestTEData;
import net.montoyo.wd.utilities.*;
@ -53,6 +53,7 @@ public class TileEntityScreen extends TileEntity {
public long turnOnTime;
public EntityPlayer laserUser;
public final Vector2i lastMousePos = new Vector2i();
public NibbleArray redstoneStatus; //null on client
public static Screen deserialize(NBTTagCompound tag) {
Screen ret = new Screen();
@ -151,6 +152,37 @@ public class TileEntityScreen extends TileEntity {
return friends.stream().anyMatch((f) -> f.uuid.equals(uuid)) ? friendRights : otherRights;
}
public void setupRedstoneStatus(World world, BlockPos start) {
if(world.isRemote) {
Log.warning("Called Screen.setupRedstoneStatus() on client.");
return;
}
if(redstoneStatus != null) {
Log.warning("Called Screen.setupRedstoneStatus() on server, but redstone status is non-null");
return;
}
redstoneStatus = new NibbleArray(size.x * size.y);
final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos();
final Vector3i vec1 = new Vector3i(start);
final Vector3i vec2 = new Vector3i();
final EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()];
for(int y = 0; y < size.y; y++) {
final int base = y * size.x;
vec2.set(vec1);
for(int x = 0; x < size.x; x++) {
vec2.toBlock(mbp);
redstoneStatus.set(base + x, world.getRedstonePower(mbp, facing));
vec2.add(side.right.x, side.right.y, side.right.z);
}
vec1.add(side.up.x, side.up.y, side.up.z);
}
}
}
private ArrayList<Screen> screens = new ArrayList<>();
@ -231,9 +263,11 @@ public class TileEntityScreen extends TileEntity {
} else
ret.resolution = resolution;
if(sendUpdate && !world.isRemote) {
CMessageAddScreen msg = new CMessageAddScreen(this, ret);
WebDisplays.NET_HANDLER.sendToAllAround(msg, point());
if(!world.isRemote) {
ret.setupRedstoneStatus(world, pos);
if(sendUpdate)
WebDisplays.NET_HANDLER.sendToAllAround(new CMessageAddScreen(this, ret), point());
}
screens.add(ret);
@ -427,8 +461,45 @@ public class TileEntityScreen extends TileEntity {
if(world.isRemote) {
if(scr.browser != null)
scr.browser.runJS("if(typeof webdisplaysRedstoneCallback == \"function\") webdisplaysRedstoneCallback(" + vec.x + ", " + vec.y + ", " + redstoneLevel + ");", "");
} else if(scr.upgrades.stream().anyMatch((is) -> is.getItem() == WebDisplays.INSTANCE.itemUpgrade && is.getMetadata() == DefaultUpgrade.REDSTONE_INPUT.ordinal()))
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.jsRedstone(this, side, vec, redstoneLevel), point());
} else {
boolean sendMsg = false;
if(scr.redstoneStatus == null) {
scr.setupRedstoneStatus(world, pos);
sendMsg = true;
} else {
int idx = vec.y * scr.size.x + vec.x;
if(scr.redstoneStatus.get(idx) != redstoneLevel) {
scr.redstoneStatus.set(idx, redstoneLevel);
sendMsg = true;
}
}
if(sendMsg)
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.jsRedstone(this, side, vec, redstoneLevel), point());
}
}
public void handleJSRequest(EntityPlayerMP src, BlockSide side, int reqId, JSServerRequest req, Object[] data) {
if(world.isRemote) {
Log.error("Called handleJSRequest client-side");
return;
}
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Called handleJSRequest on non-existing side %s", side.toString());
WebDisplays.NET_HANDLER.sendTo(new CMessageJSResponse(reqId, req, 403, "Invalid side"), src);
return;
}
if(scr.upgrades.stream().noneMatch((is) -> is.getItem() == WebDisplays.INSTANCE.itemUpgrade && is.getMetadata() == DefaultUpgrade.REDSTONE_OUTPUT.ordinal())) {
WebDisplays.NET_HANDLER.sendTo(new CMessageJSResponse(reqId, req, 403, "Missing upgrade"), src);
return;
}
//Meh, TODO
}
@Override

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.utilities.Log;
@Message(messageId = 9, side = Side.CLIENT)
public class CMessageJSResponse implements IMessage, Runnable {
private int id;
private JSServerRequest type;
private boolean success;
private byte[] data;
private int errCode;
private String errString;
public CMessageJSResponse() {
}
public CMessageJSResponse(int id, JSServerRequest t, byte[] d) {
this.id = id;
type = t;
success = true;
data = d;
}
public CMessageJSResponse(int id, JSServerRequest t, int code, String err) {
this.id = id;
type = t;
success = false;
errCode = code;
errString = err;
}
@Override
public void fromBytes(ByteBuf buf) {
id = buf.readInt();
type = JSServerRequest.fromID(buf.readByte());
success = buf.readBoolean();
if(success) {
data = new byte[buf.readByte()];
buf.readBytes(data);
} else {
errCode = buf.readInt();
errString = ByteBufUtils.readUTF8String(buf);
}
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(id);
buf.writeByte(type.ordinal());
buf.writeBoolean(success);
if(success) {
buf.writeByte(data.length);
buf.writeBytes(data); //TODO: Eventually compress this data
} else {
buf.writeInt(errCode);
ByteBufUtils.writeUTF8String(buf, errString);
}
}
@Override
public void run() {
try {
if(success)
WebDisplays.PROXY.handleJSResponseSuccess(id, type, data);
else
WebDisplays.PROXY.handleJSResponseError(id, type, errCode, errString);
} catch(Throwable t) {
Log.warningEx("Could not handle JS response", t);
}
}
}

View File

@ -26,6 +26,7 @@ public class Messages {
l.add(CMessageACResult.class);
l.add(SMessagePadCtrl.class);
l.add(SMessageRedstoneCtrl.class);
l.add(CMessageJSResponse.class);
messages = l.toArray(new Class[0]);
}

View File

@ -16,6 +16,7 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
@ -35,6 +36,7 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
public static final int CTRL_LASER_DOWN = 8;
public static final int CTRL_LASER_MOVE = 9;
public static final int CTRL_LASER_UP = 10;
public static final int CTRL_JS_REQUEST = 11;
private int ctrl;
private int dim;
@ -49,6 +51,9 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
private String text;
private BlockPos soundPos;
private ItemStack toRemove;
private int jsReqID;
private JSServerRequest jsReqType;
private Object[] jsReqData;
public SMessageScreenCtrl() {
}
@ -130,6 +135,19 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
return ret;
}
public static SMessageScreenCtrl jsRequest(TileEntityScreen tes, BlockSide side, int reqId, JSServerRequest reqType, Object ... data) {
SMessageScreenCtrl ret = new SMessageScreenCtrl();
ret.ctrl = CTRL_JS_REQUEST;
ret.pos = new Vector3i(tes.getPos());
ret.dim = tes.getWorld().provider.getDimension();
ret.side = side;
ret.jsReqID = reqId;
ret.jsReqType = reqType;
ret.jsReqData = data;
return ret;
}
private static boolean isVec2Ctrl(int msg) {
return msg == CTRL_SET_RESOLUTION || msg == CTRL_LASER_DOWN || msg == CTRL_LASER_MOVE;
}
@ -159,6 +177,13 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
soundPos = new BlockPos(sx, sy, sz);
} else if(ctrl == CTRL_REMOVE_UPGRADE)
toRemove = ByteBufUtils.readItemStack(buf);
else if(ctrl == CTRL_JS_REQUEST) {
jsReqID = buf.readInt();
jsReqType = JSServerRequest.fromID(buf.readByte());
if(jsReqType != null)
jsReqData = jsReqType.deserialize(buf);
}
}
@Override
@ -184,6 +209,13 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
buf.writeInt(soundPos.getZ());
} else if(ctrl == CTRL_REMOVE_UPGRADE)
ByteBufUtils.writeItemStack(buf, toRemove);
else if(ctrl == CTRL_JS_REQUEST) {
buf.writeInt(jsReqID);
buf.writeByte(jsReqType.ordinal());
if(!jsReqType.serialize(buf, jsReqData))
throw new RuntimeException("Could not serialize CTRL_JS_REQUEST " + jsReqType);
}
}
@Override
@ -248,7 +280,12 @@ public class SMessageScreenCtrl implements IMessage, Runnable {
tes.laserDownMove(side, player, vec2i, ctrl == CTRL_LASER_DOWN);
else if(ctrl == CTRL_LASER_UP)
tes.laserUp(side, player);
else
else if(ctrl == CTRL_JS_REQUEST) {
if(jsReqType == null || jsReqData == null)
Log.warning("Caught invalid JS request from player %s (UUID %s)", player.getName(), player.getGameProfile().getId().toString());
else
tes.handleJSRequest(player, side, jsReqID, jsReqType, jsReqData);
} else
Log.info("SMessageScreenCtrl: TODO"); //TODO: other ctrl messages
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
public final class NibbleArray {
private final byte[] data;
public NibbleArray(int count) {
if((count & 1) != 0)
count++;
data = new byte[count >> 1];
}
public NibbleArray(byte[] d) {
data = d;
}
public final int get(int idx) {
if((idx & 1) == 0)
return (data[idx >> 1] >> 4) & 0x0F; //MSB
else
return data[idx >> 1] & 0x0F; //LSB
}
public final void set(int idx, int val) {
val &= 0x0F;
if((idx & 1) == 0) {
idx >>= 1;
data[idx] = (byte) ((data[idx] & 0x0F) | (val << 4)); //MSB
} else {
idx >>= 1;
data[idx] = (byte) ((data[idx] & 0xF0) | val); //LSB
}
}
public byte[] copyBytes() {
byte[] ret = new byte[data.length];
System.arraycopy(data, 0, ret, 0, data.length);
return ret;
}
}

View File

@ -0,0 +1,125 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
body {
margin: 0;
padding: 0;
overflow: hidden;
}
#content {
margin: 0;
padding: 0;
}
#content td {
margin: 0;
padding: 0;
text-align: center;
text-valign: middle;
}
#content tr {
margin: 0;
padding: 0;
}
.border_left {
border-left: 1px solid black;
}
.border_top {
border-top: 1px solid black;
}
.redstone_on {
background-color: rgb(255, 0, 0);
}
</style>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="wdlib.js"></script>
<script type="text/javascript">
var screenW = 1;
var screenH = 1;
var screenData = [ 0 ];
var gotSize = false;
var gotData = false;
function generateTable() {
var ppp = $(window).width() / (screenW - 0.25);
var border = Math.floor(ppp * 0.125);
ppp = Math.floor(ppp);
for(y = 0; y < screenH; y++) {
var line = "<tr>";
for(x = 0; x < screenW; x++) {
var classes = [];
var cw = ppp;
var ch = ppp;
var value = screenData[(screenH - y - 1) * screenW + x];
if(x > 0)
classes.push("border_left");
if(x <= 0 || x >= screenW - 1)
cw -= border;
if(y > 0)
classes.push("border_top");
if(y <= 0 || y >= screenH - 1)
ch -= border;
if(value > 0)
classes.push("redstone_on");
line += "<td id=\"cell_" + x + "_" + y + "\" class=\"" + classes.join(" ") + "\" style=\"width: " + cw + "px; height: " + ch + "px;\">" + value + "</td>";
}
line += "</tr>";
$("#content").append(line);
}
}
/* This function has to be named that way */
function webdisplaysRedstoneCallback(x, y, value) {
y = screenH - y - 1; //Flip Y axis
var elem = $("#cell_" + x + "_" + y);
elem.html("" + value);
if(value > 0 && !elem.hasClass("redstone_on"))
elem.addClass("redstone_on");
else if(value <= 0 && elem.hasClass("redstone_on"))
elem.removeClass("redstone_on");
}
$(function() {
wdGetSize(function(w, h) {
screenW = w;
screenH = h;
if(gotData)
generateTable();
else
gotSize = true;
});
wdGetRedstoneArray(function(array) {
screenData = array;
if(gotSize)
generateTable();
else
gotData = true;
});
});
</script>
</head>
<body>
<table id="content" cellspacing="0" cellpadding="0">
</table>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,38 @@
/* This specific file is completely open-source,
* comes without copyright and you can freely
* copy-paste it wherever you want or do whatever
* you want with it.
*/
function wdExecRequest(name, func) {
window.mcefQuery({ request: "WebDisplays_" + name,
persistent: true,
onSuccess: function(response) {
try {
func(JSON.parse(response));
} catch(e) {
document.write(response + "<br/>" + e);
}
},
onFailure: function(errCode, errMsg) {
document.write(errMsg);
}});
}
function wdGetSize(callback) {
wdExecRequest("GetSize", function(size) {
callback(size.x, size.y);
});
}
function wdGetRedstoneAt(x, y, callback) {
wdExecRequest("GetRedstoneAt(" + x + "," + y + ")", function(resp) {
callback(resp.level);
});
}
function wdGetRedstoneArray(callback) {
wdExecRequest("GetRedstoneArray", function(resp) {
callback(resp.levels);
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B