+ Redstone input [WIP]

This commit is contained in:
Nicolas BARBOTIN 2018-01-31 04:18:48 +01:00
parent 63ba61a138
commit 18b2aa5ac3
11 changed files with 319 additions and 19 deletions

View File

@ -2,6 +2,7 @@
This is the unfinished port of the WebDisplays mod for Minecraft 1.12.2. The text below is my "TODO" list. This is the unfinished port of the WebDisplays mod for Minecraft 1.12.2. The text below is my "TODO" list.
### Missing features ### Missing features
* Crafts: upgrades, laser pointer, peripherals
* Screen upgrade: redstone input * Screen upgrade: redstone input
* Screen upgrade: redstone output * Screen upgrade: redstone output
* ~~Peripheral: ComputerCraft interface~~ (CC not up to date) * ~~Peripheral: ComputerCraft interface~~ (CC not up to date)
@ -10,6 +11,7 @@ This is the unfinished port of the WebDisplays mod for Minecraft 1.12.2. The tex
* Read config (see "Config elements" below) * Read config (see "Config elements" below)
### TODO ### TODO
* REDSTONE INPUT OPTIMIZATIONssss!!!
* Achievements (minePad 2 and all that stuff) * Achievements (minePad 2 and all that stuff)
* Top/bottom screen orientation * Top/bottom screen orientation
* GuiSetURL2 missing buttons * GuiSetURL2 missing buttons
@ -23,6 +25,8 @@ This is the unfinished port of the WebDisplays mod for Minecraft 1.12.2. The tex
* Enhance crafts * Enhance crafts
* Enhance models * Enhance models
* minePad item texture seems to be transparent in some corners... * minePad item texture seems to be transparent in some corners...
* Change mod name to WD2
* Put a limit on screen resolution
### Config elements ### Config elements
* Site blacklist * Site blacklist

View File

