large reworks of network code, various fixes

This commit is contained in:
GiantLuigi4 2023-03-14 13:00:34 -04:00
parent 3c141d9e1b
commit bc16cf9769
37 changed files with 1190 additions and 677 deletions

View File

@ -80,7 +80,7 @@ dependencies {
implementation fg.deobf("curse.maven:SU-370704:4410614")
implementation fg.deobf("curse.maven:spark-361579:4381167")
implementation fg.deobf("curse.maven:vivecraft-667903:4409427")
compileOnly fg.deobf("curse.maven:vivecraft-667903:4409427")
}
sourceSets {

View File

@ -41,6 +41,7 @@ import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.montoyo.wd.config.ModConfig;
import net.montoyo.wd.controls.ScreenControlRegistry;
import net.montoyo.wd.core.*;
import net.montoyo.wd.init.BlockInit;
import net.montoyo.wd.init.ItemInit;
@ -185,6 +186,10 @@ public class WebDisplays {
t.printStackTrace();
}
} */
if (!FMLEnvironment.production) {
ScreenControlRegistry.init();
}
}
@SubscribeEvent

View File

@ -194,13 +194,18 @@ public class BlockScreen extends BaseEntityBlock {
return InteractionResult.SUCCESS;
}
} else {
if ((scr.rightsFor(player) & ScreenRights.CLICK) == 0) {
if ((scr.rightsFor(player) & ScreenRights.INTERACT) == 0) {
Util.toast(player, "restrictions");
return InteractionResult.SUCCESS;
}
Vector2i tmp = new Vector2i();
if (hit2pixels(side, hit.getBlockPos(), pos, scr, (float) hit.getLocation().x, (float) hit.getLocation().y, (float) hit.getLocation().z, tmp))
float hitX = ((float) hit.getLocation().x) - (float) te.getBlockPos().getX();
float hitY = ((float) hit.getLocation().y) - (float) te.getBlockPos().getY();
float hitZ = ((float) hit.getLocation().z) - (float) te.getBlockPos().getZ();
if (hit2pixels(side, hit.getBlockPos(), new Vector3i(hit.getBlockPos()), scr, hitX, hitY, hitZ, tmp))
te.click(side, tmp);
return InteractionResult.SUCCESS;
}
@ -258,67 +263,64 @@ public class BlockScreen extends BaseEntityBlock {
}
}
}
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)
hitX -= 1.f;
if (side.right.z < 0 || side == BlockSide.TOP || side == BlockSide.BOTTOM)
hitZ -= 1.f;
Vector3f rel = new Vector3f(hitX, hitY, hitZ);
rel.sub(pos.toBlock().getX(), pos.toBlock().getY(), pos.toBlock().getZ());
float cx = Math.abs(rel.dot(side.right.toFloat()) - 2.f / 16.f);
float cy = Math.abs(rel.dot(side.up.toFloat()) - 2.f / 16.f);
float sw = ((float) scr.size.x) - 4.f / 16.f;
float sh = ((float) scr.size.y) - 4.f / 16.f;
cx /= sw;
cy /= sh;
cx = cx - 0.05f;
cy = cy - 0.05f;
if (cx >= 0 && cx <= 1 && cy >= 0 && cy <= 1) {
if (side != BlockSide.BOTTOM)
cy = 1.f - cy;
switch (scr.rotation) {
case ROT_90:
cy = 1.0f - cy;
break;
case ROT_180:
cx = 1.0f - cx;
cy = 1.0f - cy;
break;
case ROT_270:
cx = 1.0f - cx;
break;
default:
break;
}
cx *= (float) scr.resolution.x;
cy *= (float) scr.resolution.y;
if (scr.rotation.isVertical) {
dst.x = (int) cy;
dst.y = (int) cx;
} else {
dst.x = (int) cx;
dst.y = (int) cy;
}
return true;
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)
hitX -= 1.f;
if(side.right.z < 0 || side == BlockSide.TOP || side == BlockSide.BOTTOM)
hitZ -= 1.f;
Vector3f rel = new Vector3f(bpos.getX(), bpos.getY(), bpos.getZ());
rel.sub((float) pos.x, (float) pos.y, (float) pos.z);
rel.add(hitX, hitY, hitZ);
float cx = rel.dot(side.right.toFloat()) - 2.f / 16.f;
float cy = rel.dot(side.up.toFloat()) - 2.f / 16.f;
float sw = ((float) scr.size.x) - 4.f / 16.f;
float sh = ((float) scr.size.y) - 4.f / 16.f;
cx /= sw;
cy /= sh;
if(cx >= 0.f && cx <= 1.0 && cy >= 0.f && cy <= 1.f) {
if(side != BlockSide.BOTTOM)
cy = 1.f - cy;
switch(scr.rotation) {
case ROT_90:
cy = 1.0f - cy;
break;
case ROT_180:
cx = 1.0f - cx;
cy = 1.0f - cy;
break;
case ROT_270:
cx = 1.0f - cx;
break;
default:
break;
}
return false;
cx *= (float) scr.resolution.x;
cy *= (float) scr.resolution.y;
if(scr.rotation.isVertical) {
dst.x = (int) cy;
dst.y = (int) cx;
} else {
dst.x = (int) cx;
dst.y = (int) cy;
}
return true;
}
return false;
}
@org.jetbrains.annotations.Nullable
@Override

View File

@ -630,8 +630,8 @@ public class ClientProxy extends SharedProxy implements IDisplayHandler, IJSQuer
float hitY = ((float) result.getLocation().y) - (float) bpos.getY();
float hitZ = ((float) result.getLocation().z) - (float) bpos.getZ();
Vector2i tmp = new Vector2i();
if(BlockScreen.hit2pixels(side, bpos, pos, scr, hitX, hitY, hitZ, tmp)) {
if(BlockScreen.hit2pixels(side, bpos, new Vector3i(result.getBlockPos()), scr, hitX, hitY, hitZ, tmp)) {
laserClick(te, side, scr, tmp);
}
}
@ -694,13 +694,13 @@ public class ClientProxy extends SharedProxy implements IDisplayHandler, IJSQuer
if(t - lastPointPacket >= 100) {
lastPointPacket = t;
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.vec2(tes, side, C2SMessageScreenCtrl.CTRL_LASER_MOVE, hit));
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserMove(tes, side, hit));
}
} else {
deselectScreen();
pointedScreen = tes;
pointedScreenSide = side;
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.vec2(tes, side, C2SMessageScreenCtrl.CTRL_LASER_DOWN, hit));
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserDown(tes, side, hit));
}
}
@ -802,6 +802,8 @@ public class ClientProxy extends SharedProxy implements IDisplayHandler, IJSQuer
@Override
public BlockGetter getWorld(NetworkEvent.Context context) {
return Minecraft.getInstance().level;
BlockGetter senderLevel = super.getWorld(context);
if (senderLevel == null) return Minecraft.getInstance().level;
return senderLevel;
}
}

View File

