diff --git a/README.md b/README.md
index fd03953..e270dc5 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,16 @@
# WebDisplays for Minecraft 1.19.2
-This is a fork of the Web Displays mod from 1.12, updated to work on 1.19, and with some bug fixes and reworking.
+This is a fork of the Web Displays mod from 1.12, updated to work in newer versions, and with some bug fixes and reworking.
### Wiki
* The Wiki that details all blocks/items can be found on my website https://montoyo.net/wdwiki/
### Delayed things
* Plugin API
-* The Shop
-* CC Interface, if CC gets updated...
+* The Shop (what)
* Center camera to screen when using keyboard
* minePad management: check GuiContainer.draggedStack for minePad
* In-game command to add/remove blacklisted domains
-* Config: RPMP (Real pixels per Minecraft pixels)
-* Disable miniserv in solo
+* Config: RPMP (Real pixels per Minecraft pixels) (what)
+* CC Interface (for when it's actually possible, since the screens are client only currently, but a config option is planned to change that)
+* Redstone controls (same reason as CC interface)
+* Redo minisrv logic?
diff --git a/libs/mcef-2.x.jar b/libs/mcef-2.x.jar
index 6e2a0fe..f4316ec 100644
Binary files a/libs/mcef-2.x.jar and b/libs/mcef-2.x.jar differ
diff --git a/src/main/java/net/montoyo/wd/client/ClientProxy.java b/src/main/java/net/montoyo/wd/client/ClientProxy.java
index b4f3705..56ee004 100644
--- a/src/main/java/net/montoyo/wd/client/ClientProxy.java
+++ b/src/main/java/net/montoyo/wd/client/ClientProxy.java
@@ -85,6 +85,7 @@ import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefFrame;
import org.cef.handler.CefDisplayHandler;
+import org.cef.network.CefRequest;
import org.joml.Vector3d;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -138,12 +139,11 @@ public class ClientProxy extends SharedProxy implements CefDisplayHandler/*, IJS
return;
if (!LaserPointerRenderer.isOn()) {
- RenderSystem.setShaderTexture(0, new ResourceLocation(
- "webdisplays:textures/gui/cursors.png"
- ));
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
-
-// blit(poseStack, (screenWidth - 15) / 2, (screenHeight - 15) / 2, 240, 240, 15, 15, offset);
+
+ poseStack.blit(new ResourceLocation(
+ "webdisplays:textures/gui/cursors.png"
+ ), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, 240, 240, 15, 15, 256, 256);
ci.cancel();
return;
}
@@ -154,9 +154,16 @@ public class ClientProxy extends SharedProxy implements CefDisplayHandler/*, IJS
BlockPos bpos = result.getBlockPos();
- if (result.getType() != HitResult.Type.BLOCK || mc.level.getBlockState(bpos).getBlock() != BlockInit.blockScreen.get())
+ if (result.getType() != HitResult.Type.BLOCK || mc.level.getBlockState(bpos).getBlock() != BlockInit.blockScreen.get()) {
+ RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
+
+ poseStack.blit(new ResourceLocation(
+ "webdisplays:textures/gui/cursors.png"
+ ), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, 240, 240, 15, 15, 256, 256);
+ ci.cancel();
return;
-
+ }
+
Vector3i pos = new Vector3i(result.getBlockPos());
BlockSide side = BlockSide.values()[result.getDirection().ordinal()];
@@ -166,19 +173,17 @@ public class ClientProxy extends SharedProxy implements CefDisplayHandler/*, IJS
TileEntityScreen.Screen sc = te.getScreen(side);
if (sc == null) return;
-// if (sc.mouseType == 1) return;
-
+
int coordX = sc.mouseType * 15;
int coordY = coordX / 256;
coordX -= coordY * 256;
- RenderSystem.setShaderTexture(0, new ResourceLocation(
- "webdisplays:textures/gui/cursors.png"
- ));
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
-
-// blit(poseStack, (screenWidth - 15) / 2, (screenHeight - 15) / 2, coordX, coordY, 15, 15, offset);
-
+
+ poseStack.blit(new ResourceLocation(
+ "webdisplays:textures/gui/cursors.png"
+ ), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, coordX, coordY, 15, 15, 256, 256);
+
ci.cancel();
}
@@ -258,16 +263,21 @@ public class ClientProxy extends SharedProxy implements CefDisplayHandler/*, IJS
@Override
public void onCefInit(/*CefInitEvent event*/) {
MinecraftForge.EVENT_BUS.register(this);
-// if (mcef != null)
-// mcef.registerScheme("wd", WDScheme.class, true, false, false, true, true, false, false);
+
+ if (!MCEF.isInitialized()) return;
+
+ MCEF.getApp().getHandle().registerSchemeHandlerFactory(
+ "webdisplays", "",
+ (browser, frame, url, request) -> {
+ // TODO: check if it's a webdisplays browser?
+ return new WDScheme(request.getURL());
+ }
+ );
// jsDispatcher = new JSQueryDispatcher(this);
minePadRenderer = new MinePadRenderer();
laserPointerRenderer = new LaserPointerRenderer();
-// if (mcef == null)
-// throw new RuntimeException("MCEF is missing");
-
MCEF.getClient().addDisplayHandler(this);
// mcef.registerJSQueryHandler(this);
findAdvancementToProgressField();
diff --git a/src/main/java/net/montoyo/wd/client/WDScheme.java b/src/main/java/net/montoyo/wd/client/WDScheme.java
index 7e21582..40caf0f 100644
--- a/src/main/java/net/montoyo/wd/client/WDScheme.java
+++ b/src/main/java/net/montoyo/wd/client/WDScheme.java
@@ -1,149 +1,196 @@
-///*
-// * Copyright (C) 2018 BARBOTIN Nicolas
-// */
-//
-//package net.montoyo.wd.client;
-//
-//import net.montoyo.mcef.api.IScheme;
-//import net.montoyo.mcef.api.ISchemeResponseData;
-//import net.montoyo.mcef.api.ISchemeResponseHeaders;
-//import net.montoyo.mcef.api.SchemePreResponse;
-//import net.montoyo.wd.WebDisplays;
-//import net.montoyo.wd.miniserv.Constants;
-//import net.montoyo.wd.miniserv.client.Client;
-//import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
-//import net.montoyo.wd.utilities.Log;
-//import net.montoyo.wd.utilities.Util;
-//
-//import java.io.UnsupportedEncodingException;
-//import java.net.URLDecoder;
-//import java.util.UUID;
-//
-//public class WDScheme implements IScheme {
-//
-// private static final String ERROR_PAGE = "
%d %s
Miniserv powered by WebDisplays";
-// private ClientTaskGetFile task;
-// private boolean isErrorPage;
-//
-// @Override
-// public SchemePreResponse processRequest(String url) {
-// url = url.substring("wd://".length());
-//
-// int pos = url.indexOf('/');
-// if(pos < 0)
-// return SchemePreResponse.NOT_HANDLED;
-//
-// String uuidStr = url.substring(0, pos);
-// String fileStr = url.substring(pos + 1);
-//
-// try {
-// fileStr = URLDecoder.decode(fileStr, "UTF-8");
-// } catch(UnsupportedEncodingException ex) {
-// Log.warningEx("UTF-8 isn't supported... yeah... and I'm a billionaire...", ex);
-// }
-//
-// if(uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr))
-// return SchemePreResponse.NOT_HANDLED;
-//
-// UUID uuid;
-// try {
-// uuid = UUID.fromString(uuidStr);
-// } catch(IllegalArgumentException ex) {
-// return SchemePreResponse.NOT_HANDLED; //Invalid UUID
-// }
-//
-// task = new ClientTaskGetFile(uuid, fileStr);
-// return Client.getInstance().addTask(task) ? SchemePreResponse.HANDLED_CONTINUE : SchemePreResponse.NOT_HANDLED;
-// }
-//
-// @Override
-// public void getResponseHeaders(ISchemeResponseHeaders resp) {
-// Log.info("Waiting for response...");
-// int status = task.waitForResponse();
-// Log.info("Got response %d", status);
-//
-// if(status == 0) {
-// //OK
-// int extPos = task.getFileName().lastIndexOf('.');
-// if(extPos >= 0) {
-// String mime = ((ClientProxy) WebDisplays.PROXY).getMCEF().mimeTypeFromExtension(task.getFileName().substring(extPos + 1));
-//
-// if(mime != null)
-// resp.setMimeType(mime);
-// }
-//
-// resp.setStatus(200);
-// resp.setStatusText("OK");
-// resp.setResponseLength(-1);
-// return;
-// }
-//
-// int errCode;
-// String errStr;
-//
-// if(status == Constants.GETF_STATUS_NOT_FOUND) {
-// errCode = 404;
-// errStr = "Not Found";
-// } else {
-// errCode = 500;
-// errStr = "Internal Server Error";
-// }
-//
-// resp.setStatus(errCode);
-// resp.setStatusText(errStr);
-//
-// try {
-// dataToWrite = String.format(ERROR_PAGE, errCode, errStr).getBytes("UTF-8");
-// dataOffset = 0;
-// amountToWrite = dataToWrite.length;
-// isErrorPage = true;
-// resp.setResponseLength(amountToWrite);
-// } catch(UnsupportedEncodingException ex) {
-// resp.setResponseLength(0);
-// }
-// }
-//
-// private byte[] dataToWrite;
-// private int dataOffset;
-// private int amountToWrite;
-//
-// @Override
-// public boolean readResponse(ISchemeResponseData data) {
-// if(dataToWrite == null) {
-// if(isErrorPage) {
+/*
+ * Copyright (C) 2018 BARBOTIN Nicolas
+ */
+
+package net.montoyo.wd.client;
+
+import net.montoyo.wd.miniserv.Constants;
+import net.montoyo.wd.miniserv.client.Client;
+import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
+import net.montoyo.wd.utilities.Log;
+import net.montoyo.wd.utilities.Util;
+import org.cef.callback.CefCallback;
+import org.cef.handler.CefResourceHandler;
+import org.cef.misc.IntRef;
+import org.cef.misc.StringRef;
+import org.cef.network.CefRequest;
+import org.cef.network.CefResponse;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.UUID;
+
+public class WDScheme implements CefResourceHandler {
+
+ private static final String ERROR_PAGE = "%d %s
Miniserv powered by WebDisplays";
+ private ClientTaskGetFile task;
+ private boolean isErrorPage;
+
+ String url;
+
+ public WDScheme(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public boolean processRequest(CefRequest cefRequest, CefCallback cefCallback) {
+ url = cefRequest.getURL();
+
+ int pos = url.indexOf('/');
+ if(pos < 0)
+ return false;
+
+ String uuidStr = url.substring(0, pos);
+ String fileStr = url.substring(pos + 1);
+
+ try {
+ fileStr = URLDecoder.decode(fileStr, "UTF-8");
+ } catch(UnsupportedEncodingException ex) {
+ Log.warningEx("UTF-8 isn't supported... yeah... and I'm a billionaire...", ex);
+ }
+
+ if(uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr))
+ return false;
+
+ UUID uuid;
+ try {
+ uuid = UUID.fromString(uuidStr);
+ } catch(IllegalArgumentException ex) {
+ return false; //Invalid UUID
+ }
+
+ task = new ClientTaskGetFile(uuid, fileStr);
+ return Client.getInstance().addTask(task) ? true : false;
+ }
+
+ @Override
+ public void getResponseHeaders(CefResponse cefResponse, IntRef intRef, StringRef stringRef) {
+ Log.info("Waiting for response...");
+ int status = task.waitForResponse();
+ Log.info("Got response %d", status);
+
+ if(status == 0) {
+ //OK
+ int extPos = task.getFileName().lastIndexOf('.');
+ if(extPos >= 0) {
+ String mime = mapMime(task.getFileName().substring(extPos + 1));
+
+ if(mime != null)
+ cefResponse.setMimeType(mime);
+ }
+
+ cefResponse.setStatus(200);
+ cefResponse.setStatusText("OK");
+ cefResponse.setHeaderByName("content-length", "" + -1, true);
+ return;
+ }
+
+ int errCode;
+ String errStr;
+
+ if(status == Constants.GETF_STATUS_NOT_FOUND) {
+ errCode = 404;
+ errStr = "Not Found";
+ } else {
+ errCode = 500;
+ errStr = "Internal Server Error";
+ }
+
+ cefResponse.setStatus(errCode);
+ cefResponse.setStatusText(errStr);
+
+ try {
+ dataToWrite = String.format(ERROR_PAGE, errCode, errStr).getBytes("UTF-8");
+ dataOffset = 0;
+ amountToWrite = dataToWrite.length;
+ isErrorPage = true;
+ cefResponse.setHeaderByName("content-length", "" + amountToWrite, true);
+ } catch(UnsupportedEncodingException ex) {
+ cefResponse.setHeaderByName("content-length", "" + 0, true);
+// cefResponse.setResponseLength(0);
+ }
+ }
+
+ private byte[] dataToWrite;
+ private int dataOffset;
+ private int amountToWrite;
+
+ @Override
+ public boolean readResponse(byte[] bytes, int i, IntRef intRef, CefCallback cefCallback) {
+ if(dataToWrite == null) {
+ if(isErrorPage) {
// data.setAmountRead(0);
-// return false;
-// }
-//
-// dataToWrite = task.waitForData();
-// dataOffset = 3; //packet ID + size
-// amountToWrite = task.getDataLength();
-//
-// if(amountToWrite <= 0) {
-// dataToWrite = null;
+ return false;
+ }
+
+ dataToWrite = task.waitForData();
+ dataOffset = 3; //packet ID + size
+ amountToWrite = task.getDataLength();
+
+ if(amountToWrite <= 0) {
+ dataToWrite = null;
// data.setAmountRead(0);
-// return false;
-// }
-// }
-//
+ return false;
+ }
+ }
+
// int toWrite = data.getBytesToRead();
// if(toWrite > amountToWrite)
// toWrite = amountToWrite;
-//
+
// System.arraycopy(dataToWrite, dataOffset, data.getDataArray(), 0, toWrite);
// data.setAmountRead(toWrite);
-//
+
// dataOffset += toWrite;
// amountToWrite -= toWrite;
-//
-// if(amountToWrite <= 0) {
-// if(!isErrorPage)
-// task.nextData();
-//
-// dataToWrite = null;
-// }
-//
-// return true;
-// }
-//
-//}
+
+ if(amountToWrite <= 0) {
+ if(!isErrorPage)
+ task.nextData();
+
+ dataToWrite = null;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void cancel() {
+ }
+
+ public static String mapMime(String ext) {
+ switch (ext) {
+ case "htm":
+ case "html":
+ return "text/html";
+
+ case "css":
+ return "text/css";
+
+ case "js":
+ return "text/javascript";
+
+ case "png":
+ return "image/png";
+
+ case "jpg":
+ case "jpeg":
+ return "image/jpeg";
+
+ case "gif":
+ return "image/gif";
+
+ case "svg":
+ return "image/svg+xml";
+
+ case "xml":
+ return "text/xml";
+
+ case "txt":
+ return "text/plain";
+
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/net/montoyo/wd/client/gui/GuiServer.java b/src/main/java/net/montoyo/wd/client/gui/GuiServer.java
index 6f6c23d..4a2e71c 100644
--- a/src/main/java/net/montoyo/wd/client/gui/GuiServer.java
+++ b/src/main/java/net/montoyo/wd/client/gui/GuiServer.java
@@ -96,8 +96,8 @@ public class GuiServer extends WDScreen {
}
@Override
- public void render(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
- super.render(poseStack, mouseX, mouseY, ptt);
+ public void render(GuiGraphics graphics, int mouseX, int mouseY, float ptt) {
+ super.render(graphics, mouseX, mouseY, ptt);
int x = (width - 256) / 2;
int y = (height - 176) / 2;
@@ -105,27 +105,27 @@ public class GuiServer extends WDScreen {
// RenderSystem.enableTexture();
RenderSystem.setShaderTexture(0, BG_IMAGE);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
-// blit(poseStack, x, y, 0, 0, 256, 176);
-
+ graphics.blit(BG_IMAGE, x, y, 0, 0, 256, 256);
+
x += 18;
y += 18;
for (int i = 0; i < lines.size(); i++) {
if (selectedLine == i) {
drawWhiteQuad(x - 1, y - 2, font.width(lines.get(i)) + 1, 12);
- poseStack.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFF129700, false);
+ graphics.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFF129700, false);
} else
- poseStack.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFFFFFFFF, false);
+ graphics.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFFFFFFFF, false);
y += 12;
}
if (!promptLocked) {
if (queue.isEmpty()) {
- x = poseStack.drawString(Minecraft.getInstance().font, userPrompt, x, y, 0xFFFFFFFF, false);
- x = poseStack.drawString(Minecraft.getInstance().font, prompt, x, y, 0xFFFFFFFF, false);
+ x = graphics.drawString(Minecraft.getInstance().font, userPrompt, x, y, 0xFFFFFFFF, false);
+ x = graphics.drawString(Minecraft.getInstance().font, prompt, x, y, 0xFFFFFFFF, false);
} else {
- x = poseStack.drawString(Minecraft.getInstance().font, tr("press_for_more"), x, y, 0xFFFFFFFF, false);
+ x = graphics.drawString(Minecraft.getInstance().font, tr("press_for_more"), x, y, 0xFFFFFFFF, false);
}
}
@@ -137,7 +137,7 @@ public class GuiServer extends WDScreen {
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.setShaderTexture(0, FG_IMAGE);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
-// blit(poseStack,(width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176);
+// blit(graphics,(width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176);
}
private void drawWhiteQuad(int x, int y, int w, int h) {
diff --git a/src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java b/src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
index f06fc89..8ff2535 100644
--- a/src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
+++ b/src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
@@ -100,15 +100,15 @@ public class RenderRecipe extends Screen {
int x = this.x + 30 + sx * 18;
int y = this.y + 17 + sy * 18;
-// renderItem.renderAndDecorateItem(minecraft.player, is, x, y, 0);
-// renderItem.renderGuiItemDecorations(font, is, x, y, null);
+ context.renderItem(is, x, y);
+ context.renderItemDecorations(font, is, x, y);
}
}
}
if(recipeResult != null) {
-// renderItem.renderAndDecorateItem(minecraft.player, recipeResult, x + 124, y + 35, 0);
-// renderItem.renderGuiItemDecorations(font, recipeResult, x + 124, y + 35, null);
+ context.renderItem(recipeResult, x, y);
+ context.renderItemDecorations(font, recipeResult, x, y);
}
// GlStateManager.enableLighting();
diff --git a/src/main/java/net/montoyo/wd/client/gui/WDScreen.java b/src/main/java/net/montoyo/wd/client/gui/WDScreen.java
index 7c6842a..1a1740e 100644
--- a/src/main/java/net/montoyo/wd/client/gui/WDScreen.java
+++ b/src/main/java/net/montoyo/wd/client/gui/WDScreen.java
@@ -7,6 +7,7 @@ package net.montoyo.wd.client.gui;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
@@ -116,6 +117,8 @@ public abstract class WDScreen extends Screen {
if(defaultBackground)
renderBackground(poseStack);
+ RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
+
for(Control ctrl: controls)
ctrl.draw(poseStack, mouseX, mouseY, ptt);
@@ -137,9 +140,20 @@ public abstract class WDScreen extends Screen {
public boolean mouseClicked(double mouseX, double mouseY, int button) {
boolean clicked = false;
+ Control clickedEl = null;
for(Control ctrl: controls) {
clicked = ctrl.mouseClicked(mouseX, mouseY, button);
- if (clicked) break; // don't assume the compiler will optimize stuff
+ if (clicked) {
+ clickedEl = ctrl;
+ break; // don't assume the compiler will optimize stuff
+ }
+ }
+
+ if (clicked) {
+ for (Control control : controls) {
+ if (control != clickedEl)
+ control.unfocus();
+ }
}
return clicked;
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java b/src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
index 98aefc1..0d14ca1 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
@@ -9,6 +9,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvents;
@@ -81,12 +82,11 @@ public class CheckBox extends BasicControl {
if(visible) {
// GlStateManager.disableAlpha();
poseStack.pose().pushPose();
- RenderSystem.setShaderTexture(2, checked ? texChecked : texUnchecked);
- RenderSystem.bindTexture(2);
RenderSystem.enableBlend();
- fillTexturedRect(poseStack.pose(), x, y, WIDTH, HEIGHT, 0.0, 0.0, 1.0, 1.0);
+ poseStack.blit(
+ checked ? texChecked : texUnchecked, x, y, 0, 0, 0, WIDTH, HEIGHT, WIDTH, HEIGHT
+ );
RenderSystem.disableBlend();
- RenderSystem.bindTexture(-1);
poseStack.pose().popPose();
boolean inside = (!disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT);
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/Container.java b/src/main/java/net/montoyo/wd/client/gui/controls/Container.java
index 488f284..e6b33c7 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/Container.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/Container.java
@@ -189,4 +189,10 @@ public abstract class Container extends BasicControl {
return null;
}
+ @Override
+ public void unfocus() {
+ for (Control control : childs) {
+ control.unfocus();
+ }
+ }
}
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/Control.java b/src/main/java/net/montoyo/wd/client/gui/controls/Control.java
index 589a415..1d973a1 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/Control.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/Control.java
@@ -11,6 +11,10 @@ import com.mojang.blaze3d.vertex.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.renderer.GameRenderer;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
@@ -20,6 +24,9 @@ import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.utilities.Bounds;
import org.joml.Matrix4f;
+import java.util.Arrays;
+
+import static com.mojang.math.Axis.XP;
import static org.lwjgl.opengl.GL11.*;
@OnlyIn(Dist.CLIENT)
@@ -74,6 +81,9 @@ public abstract class Control {
return false;
}
+ public void unfocus() {
+ }
+
public boolean mouseReleased(double mouseX, double mouseY, int state) {
return false;
}
@@ -109,7 +119,7 @@ public abstract class Control {
public abstract int getHeight();
public abstract void setPos(int x, int y);
- public void fillRect(int x, double y, int w, int h, int color) {
+ public void fillRect(MultiBufferSource.BufferSource source, int x, double y, int w, int h, int color) {
double x1 = (double) x;
double y1 = (double) y;
double x2 = (double) (x + w);
@@ -119,34 +129,38 @@ public abstract class Control {
int g = (color >> 8 ) & 0xFF;
int b = color & 0xFF;
- RenderSystem.setShaderColor(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
+ float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
+ RenderSystem.setShaderColor(1, 1, 1, 1f);
// RenderSystem.disableTexture();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
- vBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION);
- vBuffer.vertex(x1, y2, 0.0).endVertex();
- vBuffer.vertex(x2, y2, 0.0).endVertex();
- vBuffer.vertex(x2, y1, 0.0).endVertex();
- vBuffer.vertex(x1, y1, 0.0).endVertex();
- tessellator.end();
+ VertexConsumer consumer = source.getBuffer(RenderType.gui());
+ consumer.vertex(x1, y2, 0.0).color(r, g, b, a).endVertex();
+ consumer.vertex(x2, y2, 0.0).color(r, g, b, a).endVertex();
+ consumer.vertex(x2, y1, 0.0).color(r, g, b, a).endVertex();
+ consumer.vertex(x1, y1, 0.0).color(r, g, b, a).endVertex();
+
+ RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
RenderSystem.disableBlend();
// RenderSystem.enableTexture();
}
public void fillTexturedRect(PoseStack poseStack, int x, int y, int w, int h, double u1, double v1, double u2, double v2) {
- double x1 = (double) x;
- double y1 = (double) y;
- double x2 = (double) (x + w);
- double y2 = (double) (y + h);
+ float x1 = x;
+ float y1 = y;
+ float x2 = (x + w);
+ float y2 = (y + h);
- vBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
- vBuffer.vertex(x1, y2, 0.0).uv((float) u1, (float) v2).color(255, 255, 255, 255).endVertex();
- vBuffer.vertex(x2, y2, 0.0).uv((float) u2, (float) v2).color(255, 255, 255, 255).endVertex();
- vBuffer.vertex(x2, y1, 0.0).uv((float) u2, (float) v1).color(255, 255, 255, 255).endVertex();
- vBuffer.vertex(x1, y1, 0.0).uv((float) u1, (float) v1).color(255, 255, 255, 255).endVertex();
- tessellator.end();
+ RenderSystem.setShader(GameRenderer::getPositionColorTexShader);
+ Matrix4f p = poseStack.last().pose();
+ vBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX);
+ vBuffer.vertex(p, x1, y2, 0.0f).color(255, 255, 255, 255).uv((float) u1, (float) v2).endVertex();
+ vBuffer.vertex(p, x2, y2, 0.0f).color(255, 255, 255, 255).uv((float) u2, (float) v2).endVertex();
+ vBuffer.vertex(p, x2, y1, 0.0f).color(255, 255, 255, 255).uv((float) u2, (float) v1).endVertex();
+ vBuffer.vertex(p, x1, y1, 0.0f).color(255, 255, 255, 255).uv((float) u1, (float) v1).endVertex();
+ BufferUploader.drawWithShader(vBuffer.end());
}
public static void blend(boolean enable) {
@@ -178,6 +192,7 @@ public abstract class Control {
int g = (color >> 8 ) & 0xFF;
int b = color & 0xFF;
+ float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
RenderSystem.setShaderColor(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
// RenderSystem.enableTexture();
RenderSystem.enableBlend();
@@ -209,13 +224,15 @@ public abstract class Control {
vBuffer.vertex(x2 - sz, y1, 0.0).endVertex();
tessellator.end();
+ RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
+
RenderSystem.disableBlend();
// RenderSystem.enableTexture();
}
public GuiGraphics beginFramebuffer(RenderTarget fbo, float vpW, float vpH) {
GuiGraphics tmpGraphics = new GuiGraphics(Minecraft.getInstance(), Minecraft.getInstance().renderBuffers().bufferSource());
-
+
fbo.bindWrite(true);
RenderSystem.backupProjectionMatrix();
@@ -226,7 +243,10 @@ public abstract class Control {
PoseStack poseStack = tmpGraphics.pose();
poseStack.pushPose();
poseStack.setIdentity();
-// poseStack.mulPose(Vector3f.XP.rotationDegrees(180.0f));
+ poseStack.mulPose(XP.rotationDegrees(180.0f));
+ RenderSystem.getModelViewStack().pushPose();
+ RenderSystem.getModelViewStack().last().pose().set(poseStack.last().pose());
+ RenderSystem.getModelViewStack().last().normal().set(poseStack.last().normal());
RenderSystem.applyModelViewMatrix();
if(!fbo.useDepth)
@@ -243,6 +263,7 @@ public abstract class Control {
RenderSystem.colorMask(true, true, true, true);
RenderSystem.restoreProjectionMatrix();
poseStack.pose().popPose();
+ RenderSystem.getModelViewStack().popPose();
RenderSystem.applyModelViewMatrix();
fbo.unbindWrite();
mc.getMainRenderTarget().bindWrite(true);
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/ControlGroup.java b/src/main/java/net/montoyo/wd/client/gui/controls/ControlGroup.java
index e8425f2..ce32abf 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/ControlGroup.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/ControlGroup.java
@@ -15,6 +15,8 @@ import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.utilities.Bounds;
import org.lwjgl.opengl.GL11;
+import java.util.Arrays;
+
import static org.lwjgl.opengl.GL11.*;
public class ControlGroup extends Container {
@@ -102,17 +104,18 @@ public class ControlGroup extends Container {
if(visible) {
poseStack.pose().pushPose();
+ float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
RenderSystem.setShaderColor(0.5f, 0.5f, 0.5f, 1.f);
// RenderSystem.disableTexture();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
- double x1 = (double) x;
- double y1 = (double) y;
- double x2 = (double) (x + width);
- double y2 = (double) (y + height);
+ double x1 = x;
+ double y1 = y;
+ double x2 = (x + width);
+ double y2 = (y + height);
double bp = 4.0;
- double lw = (double) labelW;
+ double lw = labelW;
x1 += bp;
y1 += bp;
@@ -161,6 +164,8 @@ public class ControlGroup extends Container {
vBuffer.vertex(x2 - 1.0, y1, 0.0).endVertex();
tessellator.end();
+ RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
+
RenderSystem.disableBlend();
// RenderSystem.enableTexture();
poseStack.pose().popPose();
@@ -179,6 +184,13 @@ public class ControlGroup extends Container {
height = bounds.getHeight() + paddingY * 2;
}
+ @Override
+ public void unfocus() {
+ for (Control control : childs) {
+ control.unfocus();
+ }
+ }
+
@Override
public void load(JsonOWrapper json) {
super.load(json);
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/List.java b/src/main/java/net/montoyo/wd/client/gui/controls/List.java
index b707751..4d7a62f 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/List.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/List.java
@@ -10,12 +10,16 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.renderer.GameRenderer;
+import net.minecraft.client.renderer.MultiBufferSource;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
+import org.lwjgl.opengl.GL;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL20;
import java.util.ArrayList;
-import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
-import static org.lwjgl.opengl.GL11.GL_NEAREST;
+import static org.lwjgl.opengl.GL11.*;
public class List extends BasicControl {
@@ -97,19 +101,21 @@ public class List extends BasicControl {
if(fbo != null)
fbo.destroyBuffers();
- fbo = new TextureTarget(parent.screen2DisplayX(width), parent.screen2DisplayY(height), false, Minecraft.ON_OSX);
+ fbo = new TextureTarget(parent.screen2DisplayX(width), parent.screen2DisplayY(height), true, Minecraft.ON_OSX);
fbo.setFilterMode(GL_NEAREST);
- fbo.bindWrite(false);
+ fbo.bindWrite(true);
RenderSystem.clearColor(0.0f, 0.0f, 0.0f, 1.f); //Set alpha to 1
RenderSystem.clearDepth(GL_COLOR_BUFFER_BIT);
fbo.unbindWrite();
+ mc.getMainRenderTarget().bindWrite(true);
update = true;
}
- private void renderToFBO() {
- GuiGraphics poseStack = beginFramebuffer(fbo, width, height);
- poseStack.pose().pushPose();
- fillRect(0, 0, width, height, COLOR_BLACK);
+ private void renderToFBO(MultiBufferSource.BufferSource source) {
+ GuiGraphics graphics = beginFramebuffer(fbo, width, height);
+ GL11.glColorMask(true, true, true, true);
+ RenderSystem.applyModelViewMatrix();
+ graphics.fill(0, 0, width, height, COLOR_BLACK);
RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
int offset = 4 - getYOffset();
@@ -121,13 +127,13 @@ public class List extends BasicControl {
break;
int color = (i == selected) ? selColor : COLOR_WHITE;
- poseStack.drawString(font, content.get(i).text, 4, i * 12 + offset, color);
+ graphics.drawString(font, content.get(i).text, 4, i * 12 + offset, color);
}
}
- drawBorder(poseStack, 0, 0, width, height, 0xFF808080);
- endFramebuffer(poseStack, fbo);
- poseStack.pose().popPose();
+ graphics.renderOutline(0, 0, width, height, 0xFF808080);
+ graphics.flush();
+ endFramebuffer(graphics, fbo);
}
@Override
@@ -312,19 +318,18 @@ public class List extends BasicControl {
}
@Override
- public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
+ public void draw(GuiGraphics graphics, int mouseX, int mouseY, float ptt) {
if(visible) {
if(update) {
- renderToFBO();
+ renderToFBO(graphics.bufferSource());
update = false;
}
- fbo.bindRead(); //TODO: Make sure is right
+ RenderSystem.setShaderTexture(0, fbo.getColorTextureId());
RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
- fillTexturedRect(poseStack.pose(), x, y, width, height, 0.0, 1.0, 1.0, 0.0);
- fbo.unbindRead();
+ fillTexturedRect(graphics.pose(), x, y, width, height, 0.0, 1.0, 1.0, 0.0);
- fillRect(x + width - 5, y + 1 + scrollPos, 4, scrollSize, (scrolling || isInScrollbar(mouseX, mouseY)) ? 0xFF202020 : 0xFF404040);
+ fillRect(graphics.bufferSource(), x + width - 5, y + 1 + scrollPos, 4, scrollSize, (scrolling || isInScrollbar(mouseX, mouseY)) ? 0xFF202020 : 0xFF404040);
}
}
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/TextField.java b/src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
index dc7d79a..7b90155 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
@@ -99,15 +99,18 @@ public class TextField extends Control {
public TextField() {
field = new EditBox(font, 1, 1, 198, 20, Component.nullToEmpty(""));
+ setFocused(false);
}
public TextField(int x, int y, int width, int height) {
field = new EditBox(font, x + 1, y + 1, width - 2, height - 2, Component.nullToEmpty(""));
+ setFocused(false);
}
public TextField(int x, int y, int width, int height, String text) {
field = new EditBox(font, x + 1, y + 1, width - 2, height - 2, Component.nullToEmpty(""));
field.setValue(text);
+ setFocused(false);
}
// TODO: make this public static in CefBrowserOSR
@@ -166,11 +169,18 @@ public class TextField extends Control {
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
- if (field.mouseClicked(mouseX, mouseY, mouseButton))
+ if (field.mouseClicked(mouseX, mouseY, mouseButton)) {
setFocused(true);
+ return true;
+ }
return false;
}
-
+
+ @Override
+ public void unfocus() {
+ setFocused(false);
+ }
+
@Override
public boolean mouseReleased(double mouseX, double mouseY, int state) {
return field.mouseReleased(mouseX, mouseY, state);
@@ -262,7 +272,8 @@ public class TextField extends Control {
public void setDisabled(boolean en) {
enabled = !en;
- field.setFocused(enabled);
+ if (!en)
+ field.setFocused(false);
}
public boolean isDisabled() {
@@ -270,7 +281,6 @@ public class TextField extends Control {
}
public void enable() {
- field.setFocused(true);
enabled = true;
}
@@ -357,7 +367,7 @@ public class TextField extends Control {
field.setTextColor(textColor);
field.setTextColorUneditable(disabledColor);
-// field.setFocus(enabled);
+ setFocused(false);
}
}
diff --git a/src/main/java/net/montoyo/wd/client/gui/controls/UpgradeGroup.java b/src/main/java/net/montoyo/wd/client/gui/controls/UpgradeGroup.java
index 8f54a08..6780e13 100644
--- a/src/main/java/net/montoyo/wd/client/gui/controls/UpgradeGroup.java
+++ b/src/main/java/net/montoyo/wd/client/gui/controls/UpgradeGroup.java
@@ -7,6 +7,7 @@ package net.montoyo.wd.client.gui.controls;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.world.item.ItemStack;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
@@ -33,10 +34,10 @@ public class UpgradeGroup extends BasicControl {
for(ItemStack is: upgrades) {
if(is == overStack && !disabled)
- fillRect(x, y, 16, 16, 0x80FF0000);
+ fillRect(poseStack.bufferSource(), x, y, 16, 16, 0x80FF0000);
-// renderItem.renderAndDecorateItem(mc.player, is, x, y, 0);
-// renderItem.renderAndDecorateItem(is, font.lineHeight, x, y); //TODO is lineHeight right?
+ poseStack.renderItem(is, x, y);
+ poseStack.renderItemDecorations(font, is, x, y);
x += 18;
}
}
diff --git a/src/main/java/net/montoyo/wd/controls/ScreenControlRegistry.java b/src/main/java/net/montoyo/wd/controls/ScreenControlRegistry.java
index 477baf3..3d85d8e 100644
--- a/src/main/java/net/montoyo/wd/controls/ScreenControlRegistry.java
+++ b/src/main/java/net/montoyo/wd/controls/ScreenControlRegistry.java
@@ -63,6 +63,7 @@ public class ScreenControlRegistry {
register(ManageRightsAndUpdgradesControl.id, new ScreenControlType<>(ManageRightsAndUpdgradesControl.class, ManageRightsAndUpdgradesControl::new));
register(ClickControl.id, new ScreenControlType<>(ClickControl.class, ClickControl::new));
register(OwnerControl.id, new ScreenControlType<>(OwnerControl.class, OwnerControl::new));
+ register(TurnOffControl.id, new ScreenControlType<>(TurnOffControl.class, (buf) -> TurnOffControl.INSTANCE));
}
public static ScreenControl parse(FriendlyByteBuf buf) {
diff --git a/src/main/java/net/montoyo/wd/controls/builtin/TurnOffControl.java b/src/main/java/net/montoyo/wd/controls/builtin/TurnOffControl.java
new file mode 100644
index 0000000..13a5d13
--- /dev/null
+++ b/src/main/java/net/montoyo/wd/controls/builtin/TurnOffControl.java
@@ -0,0 +1,49 @@
+package net.montoyo.wd.controls.builtin;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
+import net.minecraftforge.network.NetworkEvent;
+import net.montoyo.wd.WebDisplays;
+import net.montoyo.wd.controls.ScreenControl;
+import net.montoyo.wd.core.MissingPermissionException;
+import net.montoyo.wd.entity.TileEntityScreen;
+import net.montoyo.wd.utilities.BlockSide;
+import net.montoyo.wd.utilities.NameUUIDPair;
+
+import java.util.function.Function;
+
+public class TurnOffControl extends ScreenControl {
+ public static final ResourceLocation id = new ResourceLocation("webdisplays:deactivate");
+
+ public static final TurnOffControl INSTANCE = new TurnOffControl();
+
+ public TurnOffControl() {
+ super(id);
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ }
+
+ @Override
+ public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function permissionChecker) throws MissingPermissionException {
+ throw new RuntimeException("Cannot handle deactivation packet from server");
+ }
+
+ @Override
+ @OnlyIn(Dist.CLIENT)
+ public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
+ if (side != null) {
+ WebDisplays.PROXY.closeGui(pos, side);
+ tes.disableScreen(side);
+ } else {
+ for (BlockSide value : BlockSide.values()) {
+ WebDisplays.PROXY.closeGui(pos, value);
+ tes.disableScreen(value);
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java b/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java
index 368a467..d155b33 100644
--- a/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java
+++ b/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java
@@ -6,6 +6,7 @@ package net.montoyo.wd.entity;
import com.cinemamod.mcef.MCEF;
import com.cinemamod.mcef.MCEFBrowser;
+import com.cinemamod.mcef.MCEFCursorChangeListener;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@@ -63,7 +64,7 @@ public class TileEntityScreen extends BlockEntity {
public TileEntityScreen(BlockPos arg2, BlockState arg3) {
super(TileInit.SCREEN_BLOCK_ENTITY.get(), arg2, arg3);
}
-
+
public static class Screen {
public BlockSide side;
@@ -233,7 +234,7 @@ public class TileEntityScreen extends BlockEntity {
else
mcefBrowser.resize(resolution.x, resolution.y);
- mcefBrowser.setCursorChangeListener((type) -> mouseType = type);
+ mcefBrowser.setCursorChangeListener((MCEFCursorChangeListener) (type) -> mouseType = type);
}
doTurnOnAnim = doAnim;
@@ -1139,7 +1140,27 @@ public class TileEntityScreen extends BlockEntity {
scr.upgrades.clear();
}
- WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), new S2CMessageCloseGui(getBlockPos()));
+ WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.turnOff(getBlockPos(), null));
+ }
+
+ public void disableScreen(BlockSide side) {
+ Screen remove = null;
+ for (Screen screen : screens) {
+ if (screen.side == side) {
+ remove = screen;
+ break;
+ }
+ }
+
+ if (remove == null) return;
+
+ if (level != null && !level.isClientSide) {
+ final Screen scrn = remove;
+ remove.upgrades.forEach(is -> dropUpgrade(is, scrn.side, null));
+ }
+
+ remove.upgrades.clear();
+ screens.remove(remove);
}
public void setOwner(BlockSide side, Player newOwner) {
diff --git a/src/main/java/net/montoyo/wd/net/client_bound/S2CMessageScreenUpdate.java b/src/main/java/net/montoyo/wd/net/client_bound/S2CMessageScreenUpdate.java
index 94cc668..05c7bf5 100644
--- a/src/main/java/net/montoyo/wd/net/client_bound/S2CMessageScreenUpdate.java
+++ b/src/main/java/net/montoyo/wd/net/client_bound/S2CMessageScreenUpdate.java
@@ -86,7 +86,13 @@ public class S2CMessageScreenUpdate extends Packet {
screenUpdate.control = new OwnerControl(owner);
return screenUpdate;
}
-
+
+ public static S2CMessageScreenUpdate turnOff(BlockPos blockPos, BlockSide side) {
+ S2CMessageScreenUpdate screenUpdate = new S2CMessageScreenUpdate(blockPos, side);
+ screenUpdate.control = TurnOffControl.INSTANCE;
+ return screenUpdate;
+ }
+
@Override
public void write(FriendlyByteBuf buf) {
buf.writeBlockPos(pos);