@ -4,6 +4,7 @@
package net.montoyo.wd.block; package net.montoyo.wd.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.EnumPushReaction; import net.minecraft.block.material.EnumPushReaction;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.IProperty;
@ -29,6 +30,7 @@ import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty; import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.common.property.Properties; import net.minecraftforge.common.property.Properties;
import net.montoyo.wd.WebDisplays; import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.ScreenRights; import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.core.IUpgrade; import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.data.SetURLData; import net.montoyo.wd.data.SetURLData;
@ -188,6 +190,23 @@ public class BlockScreen extends WDBlockContainer {
return true; return true;
} }
@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
for(BlockSide side: BlockSide.values()) {
Vector3i vec = new Vector3i(pos);
Multiblock.findOrigin(world, vec, side, null);
TileEntityScreen tes = (TileEntityScreen) world.getTileEntity(vec.toBlock());
if(tes != null && tes.hasUpgrade(side, WebDisplays.INSTANCE.itemUpgrade, DefaultUpgrade.REDSTONE_INPUT.ordinal())) {
EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()]; //Opposite face
vec.sub(pos.getX(), pos.getY(), pos.getZ()).neg();
tes.updateJSRedstone(side, new Vector2i(vec.dot(side.right), vec.dot(side.up)), world.getRedstonePower(pos, facing));
}
}
}
}
public static boolean hit2pixels(BlockSide side, BlockPos bpos, Vector3i pos, TileEntityScreen.Screen scr, float hitX, float hitY, float hitZ, Vector2i dst) { public static boolean hit2pixels(BlockSide side, BlockPos bpos, Vector3i pos, TileEntityScreen.Screen scr, float hitX, float hitY, float hitZ, Vector2i dst) {
if(side.right.x < 0) if(side.right.x < 0)
hitX -= 1.f; hitX -= 1.f;

View File

@ -31,9 +31,7 @@ import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.montoyo.mcef.api.IBrowser; import net.montoyo.mcef.api.*;
import net.montoyo.mcef.api.IDisplayHandler;
import net.montoyo.mcef.api.MCEFApi;
import net.montoyo.wd.SharedProxy; import net.montoyo.wd.SharedProxy;
import net.montoyo.wd.WebDisplays; import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen; import net.montoyo.wd.block.BlockScreen;
@ -53,7 +51,7 @@ import net.montoyo.wd.utilities.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public class ClientProxy extends SharedProxy implements IResourceManagerReloadListener, IDisplayHandler { public class ClientProxy extends SharedProxy implements IResourceManagerReloadListener, IDisplayHandler, IJSQueryHandler {
public class PadData { public class PadData {
@ -75,6 +73,7 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
private ArrayList<ResourceModelPair> modelBakers = new ArrayList<>(); private ArrayList<ResourceModelPair> modelBakers = new ArrayList<>();
private net.montoyo.mcef.api.API mcef; private net.montoyo.mcef.api.API mcef;
private MinePadRenderer minePadRenderer; private MinePadRenderer minePadRenderer;
private JSQueryDispatcher jsDispatcher;
private LaserPointerRenderer laserPointerRenderer; private LaserPointerRenderer laserPointerRenderer;
//Laser pointer //Laser pointer
@ -106,6 +105,7 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
public void init() { public void init() {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityScreen.class, new ScreenRenderer()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityScreen.class, new ScreenRenderer());
mcef = MCEFApi.getAPI(); mcef = MCEFApi.getAPI();
jsDispatcher = new JSQueryDispatcher(this);
minePadRenderer = new MinePadRenderer(); minePadRenderer = new MinePadRenderer();
laserPointerRenderer = new LaserPointerRenderer(); laserPointerRenderer = new LaserPointerRenderer();
} }
@ -118,6 +118,7 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
throw new RuntimeException("MCEF is missing"); throw new RuntimeException("MCEF is missing");
mcef.registerDisplayHandler(this); mcef.registerDisplayHandler(this);
mcef.registerJSQueryHandler(this);
} }
@Override @Override
@ -239,6 +240,46 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
public void onStatusMessage(IBrowser browser, String value) { public void onStatusMessage(IBrowser browser, String value) {
} }
/**************************************** JS HANDLER METHODS ****************************************/
@Override
public boolean handleQuery(IBrowser browser, long queryId, String query, boolean persistent, IJSQueryCallback cb) {
if(browser != null && persistent && query != null && cb != null) {
query = query.toLowerCase();
if(query.startsWith("webdisplays_")) {
query = query.substring(12);
String args;
int parenthesis = query.indexOf('(');
if(parenthesis < 0)
args = null;
else {
if(query.indexOf(')') != query.length() - 1) {
cb.failure(400, "Malformed request");
return true;
}
args = query.substring(parenthesis + 1, query.length() - 1);
query = query.substring(0, parenthesis);
}
if(jsDispatcher.canHandleQuery(query))
jsDispatcher.enqueueQuery(browser, query, args, cb);
else
cb.failure(404, "Unknown WebDisplays query");
return true;
}
}
return false;
}
@Override
public void cancelQuery(IBrowser browser, long queryId) {
}
/**************************************** EVENT METHODS ****************************************/ /**************************************** EVENT METHODS ****************************************/
@SubscribeEvent @SubscribeEvent
@ -368,6 +409,9 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
if(!raycastHit) if(!raycastHit)
deselectScreen(); deselectScreen();
//Handle JS queries
jsDispatcher.handleQueries();
} }
} }
@ -484,4 +528,27 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
return mcef; return mcef;
} }
public static final class ScreenSidePair {
public TileEntityScreen tes;
public BlockSide side;
}
public boolean findScreenFromBrowser(IBrowser browser, ScreenSidePair pair) {
for(TileEntityScreen tes: screenTracking) {
for(int i = 0; i < tes.screenCount(); i++) {
TileEntityScreen.Screen scr = tes.getScreen(i);
if(scr.browser == browser) {
pair.tes = tes;
pair.side = scr.side;
return true;
}
}
}
return false;
}
} }

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
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.core.IScreenQueryHandler;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector2i;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
@SideOnly(Side.CLIENT)
public final class JSQueryDispatcher {
private static final class QueryData {
private final IBrowser browser;
private final String query;
private final String args;
private final IJSQueryCallback callback;
private QueryData(IBrowser b, String q, String a, IJSQueryCallback cb) {
browser = b;
query = q;
args = a;
callback = cb;
}
}
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<>();
public JSQueryDispatcher(ClientProxy proxy) {
this.proxy = proxy;
registerDefaults();
}
public void enqueueQuery(IBrowser b, String q, String a, IJSQueryCallback cb) {
synchronized(queue) {
queue.offer(new QueryData(b, q, a, cb));
}
}
public void handleQueries() {
while(true) {
QueryData next;
synchronized(queue) {
next = queue.poll();
}
if(next == null)
break;
if(proxy.findScreenFromBrowser(next.browser, lookupResult)) {
Object[] args = (next.args == null) ? new Object[0] : parseArgs(next.args);
if(args == null)
next.callback.failure(400, "Malformed request parameters");
else {
try {
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);
}
}
} else
next.callback.failure(403, "A screen is required");
}
}
public boolean canHandleQuery(String q) {
return handlers.containsKey(q);
}
private static Object[] parseArgs(String args) {
ArrayList<String> array = new ArrayList<>();
int lastIdx = 0;
boolean inString = false;
boolean escape = false;
boolean hadString = false;
for(int i = 0; i < args.length(); i++) {
char chr = args.charAt(i);
if(inString) {
if(escape)
escape = false;
else {
if(chr == '\"')
inString = false;
else if(chr == '\\')
escape = true;
}
} else if(chr == '\"') {
if(hadString)
return null;
inString = true;
hadString = true;
} else if(chr == ',') {
array.add(args.substring(lastIdx, i).trim());
lastIdx = i + 1;
hadString = false;
}
}
if(inString)
return null; //Non terminated string
array.add(args.substring(lastIdx).trim());
Object[] ret = new Object[array.size()];
for(int i = 0; i < ret.length; i++) {
String str = array.get(i);
if(str.isEmpty())
return null; //Nah...
if(str.charAt(0) == '\"') //String
ret[i] = str.substring(1, str.length() - 1);
else {
try {
ret[i] = Double.parseDouble(str);
} catch(NumberFormatException ex) {
return null;
}
}
}
return ret;
}
public void register(String query, IScreenQueryHandler handler) {
handlers.put(query.toLowerCase(), handler);
}
private void registerDefaults() {
register("getSize", (cb, tes, side, args) -> {
Vector2i size = tes.getScreen(side).size;
cb.success("{\"x\":" + size.x + ",\"y\":" + size.y + "}");
});
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.montoyo.mcef.api.IJSQueryCallback;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import javax.annotation.Nonnull;
public interface IScreenQueryHandler {
//args is an array of Doubles or Strings
//The screen DOES exist, so scr.getScreen(side) is never null
void handleQuery(@Nonnull IJSQueryCallback cb, @Nonnull TileEntityScreen scr, @Nonnull BlockSide side, @Nonnull Object[] args);
}

View File

@ -29,9 +29,7 @@ import net.montoyo.wd.data.ScreenConfigData;
import net.montoyo.wd.net.CMessageAddScreen; import net.montoyo.wd.net.CMessageAddScreen;
import net.montoyo.wd.net.CMessageScreenUpdate; import net.montoyo.wd.net.CMessageScreenUpdate;
import net.montoyo.wd.net.SMessageRequestTEData; import net.montoyo.wd.net.SMessageRequestTEData;
import net.montoyo.wd.net.SMessageScreenCtrl;
import net.montoyo.wd.utilities.*; import net.montoyo.wd.utilities.*;
import org.lwjgl.Sys;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
@ -419,6 +417,20 @@ public class TileEntityScreen extends TileEntity {
} }
} }
public void updateJSRedstone(BlockSide side, Vector2i vec, int redstoneLevel) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Called updateJSRedstone on non-existing side %s", side.toString());
return;
}
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());
}
@Override @Override
public void onLoad() { public void onLoad() {
if(world.isRemote) { if(world.isRemote) {

View File

@ -30,6 +30,7 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
public static final int UPDATE_MOUSE = 3; public static final int UPDATE_MOUSE = 3;
public static final int UPDATE_TYPE = 4; public static final int UPDATE_TYPE = 4;
public static final int UPDATE_UPGRADES = 5; public static final int UPDATE_UPGRADES = 5;
public static final int UPDATE_JS_REDSTONE = 6;
public static final int MOUSE_CLICK = 0; public static final int MOUSE_CLICK = 0;
public static final int MOUSE_UP = 1; public static final int MOUSE_UP = 1;
@ -40,11 +41,11 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
private BlockSide side; private BlockSide side;
private int action; private int action;
private String url; private String url;
private Vector2i resolution; private Vector2i vec2i;
private int mouseEvent; private int mouseEvent;
private Vector2i mouse;
private String text; private String text;
private ItemStack[] upgrades; private ItemStack[] upgrades;
private int redstoneLevel;
public CMessageScreenUpdate() { public CMessageScreenUpdate() {
} }
@ -64,7 +65,7 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
ret.pos = new Vector3i(tes.getPos()); ret.pos = new Vector3i(tes.getPos());
ret.side = side; ret.side = side;
ret.action = UPDATE_RESOLUTION; ret.action = UPDATE_RESOLUTION;
ret.resolution = res; ret.vec2i = res;
return ret; return ret;
} }
@ -75,7 +76,7 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
ret.side = side; ret.side = side;
ret.action = UPDATE_MOUSE; ret.action = UPDATE_MOUSE;
ret.mouseEvent = mouseEvent; ret.mouseEvent = mouseEvent;
ret.mouse = pos; ret.vec2i = pos;
return ret; return ret;
} }
@ -111,6 +112,17 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
return ret; return ret;
} }
public static CMessageScreenUpdate jsRedstone(TileEntityScreen tes, BlockSide side, Vector2i vec, int level) {
CMessageScreenUpdate ret = new CMessageScreenUpdate();
ret.pos = new Vector3i(tes.getPos());
ret.side = side;
ret.action = UPDATE_JS_REDSTONE;
ret.vec2i = vec;
ret.redstoneLevel = level;
return ret;
}
@Override @Override
public void fromBytes(ByteBuf buf) { public void fromBytes(ByteBuf buf) {
pos = new Vector3i(buf); pos = new Vector3i(buf);
@ -123,9 +135,9 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
mouseEvent = buf.readByte(); mouseEvent = buf.readByte();
if(mouseEvent != MOUSE_UP) if(mouseEvent != MOUSE_UP)
mouse = new Vector2i(buf); vec2i = new Vector2i(buf);
} else if(action == UPDATE_RESOLUTION) } else if(action == UPDATE_RESOLUTION)
resolution = new Vector2i(buf); vec2i = new Vector2i(buf);
else if(action == UPDATE_TYPE) else if(action == UPDATE_TYPE)
text = ByteBufUtils.readUTF8String(buf); text = ByteBufUtils.readUTF8String(buf);
else if(action == UPDATE_UPGRADES) { else if(action == UPDATE_UPGRADES) {
@ -133,6 +145,9 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
for(int i = 0; i < upgrades.length; i++) for(int i = 0; i < upgrades.length; i++)
upgrades[i] = ByteBufUtils.readItemStack(buf); upgrades[i] = ByteBufUtils.readItemStack(buf);
} else if(action == UPDATE_JS_REDSTONE) {
vec2i = new Vector2i(buf);
redstoneLevel = buf.readByte();
} }
} }
@ -148,9 +163,9 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
buf.writeByte(mouseEvent); buf.writeByte(mouseEvent);
if(mouseEvent != MOUSE_UP) if(mouseEvent != MOUSE_UP)
mouse.writeTo(buf); vec2i.writeTo(buf);
} else if(action == UPDATE_RESOLUTION) } else if(action == UPDATE_RESOLUTION)
resolution.writeTo(buf); vec2i.writeTo(buf);
else if(action == UPDATE_TYPE) else if(action == UPDATE_TYPE)
ByteBufUtils.writeUTF8String(buf, text); ByteBufUtils.writeUTF8String(buf, text);
else if(action == UPDATE_UPGRADES) { else if(action == UPDATE_UPGRADES) {
@ -158,6 +173,9 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
for(ItemStack is: upgrades) for(ItemStack is: upgrades)
ByteBufUtils.writeItemStack(buf, is); ByteBufUtils.writeItemStack(buf, is);
} else if(action == UPDATE_JS_REDSTONE) {
vec2i.writeTo(buf);
buf.writeByte(redstoneLevel);
} }
} }
@ -179,15 +197,17 @@ public class CMessageScreenUpdate implements IMessage, Runnable {
if(action == UPDATE_URL) if(action == UPDATE_URL)
tes.setScreenURL(side, url); tes.setScreenURL(side, url);
else if(action == UPDATE_MOUSE) else if(action == UPDATE_MOUSE)
tes.handleMouseEvent(side, mouseEvent, mouse); tes.handleMouseEvent(side, mouseEvent, vec2i);
else if(action == UPDATE_DELETE) else if(action == UPDATE_DELETE)
tes.removeScreen(side); tes.removeScreen(side);
else if(action == UPDATE_RESOLUTION) else if(action == UPDATE_RESOLUTION)
tes.setResolution(side, resolution); tes.setResolution(side, vec2i);
else if(action == UPDATE_TYPE) else if(action == UPDATE_TYPE)
tes.type(side, text, null); tes.type(side, text, null);
else if(action == UPDATE_UPGRADES) else if(action == UPDATE_UPGRADES)
tes.updateUpgrades(side, upgrades); tes.updateUpgrades(side, upgrades);
else if(action == UPDATE_JS_REDSTONE)
tes.updateJSRedstone(side, vec2i, redstoneLevel);
else else
Log.warning("===> TODO"); //TODO Log.warning("===> TODO"); //TODO
} }

View File

@ -199,6 +199,10 @@ public final class Vector3i {
return this; return this;
} }
public int dot(Vector3i vec) {
return x * vec.x + y * vec.y + z * vec.z;
}
public Vector3f toFloat() { public Vector3f toFloat() {
return new Vector3f((float) x, (float) y, (float) z); return new Vector3f((float) x, (float) y, (float) z);
} }

View File

@ -77,6 +77,6 @@
<img src="webdisplays.png" /> <img src="webdisplays.png" />
</td> </td>
</tr> </tr>
</div> </table>
</body> </body>
</html> </html>

View File

@ -1,6 +1,7 @@
{ {
"parent": "item/generated", "parent": "item/generated",
"textures": { "textures": {
"layer0": "webdisplays:items/upgrade" "layer0": "webdisplays:items/upgrade",
"layer1": "webdisplays:items/input"
} }
} }

View File

@ -1,6 +1,7 @@
{ {
"parent": "item/generated", "parent": "item/generated",
"textures": { "textures": {
"layer0": "webdisplays:items/upgrade" "layer0": "webdisplays:items/upgrade",
"layer1": "webdisplays:items/output"
} }
} }