@ -133,17 +133,17 @@ public class GuiScreenConfig extends WDScreen {
loadFrom(new ResourceLocation("webdisplays", "gui/screencfg.json"));
friendBoxes = new CheckBox[] { boxFResolution, boxFUpgrades, boxFOthers, boxFFriends, boxFClick, boxFSetUrl };
boxFResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
boxFResolution.setUserdata(ScreenRights.MODIFY_SCREEN);
boxFUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
boxFOthers.setUserdata(ScreenRights.MANAGE_OTHER_RIGHTS);
boxFFriends.setUserdata(ScreenRights.MANAGE_FRIEND_LIST);
boxFClick.setUserdata(ScreenRights.CLICK);
boxFClick.setUserdata(ScreenRights.INTERACT);
boxFSetUrl.setUserdata(ScreenRights.CHANGE_URL);
otherBoxes = new CheckBox[] { boxOResolution, boxOUpgrades, boxOClick, boxOSetUrl };
boxOResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
boxOResolution.setUserdata(ScreenRights.MODIFY_SCREEN);
boxOUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
boxOClick.setUserdata(ScreenRights.CLICK);
boxOClick.setUserdata(ScreenRights.INTERACT);
boxOSetUrl.setUserdata(ScreenRights.CHANGE_URL);
TileEntityScreen.Screen scr = tes.getScreen(side);
@ -201,7 +201,7 @@ public class GuiScreenConfig extends WDScreen {
throw new NumberFormatException(); //I'm lazy
if(x != scr.resolution.x || y != scr.resolution.y)
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.vec2(tes, side, C2SMessageScreenCtrl.CTRL_SET_RESOLUTION, new Vector2i(x, y)));
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.resolution(tes, side, new Vector2i(x, y)));
} catch(NumberFormatException ex) {
//Roll back
tfResX.setText("" + scr.resolution.x);
@ -455,7 +455,7 @@ public class GuiScreenConfig extends WDScreen {
flag = (myRights & ScreenRights.MANAGE_OTHER_RIGHTS) == 0;
grpOthers.setDisabled(flag);
flag = (myRights & ScreenRights.CHANGE_RESOLUTION) == 0;
flag = (myRights & ScreenRights.MODIFY_SCREEN) == 0;
tfResX.setDisabled(flag);
tfResY.setDisabled(flag);
btnChangeRot.setDisabled(flag);

View File

@ -18,116 +18,153 @@ import org.jetbrains.annotations.NotNull;
import static com.mojang.math.Vector3f.*;
public class ScreenRenderer implements BlockEntityRenderer<TileEntityScreen> {
public ScreenRenderer() {}
public static class ScreenRendererProvider implements BlockEntityRendererProvider<TileEntityScreen> {
@Override
public @NotNull BlockEntityRenderer<TileEntityScreen> create(@NotNull Context arg) {
return new ScreenRenderer();
}
}
private final Vector3f mid = new Vector3f();
private final Vector3i tmpi = new Vector3i();
private final Vector3f tmpf = new Vector3f();
@Override
public void render(TileEntityScreen te, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
if(!te.isLoaded())
return;
//Disable lighting
RenderSystem.enableTexture();
public ScreenRenderer() {
}
public static class ScreenRendererProvider implements BlockEntityRendererProvider<TileEntityScreen> {
@Override
public @NotNull BlockEntityRenderer<TileEntityScreen> create(@NotNull Context arg) {
return new ScreenRenderer();
}
}
private final Vector3f mid = new Vector3f();
private final Vector3i tmpi = new Vector3i();
private final Vector3f tmpf = new Vector3f();
@Override
public void render(TileEntityScreen te, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
if (!te.isLoaded())
return;
//Disable lighting
RenderSystem.enableTexture();
// RenderSystem.disableCull();
RenderSystem.disableBlend();
for(int i = 0; i < te.screenCount(); i++) {
TileEntityScreen.Screen scr = te.getScreen(i);
if(scr.browser == null) {
scr.createBrowser(true);
}
// TODO: manually backface cull the screens
tmpi.set(scr.side.right);
tmpi.mul(scr.size.x);
tmpi.addMul(scr.side.up, scr.size.y);
tmpf.set(tmpi);
mid.set(0.5, 0.5, 0.5);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.left);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.down);
mid.addMul(tmpf, 0.5f);
poseStack.pushPose();
poseStack.translate(mid.x, mid.y, mid.z);
switch(scr.side) {
case BOTTOM:
poseStack.mulPose(XP.rotation(90.f + 49.8f));
break;
case TOP:
poseStack.mulPose(XN.rotation(90.f + 49.8f));
break;
case NORTH:
poseStack.mulPose(YN.rotationDegrees(180.f));
break;
case SOUTH:
break;
case WEST:
poseStack.mulPose(YN.rotationDegrees(90.f));
break;
case EAST:
poseStack.mulPose(YP.rotationDegrees(90.f));
break;
}
if(scr.doTurnOnAnim) {
long lt = System.currentTimeMillis() - scr.turnOnTime;
float ft = ((float) lt) / 100.0f;
if(ft >= 1.0f) {
ft = 1.0f;
scr.doTurnOnAnim = false;
}
poseStack.scale(ft, ft, 1.0f);
}
if(!scr.rotation.isNull)
poseStack.mulPose(ZP.rotationDegrees(scr.rotation.angle));
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
if(scr.rotation.isVertical) {
float tmp = sw;
sw = sh;
sh = tmp;
}
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder builder = tesselator.getBuilder();
//TODO: don't use tesselator
RenderSystem.enableDepthTest();
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
RenderSystem._setShaderTexture(0, scr.browser.getTextureID());
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
builder.vertex(poseStack.last().pose(),-sw, -sh, 0.505f).uv(0.f, 1.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(), sw, -sh, 0.505f).uv(1.f, 1.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(), sw, sh, 0.505f).uv(1.f, 0.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(),-sw, sh, 0.505f).uv(0.f, 0.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
tesselator.end();//Minecraft does shit with mah texture otherwise...
RenderSystem.disableDepthTest();
poseStack.popPose();
}
RenderSystem.disableBlend();
for (int i = 0; i < te.screenCount(); i++) {
TileEntityScreen.Screen scr = te.getScreen(i);
if (scr.browser == null) {
scr.createBrowser(true);
}
// TODO: manually backface cull the screens
tmpi.set(scr.side.right);
tmpi.mul(scr.size.x);
tmpi.addMul(scr.side.up, scr.size.y);
tmpf.set(tmpi);
mid.set(0.5, 0.5, 0.5);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.left);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.down);
mid.addMul(tmpf, 0.5f);
poseStack.pushPose();
poseStack.translate(mid.x, mid.y, mid.z);
switch (scr.side) {
case BOTTOM:
poseStack.mulPose(XP.rotation(90.f + 49.8f));
break;
case TOP:
poseStack.mulPose(XN.rotation(90.f + 49.8f));
break;
case NORTH:
poseStack.mulPose(YN.rotationDegrees(180.f));
break;
case SOUTH:
break;
case WEST:
poseStack.mulPose(YN.rotationDegrees(90.f));
break;
case EAST:
poseStack.mulPose(YP.rotationDegrees(90.f));
break;
}
if (scr.doTurnOnAnim) {
long lt = System.currentTimeMillis() - scr.turnOnTime;
float ft = ((float) lt) / 100.0f;
if (ft >= 1.0f) {
ft = 1.0f;
scr.doTurnOnAnim = false;
}
poseStack.scale(ft, ft, 1.0f);
}
if (!scr.rotation.isNull)
poseStack.mulPose(ZP.rotationDegrees(scr.rotation.angle));
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
if (scr.rotation.isVertical) {
float tmp = sw;
sw = sh;
sh = tmp;
}
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder builder = tesselator.getBuilder();
//TODO: don't use tesselator
RenderSystem.enableDepthTest();
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
RenderSystem._setShaderTexture(0, scr.browser.getTextureID());
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
builder.vertex(poseStack.last().pose(), -sw, -sh, 0.505f).uv(0.f, 1.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(), sw, -sh, 0.505f).uv(1.f, 1.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(), sw, sh, 0.505f).uv(1.f, 0.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
builder.vertex(poseStack.last().pose(), -sw, sh, 0.505f).uv(0.f, 0.f).color(1.f, 1.f, 1.f, 1.f).endVertex();
tesselator.end();//Minecraft does shit with mah texture otherwise...
RenderSystem.disableDepthTest();
// TODO: it'd be neat to draw a mouse cursor on the screen
// // debug hit2pixels
// HitResult result = Minecraft.getInstance().hitResult;
// VertexConsumer consumer = bufferSource.getBuffer(RenderType.lines());
// poseStack.translate(-sw, -sh, 0);
// if (result instanceof BlockHitResult hit) {
// BlockPos bpos = hit.getBlockPos();
//
// Vector3i pos = new Vector3i(hit.getBlockPos());
// float hitX = ((float) result.getLocation().x) - (float) te.getBlockPos().getX();
// float hitY = ((float) result.getLocation().y) - (float) te.getBlockPos().getY();
// float hitZ = ((float) result.getLocation().z) - (float) te.getBlockPos().getZ();
// Vector2i tmp = new Vector2i();
//
// if (BlockScreen.hit2pixels(scr.side, bpos, pos, scr, hitX, hitY, hitZ, tmp)) {
// float x = tmp.x / (float) scr.resolution.x * scr.size.x;
// float y = tmp.y / (float) scr.resolution.y * scr.size.y;
// y = scr.size.y - y;
//
// x /= scr.size.x;
// y /= scr.size.y;
// x *= sw * 2;
// y *= sh * 2;
//
// LevelRenderer.renderLineBox(
// poseStack,
// consumer, new AABB(
// x - 0.01, y - 0.01, 0.5 - 0.01,
// x + 0.01, y + 0.01, 0.5 + 0.01
// ),
// 1f, 0, 0, 1f
// );
// }
// }
poseStack.popPose();
}
// //Bounding box debugging
@ -138,8 +175,8 @@ public class ScreenRenderer implements BlockEntityRenderer<TileEntityScreen> {
// te.getRenderBoundingBox(), 1, 1, 1, 1f
// );
// poseStack.popPose();
//Re-enable lighting
//Re-enable lighting
// RenderSystem.enableCull();
}
}
}

View File

@ -0,0 +1,38 @@
package net.montoyo.wd.controls;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import java.util.Objects;
import java.util.function.Function;
public abstract class ScreenControl {
private final ResourceLocation id;
public ScreenControl(ResourceLocation id) {
this.id = id;
}
public abstract void write(FriendlyByteBuf buf);
public abstract void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException;
@OnlyIn(Dist.CLIENT)
public abstract void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx);
public void checkPerms(int perms, Function<Integer, Boolean> checker, ServerPlayer player) throws MissingPermissionException {
if (!checker.apply(perms)) {
throw new MissingPermissionException(perms, Objects.requireNonNull(player));
}
}
public final ResourceLocation getId() {
return id;
}
}

View File

@ -0,0 +1,73 @@
package net.montoyo.wd.controls;
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.fml.loading.FMLEnvironment;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.controls.builtin.*;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import java.lang.reflect.Method;
import java.util.HashMap;
// TODO: enable deferred registry of these
public class ScreenControlRegistry {
private static final HashMap<ResourceLocation, ScreenControlType<?>> CONTROL_TYPES = new HashMap<>();
public static void register(ResourceLocation name, ScreenControlType<?> type) {
if (CONTROL_TYPES.containsKey(name)) {
Log.warning("ScreenControlRegistry#CONTROL_TYPES already contains an entry with name " + name);
throw new IllegalArgumentException("Cannot have two entries with the same name.");
}
CONTROL_TYPES.put(name, type);
// lil thing for sanity
// avoids the pain the dist cleaner causes, hopefully
if (!FMLEnvironment.production) {
if (FMLEnvironment.dist.isClient()) {
boolean shouldThrow = false;
try {
Method m = type.clazz.getMethod("handleClient", BlockPos.class, BlockSide.class, TileEntityScreen.class, NetworkEvent.Context.class);
OnlyIn onlyIn = m.getAnnotation(OnlyIn.class);
if (onlyIn == null) shouldThrow = true;
Dist d = onlyIn.value(); // idc if this throws, lol
if (d != Dist.CLIENT) shouldThrow = true;
} catch (Throwable ignored) {
}
if (shouldThrow) {
Log.warning("handleClient on ScreenControl classes MUST be marked with `@OnlyIn(Dist.CLIENT)`, but it is not on " + type.clazz);
throw new IllegalStateException(
"handleClient on ScreenControl classes MUST be marked with `@OnlyIn(Dist.CLIENT)`, but it is not on " + type.clazz
);
}
}
}
}
// if needed, the old code
// https://github.com/Mysticpasta1/webdisplays/blob/ff55cbf1b27773c15f44f17ad3364da3a16b6ed9/src/main/java/net/montoyo/wd/net/server/SMessageScreenCtrl.java
static {
register(SetURLControl.id, new ScreenControlType<>(SetURLControl.class, SetURLControl::new));
register(KeyTypedControl.id, new ScreenControlType<>(KeyTypedControl.class, KeyTypedControl::new));
register(AutoVolumeControl.id, new ScreenControlType<>(AutoVolumeControl.class, AutoVolumeControl::new));
register(JSRequestControl.id, new ScreenControlType<>(JSRequestControl.class, JSRequestControl::new));
register(LaserControl.id, new ScreenControlType<>(LaserControl.class, LaserControl::new));
register(ScreenModifyControl.id, new ScreenControlType<>(ScreenModifyControl.class, ScreenModifyControl::new));
register(ModifyFriendListControl.id, new ScreenControlType<>(ModifyFriendListControl.class, ModifyFriendListControl::new));
register(ManageRightsAndUpdgradesControl.id, new ScreenControlType<>(ManageRightsAndUpdgradesControl.class, ManageRightsAndUpdgradesControl::new));
}
public static ScreenControl parse(FriendlyByteBuf buf) {
return CONTROL_TYPES.get(new ResourceLocation(buf.readUtf()))
.deserializer.apply(buf);
}
public static void init() {
/* NO-OP: allows static init to run during mod init in dev env */
}
}

View File

@ -0,0 +1,15 @@
package net.montoyo.wd.controls;
import net.minecraft.network.FriendlyByteBuf;
import java.util.function.Function;
public class ScreenControlType<T extends ScreenControl> {
Class<T> clazz;
Function<FriendlyByteBuf, ScreenControl> deserializer;
public ScreenControlType(Class<T> clazz, Function<FriendlyByteBuf, ScreenControl> deserializer) {
this.clazz = clazz;
this.deserializer = deserializer;
}
}

View File

@ -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.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import java.util.function.Function;
public class AutoVolumeControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:auto_volume");
boolean autoVol;
public AutoVolumeControl(boolean autoVol) {
super(id);
this.autoVol = autoVol;
}
public AutoVolumeControl(FriendlyByteBuf buf) {
super(id);
autoVol = buf.readBoolean();
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeBoolean(autoVol);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
// I feel like there's probably a better permission category
checkPerms(ScreenRights.MANAGE_UPGRADES, permissionChecker, ctx.getSender());
tes.setAutoVolume(side, autoVol);
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
tes.setAutoVolume(side, autoVol);
}
}

View File

@ -0,0 +1,63 @@
package net.montoyo.wd.controls.builtin;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.controls.ScreenControl;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import java.util.function.Function;
public class JSRequestControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:js_req");
int reqId;
JSServerRequest reqType;
Object[] data;
public JSRequestControl(int reqId, JSServerRequest reqType, Object[] data) {
super(id);
this.reqId = reqId;
this.reqType = reqType;
this.data = data;
}
public JSRequestControl(FriendlyByteBuf buf) {
super(id);
reqId = buf.readInt();
reqType = JSServerRequest.fromID(buf.readByte());
if (reqType != null)
data = reqType.deserialize(buf);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(reqId);
buf.writeByte(reqType.ordinal());
if (!reqType.serialize(buf, data))
throw new RuntimeException("Could not serialize CTRL_JS_REQUEST " + reqType);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
ServerPlayer player = ctx.getSender();
if (reqType == null || data == null) Log.warning("Caught invalid JS request from player %s (UUID %s)", player.getName(), player.getGameProfile().getId().toString());
else tes.handleJSRequest(player, side, reqId, reqType, data);
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
throw new RuntimeException("TODO");
}
}

View File

@ -0,0 +1,52 @@
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.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import java.util.function.Function;
public class KeyTypedControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:type");
String text;
BlockPos soundPos;
public KeyTypedControl(String text, BlockPos soundPos) {
super(id);
this.text = text;
this.soundPos = soundPos;
}
public KeyTypedControl(FriendlyByteBuf buf) {
super(id);
text = buf.readUtf();
soundPos = buf.readBlockPos();
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeUtf(text);
buf.writeBlockPos(soundPos);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
checkPerms(ScreenRights.INTERACT, permissionChecker, ctx.getSender());
tes.type(side, text, soundPos);
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
tes.type(side, text, soundPos);
}
}

View File

@ -0,0 +1,64 @@
package net.montoyo.wd.controls.builtin;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkEvent;
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.Vector2i;
import java.util.function.Function;
public class LaserControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:laser");
public static enum ControlType {
MOVE, DOWN, UP
}
ControlType type;
Vector2i coord;
public LaserControl(ControlType type, Vector2i coord) {
super(id);
this.type = type;
this.coord = coord;
}
public LaserControl(FriendlyByteBuf buf) {
super(id);
type = ControlType.values()[buf.readByte()];
if (!type.equals(ControlType.UP))
coord = new Vector2i(buf);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeByte(type.ordinal());
if (coord != null) coord.writeTo(buf);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
// feel like this makes sense, but I wanna get opinions first
// checkPerms(ScreenRights.INTERACT, permissionChecker, ctx.getSender());
ServerPlayer sender = ctx.getSender();
switch (type) {
case UP -> tes.laserUp(side, sender);
case DOWN -> tes.laserDownMove(side, sender, coord, true);
case MOVE -> tes.laserDownMove(side, sender, coord, false);
}
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
throw new RuntimeException("TODO");
}
}

View File

@ -0,0 +1,97 @@
package net.montoyo.wd.controls.builtin;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import java.util.function.Function;
/**
* TODO: I'm considering merging this with {@link ModifyFriendListControl} to make ManageScreenControl
*/
@Deprecated
public class ManageRightsAndUpdgradesControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:mod_rights_upgrades");
public static enum ControlType {
RIGHTS, UPGRADES
}
ControlType type;
ItemStack toRemove;
private int friendRights;
private int otherRights;
public ManageRightsAndUpdgradesControl(ItemStack toRemove) {
super(id);
type = ControlType.UPGRADES;
this.toRemove = toRemove;
}
public ManageRightsAndUpdgradesControl(int friendRights, int otherRights) {
super(id);
this.friendRights = friendRights;
this.otherRights = otherRights;
}
public ManageRightsAndUpdgradesControl(FriendlyByteBuf buf) {
super(id);
type = ControlType.values()[buf.readByte()];
switch (type) {
case UPGRADES -> toRemove = buf.readItem();
case RIGHTS -> {
friendRights = buf.readInt();
otherRights = buf.readInt();
}
}
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeByte(type.ordinal());
switch (type) {
case UPGRADES -> buf.writeItem(toRemove);
case RIGHTS -> {
buf.writeInt(friendRights);
buf.writeInt(otherRights);
}
}
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
ServerPlayer player = ctx.getSender();
switch (type) {
case UPGRADES -> {
checkPerms(ScreenRights.MANAGE_UPGRADES, permissionChecker, ctx.getSender());
tes.removeUpgrade(side, toRemove, player);
}
case RIGHTS -> {
TileEntityScreen.Screen scr = tes.getScreen(side);
int fr = scr.owner.uuid.equals(player.getGameProfile().getId()) ? friendRights : scr.friendRights;
int or = (scr.rightsFor(player) & ScreenRights.MANAGE_OTHER_RIGHTS) == 0 ? scr.otherRights : otherRights;
if(scr.friendRights != fr || scr.otherRights != or)
tes.setRights(player, side, fr, or);
}
}
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
throw new RuntimeException("TODO");
}
}

View File

@ -0,0 +1,56 @@
package net.montoyo.wd.controls.builtin;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
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 ModifyFriendListControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:mod_friend_list");
boolean adding;
NameUUIDPair friend;
public ModifyFriendListControl(NameUUIDPair pair, boolean adding) {
super(id);
this.adding = adding;
this.friend = pair;
}
public ModifyFriendListControl(FriendlyByteBuf buf) {
super(id);
adding = buf.readBoolean();
friend = new NameUUIDPair(buf);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeBoolean(adding);
friend.writeTo(buf);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
ServerPlayer player = ctx.getSender();
checkPerms(ScreenRights.MANAGE_FRIEND_LIST, permissionChecker, ctx.getSender());
if (adding) tes.addFriend(player, side, friend);
else tes.removeFriend(player, side, friend);
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
throw new RuntimeException("TODO");
}
}

View File

@ -0,0 +1,71 @@
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.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Rotation;
import net.montoyo.wd.utilities.Vector2i;
import java.util.function.Function;
public class ScreenModifyControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:mod_screen");
public static enum ControlType {
RESOLUTION, ROTATION
}
ControlType type;
Vector2i res;
Rotation rotation;
public ScreenModifyControl(Vector2i res) {
super(id);
this.type = ControlType.RESOLUTION;
this.res = res;
}
public ScreenModifyControl(Rotation rotation) {
super(id);
this.type = ControlType.ROTATION;
this.rotation = rotation;
}
public ScreenModifyControl(FriendlyByteBuf buf) {
super(id);
type = ControlType.values()[buf.readByte()];
if (type.equals(ControlType.RESOLUTION))
res = new Vector2i(buf);
else rotation = Rotation.values()[buf.readByte()];
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeByte(type.ordinal());
if (res != null) res.writeTo(buf);
else if (rotation != null) buf.writeByte(rotation.ordinal());
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
checkPerms(ScreenRights.MODIFY_SCREEN, permissionChecker, ctx.getSender());
switch (type) {
case RESOLUTION -> tes.setResolution(side, res);
case ROTATION -> tes.setRotation(side, rotation);
}
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
throw new RuntimeException("TODO");
}
}

View File

@ -0,0 +1,63 @@
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.controls.ScreenControl;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Vector3i;
import java.util.function.Function;
public class SetURLControl extends ScreenControl {
public static final ResourceLocation id = new ResourceLocation("webdisplays:set_url");
String url;
Vector3i remoteLocation;
public SetURLControl(String url, Vector3i remoteLocation) {
super(id);
this.url = url;
this.remoteLocation = remoteLocation;
}
public SetURLControl(FriendlyByteBuf buf) {
super(id);
url = buf.readUtf();
if (buf.readBoolean()) remoteLocation = new Vector3i(buf);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeUtf(url);
buf.writeBoolean(remoteLocation != null);
if (remoteLocation != null) remoteLocation.writeTo(buf);
}
@Override
public void handleServer(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
// TODO: deal with remote
checkPerms(ScreenRights.CHANGE_URL, permissionChecker, ctx.getSender());
try {
tes.setScreenURL(side, url);
} catch (Throwable err) {
err.printStackTrace();
}
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleClient(BlockPos pos, BlockSide side, TileEntityScreen tes, NetworkEvent.Context ctx) {
try {
tes.setScreenURL(side, url);
} catch (Throwable err) {
err.printStackTrace();
}
}
}

View File

@ -7,14 +7,19 @@ package net.montoyo.wd.core;
public abstract class ScreenRights {
public static final int CHANGE_URL = 1; //Change URL AND run JavaScript
/** use {@link ScreenRights#INTERACT instead} */
@Deprecated(forRemoval = true)
public static final int CLICK = 2; //Click AND type
public static final int INTERACT = 2; //Click AND type
public static final int MANAGE_FRIEND_LIST = 4;
public static final int MANAGE_OTHER_RIGHTS = 8;
public static final int MANAGE_UPGRADES = 16; //Manage upgrades AND peripherals AND autoVolume
@Deprecated(forRemoval = true)
public static final int CHANGE_RESOLUTION = 32; //Change resolution AND rotation
public static final int MODIFY_SCREEN = 32; //Change resolution AND rotation
public static final int NONE = 0;
public static final int ALL = 0xFF;
public static final int DEFAULTS = CHANGE_URL | CLICK | MANAGE_UPGRADES | CHANGE_RESOLUTION;
public static final int DEFAULTS = CHANGE_URL | INTERACT | MANAGE_UPGRADES | MODIFY_SCREEN;
}

View File

@ -100,7 +100,7 @@ public class ScreenConfigData extends GuiData {
onlyUpdate = buf.readBoolean();
pos = BufferUtils.readVec3i(buf);
side = (BlockSide) BufferUtils.readEnum(buf, (v) -> BlockSide.values()[v], (byte) 1);
friends = BufferUtils.readArray(buf, () -> new NameUUIDPair(buf));
friends = BufferUtils.readArray(buf, new NameUUIDPair[0], () -> new NameUUIDPair(buf));
friendRights = buf.readInt();
otherRights = buf.readInt();
}

View File

@ -89,7 +89,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
switch(what) {
case "click":
case "type":
right = ScreenRights.CLICK;
right = ScreenRights.INTERACT;
break;
case "seturl":
@ -101,7 +101,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
case "setresolution":
case "setrotation":
right = ScreenRights.CHANGE_RESOLUTION;
right = ScreenRights.MODIFY_SCREEN;
break;
default:
@ -213,7 +213,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
else {
TileEntityScreen.Screen scrscr = scr.getScreen(screenSide);
if((scrscr.rightsFor(owner.uuid) & ScreenRights.CLICK) == 0)
if((scrscr.rightsFor(owner.uuid) & ScreenRights.INTERACT) == 0)
return err("restrictions");
else {
switch(scrscr.rotation) {
@ -249,7 +249,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CLICK) == 0)
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.INTERACT) == 0)
return err("restrictions");
else {
scr.type(screenSide, what, null);
@ -350,7 +350,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_RESOLUTION) == 0)
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.MODIFY_SCREEN) == 0)
return err("restrictions");
else {
scr.setResolution(screenSide, new Vector2i(rx, ry));
@ -373,7 +373,7 @@ public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_RESOLUTION) == 0)
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.MODIFY_SCREEN) == 0)
return err("restrictions");
else {
scr.setRotation(screenSide, Rotation.values()[rot]);

View File

@ -53,7 +53,7 @@ public class TileEntityKeyboard extends TileEntityPeripheralBase {
}
TileEntityScreen.Screen scr = tes.getScreen(screenSide);
if((scr.rightsFor(player) & ScreenRights.CLICK) == 0) {
if((scr.rightsFor(player) & ScreenRights.INTERACT) == 0) {
Util.toast(player, "restrictions");
return InteractionResult.SUCCESS;
}
@ -71,9 +71,9 @@ public class TileEntityKeyboard extends TileEntityPeripheralBase {
boolean ok;
if(ent instanceof Player)
ok = (scr.rightsFor((Player) ent) & ScreenRights.CLICK) != 0;
ok = (scr.rightsFor((Player) ent) & ScreenRights.INTERACT) != 0;
else
ok = (scr.otherRights & ScreenRights.CLICK) != 0;
ok = (scr.otherRights & ScreenRights.INTERACT) != 0;
if(ok) {
char rnd = RANDOM_CHARS.charAt((int) (Math.random() * ((double) RANDOM_CHARS.length())));

View File

@ -491,7 +491,7 @@ public class TileEntityScreen extends BlockEntity {
}
private static void checkLaserUserRights(Screen scr) {
if (scr.laserUser != null && (scr.rightsFor(scr.laserUser) & ScreenRights.CLICK) == 0)
if (scr.laserUser != null && (scr.rightsFor(scr.laserUser) & ScreenRights.INTERACT) == 0)
scr.laserUser = null;
}
@ -586,7 +586,6 @@ public class TileEntityScreen extends BlockEntity {
}
public void handleJSRequest(ServerPlayer src, BlockSide side, int reqId, JSServerRequest req, Object[] data) {
// TODO:
if (level.isClientSide) {
Log.error("Called handleJSRequest client-side");
return;
@ -1058,7 +1057,7 @@ public class TileEntityScreen extends BlockEntity {
return null;
}
if ((scr.rightsFor(ply) & ScreenRights.CLICK) == 0)
if ((scr.rightsFor(ply) & ScreenRights.INTERACT) == 0)
return null; //Don't output an error, it can 'legally' happen
if (scr.upgrades.stream().noneMatch(DefaultUpgrade.LASERMOUSE::matchesLaserMouse)) {

View File

@ -3,6 +3,7 @@ package net.montoyo.wd.net;
import net.minecraft.network.FriendlyByteBuf;
import net.montoyo.wd.utilities.Vector3i;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@ -54,9 +55,9 @@ public class BufferUtils {
for (T element : elements) writer.accept(element);
}
public static <T> T[] readArray(FriendlyByteBuf buf, Supplier<T> reader) {
public static <T> T[] readArray(FriendlyByteBuf buf, T[] array, Supplier<T> reader) {
//noinspection unchecked
T[] ts = (T[]) new Object[readUShort(buf)];
T[] ts = (T[]) Arrays.copyOf(array, readUShort(buf), array.getClass());
for (int i = 0; i < ts.length; i++) ts[i] = reader.get();
return ts;
}

View File

@ -36,10 +36,11 @@ public class S2CMessageACResult extends Packet {
}
public void handle(NetworkEvent.Context ctx) {
ctx.enqueueWork(() -> {
WebDisplays.PROXY.onAutocompleteResult(result);
});
ctx.setPacketHandled(true);
if (checkClient(ctx)) {
ctx.enqueueWork(() -> {
WebDisplays.PROXY.onAutocompleteResult(result);
});
ctx.setPacketHandled(true);
}
}
}
}

View File

@ -91,45 +91,47 @@ public class S2CMessageAddScreen extends Packet {
}
public void handle(NetworkEvent.Context ctx) {
ctx.enqueueWork(() -> {
Level lvl = (Level) WebDisplays.PROXY.getWorld(ctx);
BlockEntity te = lvl.getBlockEntity(pos.toBlock());
if (!(te instanceof TileEntityScreen)) {
lvl.setBlockAndUpdate(pos.toBlock(), lvl.getBlockState(pos.toBlock()).setValue(hasTE, true));
te = lvl.getBlockEntity(pos.toBlock());
if (checkClient(ctx)) {
ctx.enqueueWork(() -> {
Level lvl = (Level) WebDisplays.PROXY.getWorld(ctx);
BlockEntity te = lvl.getBlockEntity(pos.toBlock());
if (!(te instanceof TileEntityScreen)) {
if (clear)
Log.error("CMessageAddScreen: Can't add screen to invalid tile entity at %s", pos.toString());
lvl.setBlockAndUpdate(pos.toBlock(), lvl.getBlockState(pos.toBlock()).setValue(hasTE, true));
te = lvl.getBlockEntity(pos.toBlock());
return;
}
}
TileEntityScreen tes = (TileEntityScreen) te;
if (clear)
tes.clear();
for (TileEntityScreen.Screen entry : screens) {
TileEntityScreen.Screen scr = tes.addScreen(entry.side, entry.size, entry.resolution, null, false);
scr.rotation = entry.rotation;
String webUrl;
try {
webUrl = TileEntityScreen.url(entry.url);
} catch (IOException e) {
throw new RuntimeException(e);
if (!(te instanceof TileEntityScreen)) {
if (clear)
Log.error("CMessageAddScreen: Can't add screen to invalid tile entity at %s", pos.toString());
return;
}
}
scr.url = webUrl;
scr.owner = entry.owner;
scr.upgrades = entry.upgrades;
TileEntityScreen tes = (TileEntityScreen) te;
if (clear)
tes.clear();
if (scr.browser != null)
scr.browser.loadURL(webUrl);
}
});
ctx.setPacketHandled(true);
for (TileEntityScreen.Screen entry : screens) {
TileEntityScreen.Screen scr = tes.addScreen(entry.side, entry.size, entry.resolution, null, false);
scr.rotation = entry.rotation;
String webUrl;
try {
webUrl = TileEntityScreen.url(entry.url);
} catch (IOException e) {
throw new RuntimeException(e);
}
scr.url = webUrl;
scr.owner = entry.owner;
scr.upgrades = entry.upgrades;
if (scr.browser != null)
scr.browser.loadURL(webUrl);
}
});
ctx.setPacketHandled(true);
}
}
}
}

View File

@ -46,12 +46,14 @@ public class S2CMessageCloseGui extends Packet {
}
public void handle(NetworkEvent.Context ctx) {
ctx.enqueueWork(() -> {
if (blockSide == null)
Arrays.stream(BlockSide.values()).forEach(s -> WebDisplays.PROXY.closeGui(blockPos, s));
else
WebDisplays.PROXY.closeGui(blockPos, blockSide);
});
ctx.setPacketHandled(true);
if (checkClient(ctx)) {
ctx.enqueueWork(() -> {
if (blockSide == null)
Arrays.stream(BlockSide.values()).forEach(s -> WebDisplays.PROXY.closeGui(blockPos, s));
else
WebDisplays.PROXY.closeGui(blockPos, blockSide);
});
ctx.setPacketHandled(true);
}
}
}
}

View File

@ -80,16 +80,18 @@ public class S2CMessageJSResponse extends Packet {
}
public void handle(NetworkEvent.Context ctx) {
ctx.enqueueWork(() -> {
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);
}
});
ctx.setPacketHandled(true);
if (checkClient(ctx)) {
ctx.enqueueWork(() -> {
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);
}
});
ctx.setPacketHandled(true);
}
}
}

View File

@ -43,4 +43,4 @@ public class S2CMessageMiniservKey extends Packet {
ctx.setPacketHandled(true);
}
}
}
}

View File

@ -37,7 +37,9 @@ public class S2CMessageOpenGui extends Packet {
}
public void handle(NetworkEvent.Context context) {
context.enqueueWork(() -> WebDisplays.PROXY.displayGui(data));
context.setPacketHandled(true);
if (checkClient(context)) {
context.enqueueWork(() -> WebDisplays.PROXY.displayGui(data));
context.setPacketHandled(true);
}
}
}
}

View File

@ -234,22 +234,23 @@ public class S2CMessageScreenUpdate extends Packet {
}
public void handle(NetworkEvent.Context ctx) {
ctx.enqueueWork(() -> {
BlockGetter level = WebDisplays.PROXY.getWorld(ctx);
if (level instanceof Level level1)
// ensure that the TE exists
level1.setBlock(
pos.toBlock(),
level.getBlockState(pos.toBlock()).setValue(BlockScreen.hasTE, true),11
);
BlockEntity te = level.getBlockEntity(pos.toBlock());
if(!(te instanceof TileEntityScreen)) {
Log.error("CMessageScreenUpdate: TileEntity at %s is not a screen!", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
if (checkClient(ctx)) {
ctx.enqueueWork(() -> {
BlockGetter level = WebDisplays.PROXY.getWorld(ctx);
if (level instanceof Level level1)
// ensure that the TE exists
level1.setBlock(
pos.toBlock(),
level.getBlockState(pos.toBlock()).setValue(BlockScreen.hasTE, true),11
);
BlockEntity te = level.getBlockEntity(pos.toBlock());
if(!(te instanceof TileEntityScreen)) {
Log.error("CMessageScreenUpdate: TileEntity at %s is not a screen!", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
switch (action) {
case UPDATE_URL -> {
try {
@ -274,8 +275,9 @@ public class S2CMessageScreenUpdate extends Packet {
case UPDATE_AUTO_VOL -> tes.setAutoVolume(side, autoVolume);
default -> Log.warning("Caught invalid CMessageScreenUpdate with action ID %d", action);
}
});
ctx.setPacketHandled(true);
});
ctx.setPacketHandled(true);
}
}
}

View File

@ -35,7 +35,7 @@ public class S2CMessageServerInfo extends Packet {
try {
WebDisplays.PROXY.setMiniservClientPort(miniservPort);
C2SMessageMiniservConnect message = Client.getInstance().beginConnection();
respondLater(ctx, message);
respond(ctx, message);
ctx.setPacketHandled(true);
} catch (Throwable err) {
err.printStackTrace();
@ -43,4 +43,4 @@ public class S2CMessageServerInfo extends Packet {
}
}
}
}
}

View File

@ -18,7 +18,6 @@ import net.montoyo.wd.utilities.NameUUIDPair;
import java.util.Arrays;
public class C2SMessageACQuery extends Packet implements Runnable {
private ServerPlayer player;
private String beginning;
private boolean matchExact;
@ -27,13 +26,13 @@ public class C2SMessageACQuery extends Packet implements Runnable {
beginning = beg;
matchExact = exact;
}
public C2SMessageACQuery(FriendlyByteBuf buf) {
super(buf);
beginning = buf.readUtf();
matchExact = buf.readBoolean();
}
public C2SMessageACQuery(FriendlyByteBuf buf) {
super(buf);
beginning = buf.readUtf();
matchExact = buf.readBoolean();
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeUtf(beginning);
@ -56,9 +55,10 @@ public class C2SMessageACQuery extends Packet implements Runnable {
}
public void handle(NetworkEvent.Context ctx) {
player = ctx.getSender();
ctx.enqueueWork(this);
ctx.setPacketHandled(true);
if (checkServer(ctx)) {
player = ctx.getSender();
ctx.enqueueWork(this);
ctx.setPacketHandled(true);
}
}
}
}

View File

@ -42,11 +42,11 @@ public class C2SMessageMiniservConnect extends Packet {
try {
ClientManager cliMgr = Server.getInstance().getClientManager();
byte[] encKey = cliMgr.encryptClientKey(Objects.requireNonNull(ctx.getSender()).getGameProfile().getId(), modulus, exponent);
if (encKey != null) {
respond(ctx, new S2CMessageMiniservKey(encKey));
}
ctx.setPacketHandled(true);
} catch (Throwable err) {
err.printStackTrace();
@ -54,4 +54,4 @@ public class C2SMessageMiniservConnect extends Packet {
}
}
}
}
}

View File

@ -19,66 +19,68 @@ import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.Vector3i;
public class C2SMessageRedstoneCtrl extends Packet implements Runnable {
private Player player;
private Vector3i pos;
private String risingEdgeURL;
private String fallingEdgeURL;
public C2SMessageRedstoneCtrl() {
}
public C2SMessageRedstoneCtrl(Vector3i p, String r, String f) {
pos = p;
risingEdgeURL = r;
fallingEdgeURL = f;
}
public C2SMessageRedstoneCtrl(FriendlyByteBuf buf) {
super(buf);
pos = new Vector3i(buf);
risingEdgeURL = buf.readUtf();
fallingEdgeURL = buf.readUtf();
}
@Override
public void run() {
Level world = player.level;
BlockPos blockPos = pos.toBlock();
final double maxRange = player.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue();
if(player.distanceToSqr(blockPos.getX(), blockPos.getY(), blockPos.getZ()) > maxRange * maxRange)
return;
BlockEntity te = world.getBlockEntity(blockPos);
if(te == null || !(te instanceof TileEntityRedCtrl))
return;
TileEntityRedCtrl redCtrl = (TileEntityRedCtrl) te;
if(!redCtrl.isScreenChunkLoaded()) {
Util.toast(player, "chunkUnloaded");
return;
}
TileEntityScreen tes = redCtrl.getConnectedScreen();
if(tes == null)
return;
if((tes.getScreen(redCtrl.getScreenSide()).rightsFor(player) & ScreenRights.CHANGE_URL) == 0)
return;
redCtrl.setURLs(risingEdgeURL, fallingEdgeURL);
}
@Override
public void write(FriendlyByteBuf buf) {
pos.writeTo(buf);
buf.writeUtf(risingEdgeURL);
buf.writeUtf(fallingEdgeURL);
}
public void handle(NetworkEvent.Context ctx) {
player = ctx.getSender();
ctx.enqueueWork(this);
ctx.setPacketHandled(true);
}
}
private Player player;
private Vector3i pos;
private String risingEdgeURL;
private String fallingEdgeURL;
public C2SMessageRedstoneCtrl() {
}
public C2SMessageRedstoneCtrl(Vector3i p, String r, String f) {
pos = p;
risingEdgeURL = r;
fallingEdgeURL = f;
}
public C2SMessageRedstoneCtrl(FriendlyByteBuf buf) {
super(buf);
pos = new Vector3i(buf);
risingEdgeURL = buf.readUtf();
fallingEdgeURL = buf.readUtf();
}
@Override
public void run() {
Level world = player.level;
BlockPos blockPos = pos.toBlock();
final double maxRange = player.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue();
if (player.distanceToSqr(blockPos.getX(), blockPos.getY(), blockPos.getZ()) > maxRange * maxRange)
return;
BlockEntity te = world.getBlockEntity(blockPos);
if (te == null || !(te instanceof TileEntityRedCtrl))
return;
TileEntityRedCtrl redCtrl = (TileEntityRedCtrl) te;
if (!redCtrl.isScreenChunkLoaded()) {
Util.toast(player, "chunkUnloaded");
return;
}
TileEntityScreen tes = redCtrl.getConnectedScreen();
if (tes == null)
return;
if ((tes.getScreen(redCtrl.getScreenSide()).rightsFor(player) & ScreenRights.CHANGE_URL) == 0)
return;
redCtrl.setURLs(risingEdgeURL, fallingEdgeURL);
}
@Override
public void write(FriendlyByteBuf buf) {
pos.writeTo(buf);
buf.writeUtf(risingEdgeURL);
buf.writeUtf(fallingEdgeURL);
}
public void handle(NetworkEvent.Context ctx) {
if (checkServer(ctx)) {
player = ctx.getSender();
ctx.enqueueWork(this);
ctx.setPacketHandled(true);
}
}
}

View File

@ -6,369 +6,176 @@ package net.montoyo.wd.net.server_bound;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.network.NetworkEvent;
import net.montoyo.wd.block.BlockPeripheral;
import net.montoyo.wd.core.DefaultPeripheral;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.controls.ScreenControl;
import net.montoyo.wd.controls.ScreenControlRegistry;
import net.montoyo.wd.controls.builtin.*;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.init.BlockInit;
import net.montoyo.wd.net.BufferUtils;
import net.montoyo.wd.net.Packet;
import net.montoyo.wd.utilities.*;
import java.io.IOException;
// TODO: this is a mess; a registry based approach would likely be more readable
public class C2SMessageScreenCtrl extends Packet implements Runnable {
public static final int CTRL_SET_URL = 0;
public static final int CTRL_SHUT_DOWN = 1;
public static final int CTRL_ADD_FRIEND = 2;
public static final int CTRL_REMOVE_FRIEND = 3;
public static final int CTRL_SET_RIGHTS = 4;
public static final int CTRL_SET_RESOLUTION = 5;
public static final int CTRL_TYPE = 6;
public static final int CTRL_REMOVE_UPGRADE = 7;
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;
public static final int CTRL_SET_ROTATION = 12;
public static final int CTRL_SET_URL_REMOTE = 13;
public static final int CTRL_SET_AUTO_VOL = 14;
public class C2SMessageScreenCtrl extends Packet {
@Deprecated(forRemoval = true)
public static final int CTRL_LASER_MOVE = 0;
@Deprecated(forRemoval = true)
public static final int CTRL_LASER_UP = 0;
@Deprecated(forRemoval = true)
public static final int CTRL_LASER_DOWN = 0;
@Deprecated(forRemoval = true)
public static final int CTRL_SET_RESOLUTION = 0;
private int ctrl;
private ResourceLocation dim;
private Vector3i pos;
private BlockSide side;
private String url;
private NameUUIDPair friend;
private ServerPlayer player;
private int friendRights;
private int otherRights;
private Vector2i vec2i;
private String text;
private BlockPos soundPos;
private ItemStack toRemove;
private int jsReqID;
private JSServerRequest jsReqType;
private Object[] jsReqData;
private Rotation rotation;
private Vector3i remoteLoc;
private boolean autoVol;
ScreenControl control;
BlockPos pos;
BlockSide side;
public C2SMessageScreenCtrl() {
}
public C2SMessageScreenCtrl(TileEntityScreen screen, BlockSide side, ScreenControl control) {
this.pos = screen.getBlockPos();
this.side = side;
this.control = control;
}
protected static C2SMessageScreenCtrl base(TileEntityScreen screen, BlockSide side) {
C2SMessageScreenCtrl packet = new C2SMessageScreenCtrl();
packet.pos = screen.getBlockPos();
packet.side = side;
return packet;
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl setURL(TileEntityScreen tes, BlockSide side, String url, Vector3i remoteLocation) {
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = (remoteLocation == null) ? CTRL_SET_URL : CTRL_SET_URL_REMOTE;
ret.dim = tes.getLevel().dimension().location();
ret.pos = new Vector3i(tes.getBlockPos());
ret.side = side;
ret.url = url;
if (remoteLocation != null)
ret.remoteLoc = remoteLocation;
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new SetURLControl(url, remoteLocation);
return ret;
}
@Deprecated(forRemoval = true)
public C2SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, NameUUIDPair friend, boolean del) {
ctrl = del ? CTRL_REMOVE_FRIEND : CTRL_ADD_FRIEND;
dim = tes.getLevel().dimension().location();
pos = new Vector3i(tes.getBlockPos());
this.side = side;
this.friend = friend;
this(tes, side, new ModifyFriendListControl(friend, !del));
}
@Deprecated(forRemoval = true)
public C2SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, int fr, int or) {
ctrl = CTRL_SET_RIGHTS;
dim = tes.getLevel().dimension().location();
pos = new Vector3i(tes.getBlockPos());
this.side = side;
friendRights = fr;
otherRights = or;
this(tes, side, new ManageRightsAndUpdgradesControl(fr, or));
}
@Deprecated(forRemoval = true)
public C2SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, ItemStack toRem) {
ctrl = CTRL_REMOVE_UPGRADE;
dim = tes.getLevel().dimension().location();
pos = new Vector3i(tes.getBlockPos());
this.side = side;
toRemove = toRem;
this(tes, side, new ManageRightsAndUpdgradesControl(toRem));
}
@Deprecated(forRemoval = true)
public C2SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, Rotation rot) {
ctrl = CTRL_SET_ROTATION;
dim = tes.getLevel().dimension().location();
pos = new Vector3i(tes.getBlockPos());
this.side = side;
rotation = rot;
}
public static C2SMessageScreenCtrl type(TileEntityScreen tes, BlockSide side, String text, BlockPos soundPos) {
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = CTRL_TYPE;
ret.pos = new Vector3i(tes.getBlockPos());
ret.dim = tes.getLevel().dimension().location();
ret.side = side;
ret.text = text;
ret.soundPos = soundPos;
return ret;
this(tes, side, new ScreenModifyControl(rot));
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl vec2(TileEntityScreen tes, BlockSide side, int ctrl, Vector2i vec) {
if (!isVec2Ctrl(ctrl))
throw new RuntimeException("Called SMessageScreenCtrl.vec2() with non-vec2 control message " + ctrl);
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = ctrl;
ret.pos = new Vector3i(tes.getBlockPos());
ret.dim = tes.getLevel().dimension().location();
ret.side = side;
ret.vec2i = vec;
throw new RuntimeException("Moved: look into ScreenControlRegistry");
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl resolution(TileEntityScreen tes, BlockSide side, Vector2i vec) {
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new ScreenModifyControl(vec);
return ret;
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl type(TileEntityScreen tes, BlockSide side, String text, BlockPos soundPos) {
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new KeyTypedControl(text, soundPos);
return ret;
}
public static C2SMessageScreenCtrl laserMove(TileEntityScreen tes, BlockSide side, Vector2i vec) {
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new LaserControl(LaserControl.ControlType.MOVE, vec);
return ret;
}
public static C2SMessageScreenCtrl laserDown(TileEntityScreen tes, BlockSide side, Vector2i vec) {
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new LaserControl(LaserControl.ControlType.MOVE, vec);
return ret;
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl laserUp(TileEntityScreen tes, BlockSide side) {
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = CTRL_LASER_UP;
ret.pos = new Vector3i(tes.getBlockPos());
ret.dim = tes.getLevel().dimension().location();
ret.side = side;
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new LaserControl(LaserControl.ControlType.UP, null);
return ret;
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl jsRequest(TileEntityScreen tes, BlockSide side, int reqId, JSServerRequest reqType, Object... data) {
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = CTRL_JS_REQUEST;
ret.pos = new Vector3i(tes.getBlockPos());
ret.dim = tes.getLevel().dimension().location();
ret.side = side;
ret.jsReqID = reqId;
ret.jsReqType = reqType;
ret.jsReqData = data;
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new JSRequestControl(reqId, reqType, data);
return ret;
}
@Deprecated(forRemoval = true)
public static C2SMessageScreenCtrl autoVol(TileEntityScreen tes, BlockSide side, boolean av) {
C2SMessageScreenCtrl ret = new C2SMessageScreenCtrl();
ret.ctrl = CTRL_SET_AUTO_VOL;
ret.pos = new Vector3i(tes.getBlockPos());
ret.dim = tes.getLevel().dimension().location();
ret.side = side;
ret.autoVol = av;
C2SMessageScreenCtrl ret = base(tes, side);
ret.control = new AutoVolumeControl(av);
return ret;
}
private static boolean isVec2Ctrl(int msg) {
return msg == CTRL_SET_RESOLUTION || msg == CTRL_LASER_DOWN || msg == CTRL_LASER_MOVE;
}
public C2SMessageScreenCtrl(FriendlyByteBuf buf) {
super(buf);
decode(buf);
}
public void decode(FriendlyByteBuf buf) {
C2SMessageScreenCtrl message = this;
message.ctrl = buf.readByte();
message.dim = buf.readResourceLocation();
message.pos = new Vector3i(buf);
message.side = BlockSide.fromInt(buf.readByte());
if (message.ctrl == CTRL_SET_URL)
message.url = buf.readUtf();
else if (message.ctrl == CTRL_ADD_FRIEND || message.ctrl == CTRL_REMOVE_FRIEND)
message.friend = new NameUUIDPair(buf);
else if (message.ctrl == CTRL_SET_RIGHTS) {
message.friendRights = buf.readByte();
message.otherRights = buf.readByte();
} else if (isVec2Ctrl(message.ctrl))
message.vec2i = new Vector2i(buf);
else if (message.ctrl == CTRL_TYPE) {
message.text = buf.readUtf();
int sx = buf.readInt();
int sy = buf.readInt();
int sz = buf.readInt();
message.soundPos = new BlockPos(sx, sy, sz);
} else if (message.ctrl == CTRL_REMOVE_UPGRADE)
message.toRemove = buf.readItem();
else if (message.ctrl == CTRL_JS_REQUEST) {
message.jsReqID = buf.readInt();
message.jsReqType = JSServerRequest.fromID(buf.readByte());
if (message.jsReqType != null)
message.jsReqData = message.jsReqType.deserialize(buf);
} else if (message.ctrl == CTRL_SET_ROTATION)
message.rotation = Rotation.values()[buf.readByte() & 3];
else if (message.ctrl == CTRL_SET_URL_REMOTE) {
message.url = buf.readUtf();
message.remoteLoc = new Vector3i(buf);
} else if (message.ctrl == CTRL_SET_AUTO_VOL)
message.autoVol = buf.readBoolean();
pos = buf.readBlockPos();
side = (BlockSide) BufferUtils.readEnum(buf, (i) -> BlockSide.values()[i], (byte) 1);
this.control = ScreenControlRegistry.parse(buf);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeByte(ctrl);
buf.writeResourceLocation(dim);
pos.writeTo(buf);
buf.writeByte(side.ordinal());
buf.writeBlockPos(pos);
BufferUtils.writeEnum(buf, side, (byte) 1);
if (ctrl == CTRL_SET_URL)
buf.writeUtf(url);
else if (ctrl == CTRL_ADD_FRIEND || ctrl == CTRL_REMOVE_FRIEND)
friend.writeTo(buf);
else if (ctrl == CTRL_SET_RIGHTS) {
buf.writeByte(friendRights);
buf.writeByte(otherRights);
} else if (isVec2Ctrl(ctrl))
vec2i.writeTo(buf);
else if (ctrl == CTRL_TYPE) {
buf.writeUtf(text);
buf.writeInt(soundPos.getX());
buf.writeInt(soundPos.getY());
buf.writeInt(soundPos.getZ());
} else if (ctrl == CTRL_REMOVE_UPGRADE)
buf.writeItem(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);
} else if (ctrl == CTRL_SET_ROTATION)
buf.writeByte(rotation.ordinal());
else if (ctrl == CTRL_SET_URL_REMOTE) {
buf.writeUtf(url);
remoteLoc.writeTo(buf);
} else if (ctrl == CTRL_SET_AUTO_VOL)
buf.writeBoolean(autoVol);
buf.writeUtf(control.getId().toString());
control.write(buf);
}
@Override
public void run() {
if (side == null) {
Log.warning("Caught invalid packet from %s (UUID %s) referencing an invalid block side", player.getName(), player.getGameProfile().getId().toString());
return;
}
try {
runUnsafe();
} catch (MissingPermissionException e) {
Log.errorEx("I have reasons to believe %s (UUID %s) is a hacker, but don't take my word for it...", e, e.getPlayer().getName(), e.getPlayer().getGameProfile().getId().toString());
}
}
private void checkPermission(TileEntityScreen scr, int right) throws MissingPermissionException {
int prights = scr.getScreen(side).rightsFor(player);
public void checkPermission(ServerPlayer sender, TileEntityScreen scr, int right) throws MissingPermissionException {
int prights = scr.getScreen(side).rightsFor(sender);
if ((prights & right) == 0)
throw new MissingPermissionException(right, player);
}
private void runUnsafe() throws MissingPermissionException {
Level world = player.level;
BlockPos bp = pos.toBlock();
if (!world.dimension().location().equals(dim))
return; //Out of range (dimension mismatch)
if (ctrl == CTRL_SET_URL_REMOTE) {
double reachDist = player.getAttributeValue(ForgeMod.REACH_DISTANCE.get());
BlockPos blockPos = remoteLoc.toBlock();
if (player.distanceToSqr(blockPos.getX(), blockPos.getY(), blockPos.getZ()) > reachDist * reachDist)
return; //Out of range (player reach distance)
BlockState bs = world.getBlockState(blockPos);
if (bs.getBlock() != BlockInit.blockServer.get() && bs.getBlock() != BlockInit.blockRControl.get() &&
bs.getBlock() != BlockInit.blockKeyBoard.get() && bs.getBlock() != BlockInit.blockRedControl.get()
&& bs.getValue(BlockPeripheral.type) != DefaultPeripheral.REMOTE_CONTROLLER)
return; //I call it hax...
} else if (player.distanceToSqr(bp.getX(), bp.getY(), bp.getZ()) > (128 * 128))
return; //Out of range (range problem)
BlockEntity te = world.getBlockEntity(bp);
if (te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntity at %s is not a screen; can't control it!", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
if (ctrl == CTRL_SET_URL || ctrl == CTRL_SET_URL_REMOTE) {
checkPermission(tes, ScreenRights.CHANGE_URL);
try {
tes.setScreenURL(side, url);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (ctrl == CTRL_SHUT_DOWN) {
//TODO
//checkPermission(tes, ScreenRights.CHANGE_URL);
//tes.removeScreen(side);
} else if (ctrl == CTRL_ADD_FRIEND) {
checkPermission(tes, ScreenRights.MANAGE_FRIEND_LIST);
tes.addFriend(player, side, friend);
} else if (ctrl == CTRL_REMOVE_FRIEND) {
checkPermission(tes, ScreenRights.MANAGE_FRIEND_LIST);
tes.removeFriend(player, side, friend);
} else if (ctrl == CTRL_SET_RIGHTS) {
TileEntityScreen.Screen scr = tes.getScreen(side);
if (scr != null) {
int fr = scr.owner.uuid.equals(player.getGameProfile().getId()) ? friendRights : scr.friendRights;
int or = (scr.rightsFor(player) & ScreenRights.MANAGE_OTHER_RIGHTS) == 0 ? scr.otherRights : otherRights;
if (scr.friendRights != fr || scr.otherRights != or)
tes.setRights(player, side, fr, or);
}
} else if (ctrl == CTRL_SET_RESOLUTION) {
checkPermission(tes, ScreenRights.CHANGE_RESOLUTION);
tes.setResolution(side, vec2i);
} else if (ctrl == CTRL_TYPE) {
checkPermission(tes, ScreenRights.CLICK);
tes.type(side, text, soundPos);
} else if (ctrl == CTRL_REMOVE_UPGRADE) {
checkPermission(tes, ScreenRights.MANAGE_UPGRADES);
tes.removeUpgrade(side, toRemove, player);
} else if (ctrl == CTRL_LASER_DOWN || ctrl == CTRL_LASER_MOVE)
tes.laserDownMove(side, player, vec2i, ctrl == CTRL_LASER_DOWN);
else if (ctrl == CTRL_LASER_UP)
tes.laserUp(side, player);
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 if (ctrl == CTRL_SET_ROTATION) {
checkPermission(tes, ScreenRights.CHANGE_RESOLUTION);
tes.setRotation(side, rotation);
} else if (ctrl == CTRL_SET_AUTO_VOL) {
checkPermission(tes, ScreenRights.MANAGE_UPGRADES); //because why not
tes.setAutoVolume(side, autoVol);
} else
Log.warning("Caught SMessageScreenCtrl with invalid control ID %d from player %s (UUID %s)", ctrl, player.getName(), player.getGameProfile().getId().toString());
throw new MissingPermissionException(right, sender);
}
public void handle(NetworkEvent.Context ctx) {
player = ctx.getSender();
ctx.enqueueWork(this);
ctx.setPacketHandled(true);
if (checkServer(ctx)) {
ctx.enqueueWork(() -> {
try {
Level level = (Level) WebDisplays.PROXY.getWorld(ctx);
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof TileEntityScreen tes) {
control.handleServer(pos, side, tes, ctx, (perm) -> {
try {
checkPermission(ctx.getSender(), tes, perm);
return true;
} catch (Throwable ignored) {
return false;
}
});
}
} catch (MissingPermissionException e) {
}
});
ctx.setPacketHandled(true);
}
}
}

View File

@ -81,6 +81,7 @@ public enum VideoType {
return String.format(format, vid);
}
// TODO: timestamp stuff
@Nonnull
public String getVolumeJSQuery(int volInt, int volFrac) {
return (new StringBuilder(volumeCap)).append(volumePrefix).append(volInt).append('.').append(volFrac).append(volumeSuffix).toString();

View File

@ -2,12 +2,12 @@
"itemGroup.webdisplays": "§5Web Displays",
"block.webdisplays.screen": "Web Screen",
"block.webdisplays.peripheral": "Peripheral",
"block.webdisplays.peripheral.keyboard": "Keyboard",
"block.webdisplays.peripheral.remotectrl": "Remote Controller",
"block.webdisplays.peripheral.ccinterface": "ComputerCraft Interface",
"block.webdisplays.peripheral.cointerface": "OpenComputers Interface",
"block.webdisplays.peripheral.redstonectrl": "Redstone Controller",
"block.webdisplays.peripheral.server": "Server",
"block.webdisplays.kb_left": "Keyboard",
"block.webdisplays.rctrl": "Remote Controller",
"block.webdisplays.ccinterface": "ComputerCraft Interface",
"block.webdisplays.cointerface": "OpenComputers Interface",
"block.webdisplays.redctrl": "Redstone Controller",
"block.webdisplays.server": "Server",
"item.webdisplays.screencfg": "Screen Configurator",
"item.webdisplays.ownerthief": "Ownership Thief [ADMIN]",
"item.webdisplays.linker": "Linking Tool",
@ -24,10 +24,10 @@
"item.webdisplays.minepad": "minePad",
"item.webdisplays.minepad2": "minePad 2",
"item.webdisplays.upgrade": "Screen Upgrade",
"item.webdisplays.upgrade.lasermouse": "Laser Sensor",
"item.webdisplays.upgrade.redinput": "Redstone Input Port",
"item.webdisplays.upgrade.redoutput": "Redstone Output Port",
"item.webdisplays.upgrade.gps": "GPS Module",
"item.webdisplays.upgrade_lasermouse": "Laser Sensor",
"item.webdisplays.upgrade_redinput": "Redstone Input Port",
"item.webdisplays.upgrade_redoutput": "Redstone Output Port",
"item.webdisplays.upgrade_gps": "GPS Module",
"item.webdisplays.laserpointer": "Laser Pointer",
"item.webdisplays.advicon": "Advancement Icon",
"item.webdisplays.advicon.wd": "WebDisplays",