From aa8c54508933378a8551182f9beb141f1586d572 Mon Sep 17 00:00:00 2001 From: GiantLuigi4 <49770992+GiantLuigi4@users.noreply.github.com> Date: Fri, 10 Nov 2023 22:09:39 -0500 Subject: [PATCH] screens now get removed properly, TileEntityScreen has had ctrl+alt+l applied to it, and gradle has been cleaned up --- build.gradle | 65 +- .../montoyo/wd/entity/TileEntityScreen.java | 2035 +++++++++-------- 2 files changed, 1040 insertions(+), 1060 deletions(-) diff --git a/build.gradle b/build.gradle index 3498e50..d28a328 100644 --- a/build.gradle +++ b/build.gradle @@ -5,19 +5,29 @@ plugins { id 'org.spongepowered.mixin' version '0.7.+' id 'org.parchmentmc.librarian.forgegradle' version '1.+' } +apply plugin: 'org.spongepowered.mixin' + +println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) version = mod_version group = maven_group // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = archives_base_name + +// set java version java.toolchain.languageVersion = JavaLanguageVersion.of(17) -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) +// required for making a functional mod +sourceSets.main.resources.srcDirs += 'src/generated/resources' +mixin.add sourceSets.main, "webdisplays.refmap.json" + +// neoforge gradle minecraft { mappings channel: 'parchment', version: '2023.06.26-1.20.1' accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') copyIdeResources = true + runs { client { properties 'mixin.env.remapRefMap': 'true' @@ -65,73 +75,40 @@ minecraft { } repositories{ - maven { url "https://maven.shedaniel.me/" } - maven { url 'https://jitpack.io' } maven { name = "cursemaven" url = "https://www.cursemaven.com" } flatDir { dirs 'libs' } - maven { url 'https://mcef-download.cinemamod.com/repository/releases' } - maven { url = uri('https://mcef-download.cinemamod.com/repositories/releases') } + maven { url 'https://mcef-download.cinemamod.com/repositories/releases/' } } dependencies { minecraft 'net.neoforged:forge:1.20.1-47.1.65' annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' -// implementation fg.deobf("curse.maven:spark-361579:4381167") + // useful for debugging performance problems + implementation fg.deobf("curse.maven:spark-361579:4381167") + // here because we need to manually open the VR keyboard compileOnly fg.deobf("curse.maven:vivecraft-667903:4794431") - implementation fg.deobf("com.cinemamod:mcef-forge:2.0.1-1.20.1") { + implementation fg.deobf("com.cinemamod:mcef-forge:2.1.1-1.20.1") { transitive = false } } -sourceSets { - main.resources.srcDirs += 'src/generated/resources' -} - -// Example for how to get properties into the manifest for reading by the runtime.. +// jar meta-info jar { manifest { attributes([ - "Specification-Title": "webdisplays", - "Specification-Vendor": "webdisplays", + "Specification-Title": "Webdisplays", + "Specification-Vendor": "CinemaMod Group", "Specification-Version": "1", // We are version 1 of ourselves "Implementation-Title": project.name, - "Implementation-Version": "${version}", - "Implementation-Vendor" :"webdisplays", + "Implementation-Version": project.version, + "Implementation-Vendor": "CinemaMod Group", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), "MixinConfigs": "webdisplays.mixins.json" ]) } } - -// Example configuration to allow publishing using the maven-publish task -// we define a custom artifact that is sourced from the reobfJar output task -// and then declare that to be published -// Note you'll need to add a repository here -def reobfFile = file("$buildDir/reobfJar/output.jar") -def reobfArtifact = artifacts.add('default', reobfFile) { - type 'jar' - builtBy 'reobfJar' -} -publishing { - publications { - mavenJava(MavenPublication) { - artifact reobfArtifact - } - } - repositories { - maven { - url "file:///${project.projectDir}/mcmodsrepo" - } - } -} - -apply plugin: 'org.spongepowered.mixin' - -mixin { - add sourceSets.main, "webdisplays.refmap.json" -} diff --git a/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java b/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java index 451736e..2d2ced6 100644 --- a/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java +++ b/src/main/java/net/montoyo/wd/entity/TileEntityScreen.java @@ -59,532 +59,532 @@ import java.util.function.Consumer; import static net.montoyo.wd.block.BlockPeripheral.point; 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; - public Vector2i size; - public Vector2i resolution; - public Rotation rotation = Rotation.ROT_0; - public String url; - private VideoType videoType; - public NameUUIDPair owner; - public ArrayList friends; - public int friendRights; - public int otherRights; - public CefBrowser browser; - public ArrayList upgrades; - public boolean doTurnOnAnim; - public long turnOnTime; - public Player laserUser; - public final Vector2i lastMousePos = new Vector2i(); - public NibbleArray redstoneStatus; //null on client - public boolean autoVolume = true; - - public int mouseType; - - public static Screen deserialize(CompoundTag tag) { - Screen ret = new Screen(); - ret.side = BlockSide.values()[tag.getByte("Side")]; - ret.size = new Vector2i(tag.getInt("Width"), tag.getInt("Height")); - ret.resolution = new Vector2i(tag.getInt("ResolutionX"), tag.getInt("ResolutionY")); - ret.rotation = Rotation.values()[tag.getByte("Rotation")]; - ret.url = tag.getString("URL"); - ret.videoType = VideoType.getTypeFromURL(ret.url); - - if (ret.resolution.x <= 0 || ret.resolution.y <= 0) { - float psx = ((float) ret.size.x) * 16.f - 4.f; - float psy = ((float) ret.size.y) * 16.f - 4.f; - psx *= 8.f; //TODO: Use ratio in config file - psy *= 8.f; - - ret.resolution.x = (int) psx; - ret.resolution.y = (int) psy; - } - - if (tag.contains("OwnerName")) { - String name = tag.getString("OwnerName"); - UUID uuid = tag.getUUID("OwnerUUID"); - ret.owner = new NameUUIDPair(name, uuid); - } - - ListTag friends = tag.getList("Friends", 10); - ret.friends = new ArrayList<>(friends.size()); - - for (int i = 0; i < friends.size(); i++) { - CompoundTag nf = friends.getCompound(i); - NameUUIDPair pair = new NameUUIDPair(nf.getString("Name"), nf.getUUID("UUID")); - ret.friends.add(pair); - } - - ret.friendRights = tag.getByte("FriendRights"); - ret.otherRights = tag.getByte("OtherRights"); - - ListTag upgrades = tag.getList("Upgrades", 10); - ret.upgrades = new ArrayList<>(); - - for (int i = 0; i < upgrades.size(); i++) - ret.upgrades.add(ItemStack.of(upgrades.getCompound(i))); - - if (tag.contains("AutoVolume")) - ret.autoVolume = tag.getBoolean("AutoVolume"); - - return ret; - } - - public CompoundTag serialize() { - CompoundTag tag = new CompoundTag(); - tag.putByte("Side", (byte) side.ordinal()); - tag.putInt("Width", size.x); - tag.putInt("Height", size.y); - tag.putInt("ResolutionX", resolution.x); - tag.putInt("ResolutionY", resolution.y); - tag.putByte("Rotation", (byte) rotation.ordinal()); - tag.putString("URL", url); - - if (owner == null) - Log.warning("Found TES with NO OWNER!!"); - else { - tag.putString("OwnerName", owner.name); - tag.putUUID("OwnerUUID", owner.uuid); - } - - ListTag list = new ListTag(); - for (NameUUIDPair f : friends) { - CompoundTag nf = new CompoundTag(); - nf.putString("Name", f.name); - nf.putUUID("UUID", f.uuid); - - list.add(nf); - } - - tag.put("Friends", list); - tag.putByte("FriendRights", (byte) friendRights); - tag.putByte("OtherRights", (byte) otherRights); - - list = new ListTag(); - for (ItemStack is : upgrades) - list.add(is.save(new CompoundTag())); - - tag.put("Upgrades", list); - tag.putBoolean("AutoVolume", autoVolume); - return tag; - } - - public int rightsFor(Player ply) { - return rightsFor(ply.getGameProfile().getId()); - } - - public int rightsFor(UUID uuid) { - if (owner.uuid.equals(uuid)) - return ScreenRights.ALL; - - return friends.stream().anyMatch(f -> f.uuid.equals(uuid)) ? friendRights : otherRights; - } - - public void setupRedstoneStatus(Level world, BlockPos start) { - if (world.isClientSide()) { - Log.warning("Called Screen.setupRedstoneStatus() on client."); - return; - } - - if (redstoneStatus != null) { - Log.warning("Called Screen.setupRedstoneStatus() on server, but redstone status is non-null"); - return; - } - - Direction[] VALUES = Direction.values(); - redstoneStatus = new NibbleArray(size.x * size.y); - final Direction facing = VALUES[side.reverse().ordinal()]; - final ScreenIterator it = new ScreenIterator(start, side, size); - - while (it.hasNext()) { - int idx = it.getIndex(); - redstoneStatus.set(idx, world.getSignal(it.next(), facing)); - } - } - - - public void clampResolution() { - if (resolution.x > CommonConfig.Screen.maxResolutionX) { - float newY = ((float) resolution.y) * ((float) CommonConfig.Screen.maxResolutionX) / ((float) resolution.x); - resolution.x = CommonConfig.Screen.maxResolutionX; - resolution.y = (int) newY; - } - - if (resolution.y > CommonConfig.Screen.maxResolutionY) { - float newX = ((float) resolution.x) * ((float) CommonConfig.Screen.maxResolutionY) / ((float) resolution.y); - resolution.x = (int) newX; - resolution.y = CommonConfig.Screen.maxResolutionY; - } - } - - public void createBrowser(boolean doAnim) { - if (WebDisplays.PROXY instanceof ClientProxy clientProxy) { - browser = MCEF.createBrowser(WebDisplays.applyBlacklist(url != null ? url : "https://www.google.com"), false); - - if (browser instanceof MCEFBrowser mcefBrowser) { - if (rotation.isVertical) - mcefBrowser.resize(resolution.y, resolution.x); - else - mcefBrowser.resize(resolution.x, resolution.y); - - // uh yes this is intentional - // basically: on my laptop, this line caused an error inexplicably - // reason: the compiler didn't update this file, so it stayed as a Consumer in the bytecode - //noinspection RedundantCast - mcefBrowser.setCursorChangeListener((MCEFCursorChangeListener) (type) -> mouseType = type); - } - - doTurnOnAnim = doAnim; - turnOnTime = System.currentTimeMillis(); - } - } - } - - public void forEachScreenBlocks(BlockSide side, Consumer func) { - Screen scr = getScreen(side); - - if (scr != null) { - ScreenIterator it = new ScreenIterator(getBlockPos(), side, scr.size); - - while (it.hasNext()) - func.accept(it.next()); - } - } - - private final ArrayList screens = new ArrayList<>(); - private net.minecraft.world.phys.AABB renderBB = new net.minecraft.world.phys.AABB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); - private boolean loaded = true; - public float ytVolume = Float.POSITIVE_INFINITY; - - public boolean isLoaded() { - return loaded; - } - - public void load() { - loaded = true; - } - - public void unload() { - for (Screen scr : screens) { - if (scr.browser != null) { - scr.browser.close(true); - scr.browser = null; - } - } - - loaded = false; - } - - @Override - public void load(CompoundTag tag) { - super.load(tag); - - ListTag list = tag.getList("WDScreens", Tag.TAG_COMPOUND); - if (list.isEmpty()) - return; - - screens.clear(); - for (int i = 0; i < list.size(); i++) - screens.add(Screen.deserialize(list.getCompound(i))); - } - - @Override - public CompoundTag getUpdateTag() { - CompoundTag tag = new CompoundTag(); - saveAdditional(tag); - return tag; - } - - @Override - public void handleUpdateTag(CompoundTag tag) { - load(tag); - for (Screen screen : screens) { - if (screen.browser == null) screen.createBrowser(false); - if (screen.browser != null) screen.browser.loadURL(screen.url); - } - updateAABB(); - } - - @Override - protected void saveAdditional(CompoundTag tag) { - super.saveAdditional(tag); - - ListTag list = new ListTag(); - for (Screen scr : screens) - list.add(scr.serialize()); - - tag.put("WDScreens", list); - } - - public Screen addScreen(BlockSide side, Vector2i size, @Nullable Vector2i resolution, @Nullable Player owner, boolean sendUpdate) { - for (Screen scr : screens) { - if (scr.side == side) - return scr; - } - - Screen ret = new Screen(); - ret.side = side; - ret.size = size; - ret.url = CommonConfig.Browser.homepage; - ret.friends = new ArrayList<>(); - ret.friendRights = ScreenRights.DEFAULTS; - ret.otherRights = ScreenRights.DEFAULTS; - ret.upgrades = new ArrayList<>(); - - if (owner != null) { - ret.owner = new NameUUIDPair(owner.getGameProfile()); - - if (side == BlockSide.TOP || side == BlockSide.BOTTOM) { - int rot = (int) Math.floor(((double) (owner.getYRot() * 4.0f / 360.0f)) + 2.5) & 3; - - if (side == BlockSide.TOP) { - if (rot == 1) - rot = 3; - else if (rot == 3) - rot = 1; - } - - ret.rotation = Rotation.values()[rot]; - } - } - - if (resolution == null || resolution.x < 1 || resolution.y < 1) { - float psx = ((float) size.x) * 16.f - 4.f; - float psy = ((float) size.y) * 16.f - 4.f; - psx *= 8.f; //TODO: Use ratio in config file - psy *= 8.f; - - ret.resolution = new Vector2i((int) psx, (int) psy); - } else - ret.resolution = resolution; - - ret.clampResolution(); - - if (!level.isClientSide) { - ret.setupRedstoneStatus(level, getBlockPos()); - - if (sendUpdate) - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), new S2CMessageAddScreen(this, ret)); - } - - screens.add(ret); - - if (level.isClientSide) - updateAABB(); - else - setChanged(); + public TileEntityScreen(BlockPos arg2, BlockState arg3) { + super(TileInit.SCREEN_BLOCK_ENTITY.get(), arg2, arg3); + } + + public static class Screen { + + public BlockSide side; + public Vector2i size; + public Vector2i resolution; + public Rotation rotation = Rotation.ROT_0; + public String url; + private VideoType videoType; + public NameUUIDPair owner; + public ArrayList friends; + public int friendRights; + public int otherRights; + public CefBrowser browser; + public ArrayList upgrades; + public boolean doTurnOnAnim; + public long turnOnTime; + public Player laserUser; + public final Vector2i lastMousePos = new Vector2i(); + public NibbleArray redstoneStatus; //null on client + public boolean autoVolume = true; + + public int mouseType; + + public static Screen deserialize(CompoundTag tag) { + Screen ret = new Screen(); + ret.side = BlockSide.values()[tag.getByte("Side")]; + ret.size = new Vector2i(tag.getInt("Width"), tag.getInt("Height")); + ret.resolution = new Vector2i(tag.getInt("ResolutionX"), tag.getInt("ResolutionY")); + ret.rotation = Rotation.values()[tag.getByte("Rotation")]; + ret.url = tag.getString("URL"); + ret.videoType = VideoType.getTypeFromURL(ret.url); + + if (ret.resolution.x <= 0 || ret.resolution.y <= 0) { + float psx = ((float) ret.size.x) * 16.f - 4.f; + float psy = ((float) ret.size.y) * 16.f - 4.f; + psx *= 8.f; //TODO: Use ratio in config file + psy *= 8.f; + + ret.resolution.x = (int) psx; + ret.resolution.y = (int) psy; + } + + if (tag.contains("OwnerName")) { + String name = tag.getString("OwnerName"); + UUID uuid = tag.getUUID("OwnerUUID"); + ret.owner = new NameUUIDPair(name, uuid); + } + + ListTag friends = tag.getList("Friends", 10); + ret.friends = new ArrayList<>(friends.size()); + + for (int i = 0; i < friends.size(); i++) { + CompoundTag nf = friends.getCompound(i); + NameUUIDPair pair = new NameUUIDPair(nf.getString("Name"), nf.getUUID("UUID")); + ret.friends.add(pair); + } + + ret.friendRights = tag.getByte("FriendRights"); + ret.otherRights = tag.getByte("OtherRights"); + + ListTag upgrades = tag.getList("Upgrades", 10); + ret.upgrades = new ArrayList<>(); + + for (int i = 0; i < upgrades.size(); i++) + ret.upgrades.add(ItemStack.of(upgrades.getCompound(i))); + + if (tag.contains("AutoVolume")) + ret.autoVolume = tag.getBoolean("AutoVolume"); + + return ret; + } + + public CompoundTag serialize() { + CompoundTag tag = new CompoundTag(); + tag.putByte("Side", (byte) side.ordinal()); + tag.putInt("Width", size.x); + tag.putInt("Height", size.y); + tag.putInt("ResolutionX", resolution.x); + tag.putInt("ResolutionY", resolution.y); + tag.putByte("Rotation", (byte) rotation.ordinal()); + tag.putString("URL", url); + + if (owner == null) + Log.warning("Found TES with NO OWNER!!"); + else { + tag.putString("OwnerName", owner.name); + tag.putUUID("OwnerUUID", owner.uuid); + } + + ListTag list = new ListTag(); + for (NameUUIDPair f : friends) { + CompoundTag nf = new CompoundTag(); + nf.putString("Name", f.name); + nf.putUUID("UUID", f.uuid); + + list.add(nf); + } + + tag.put("Friends", list); + tag.putByte("FriendRights", (byte) friendRights); + tag.putByte("OtherRights", (byte) otherRights); + + list = new ListTag(); + for (ItemStack is : upgrades) + list.add(is.save(new CompoundTag())); + + tag.put("Upgrades", list); + tag.putBoolean("AutoVolume", autoVolume); + return tag; + } + + public int rightsFor(Player ply) { + return rightsFor(ply.getGameProfile().getId()); + } + + public int rightsFor(UUID uuid) { + if (owner.uuid.equals(uuid)) + return ScreenRights.ALL; + + return friends.stream().anyMatch(f -> f.uuid.equals(uuid)) ? friendRights : otherRights; + } + + public void setupRedstoneStatus(Level world, BlockPos start) { + if (world.isClientSide()) { + Log.warning("Called Screen.setupRedstoneStatus() on client."); + return; + } + + if (redstoneStatus != null) { + Log.warning("Called Screen.setupRedstoneStatus() on server, but redstone status is non-null"); + return; + } + + Direction[] VALUES = Direction.values(); + redstoneStatus = new NibbleArray(size.x * size.y); + final Direction facing = VALUES[side.reverse().ordinal()]; + final ScreenIterator it = new ScreenIterator(start, side, size); + + while (it.hasNext()) { + int idx = it.getIndex(); + redstoneStatus.set(idx, world.getSignal(it.next(), facing)); + } + } + + + public void clampResolution() { + if (resolution.x > CommonConfig.Screen.maxResolutionX) { + float newY = ((float) resolution.y) * ((float) CommonConfig.Screen.maxResolutionX) / ((float) resolution.x); + resolution.x = CommonConfig.Screen.maxResolutionX; + resolution.y = (int) newY; + } + + if (resolution.y > CommonConfig.Screen.maxResolutionY) { + float newX = ((float) resolution.x) * ((float) CommonConfig.Screen.maxResolutionY) / ((float) resolution.y); + resolution.x = (int) newX; + resolution.y = CommonConfig.Screen.maxResolutionY; + } + } + + public void createBrowser(boolean doAnim) { + if (WebDisplays.PROXY instanceof ClientProxy clientProxy) { + browser = MCEF.createBrowser(WebDisplays.applyBlacklist(url != null ? url : "https://www.google.com"), false); + + if (browser instanceof MCEFBrowser mcefBrowser) { + if (rotation.isVertical) + mcefBrowser.resize(resolution.y, resolution.x); + else + mcefBrowser.resize(resolution.x, resolution.y); + + // uh yes this is intentional + // basically: on my laptop, this line caused an error inexplicably + // reason: the compiler didn't update this file, so it stayed as a Consumer in the bytecode + //noinspection RedundantCast + mcefBrowser.setCursorChangeListener((MCEFCursorChangeListener) (type) -> mouseType = type); + } + + doTurnOnAnim = doAnim; + turnOnTime = System.currentTimeMillis(); + } + } + } + + public void forEachScreenBlocks(BlockSide side, Consumer func) { + Screen scr = getScreen(side); + + if (scr != null) { + ScreenIterator it = new ScreenIterator(getBlockPos(), side, scr.size); + + while (it.hasNext()) + func.accept(it.next()); + } + } + + private final ArrayList screens = new ArrayList<>(); + private net.minecraft.world.phys.AABB renderBB = new net.minecraft.world.phys.AABB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + private boolean loaded = true; + public float ytVolume = Float.POSITIVE_INFINITY; + + public boolean isLoaded() { + return loaded; + } + + public void load() { + loaded = true; + } + + public void unload() { + for (Screen scr : screens) { + if (scr.browser != null) { + scr.browser.close(true); + scr.browser = null; + } + } + + loaded = false; + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + + ListTag list = tag.getList("WDScreens", Tag.TAG_COMPOUND); + if (list.isEmpty()) + return; + + screens.clear(); + for (int i = 0; i < list.size(); i++) + screens.add(Screen.deserialize(list.getCompound(i))); + } + + @Override + public CompoundTag getUpdateTag() { + CompoundTag tag = new CompoundTag(); + saveAdditional(tag); + return tag; + } + + @Override + public void handleUpdateTag(CompoundTag tag) { + load(tag); + for (Screen screen : screens) { + if (screen.browser == null) screen.createBrowser(false); + if (screen.browser != null) screen.browser.loadURL(screen.url); + } + updateAABB(); + } + + @Override + protected void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); + + ListTag list = new ListTag(); + for (Screen scr : screens) + list.add(scr.serialize()); + + tag.put("WDScreens", list); + } + + public Screen addScreen(BlockSide side, Vector2i size, @Nullable Vector2i resolution, @Nullable Player owner, boolean sendUpdate) { + for (Screen scr : screens) { + if (scr.side == side) + return scr; + } + + Screen ret = new Screen(); + ret.side = side; + ret.size = size; + ret.url = CommonConfig.Browser.homepage; + ret.friends = new ArrayList<>(); + ret.friendRights = ScreenRights.DEFAULTS; + ret.otherRights = ScreenRights.DEFAULTS; + ret.upgrades = new ArrayList<>(); + + if (owner != null) { + ret.owner = new NameUUIDPair(owner.getGameProfile()); + + if (side == BlockSide.TOP || side == BlockSide.BOTTOM) { + int rot = (int) Math.floor(((double) (owner.getYRot() * 4.0f / 360.0f)) + 2.5) & 3; + + if (side == BlockSide.TOP) { + if (rot == 1) + rot = 3; + else if (rot == 3) + rot = 1; + } + + ret.rotation = Rotation.values()[rot]; + } + } + + if (resolution == null || resolution.x < 1 || resolution.y < 1) { + float psx = ((float) size.x) * 16.f - 4.f; + float psy = ((float) size.y) * 16.f - 4.f; + psx *= 8.f; //TODO: Use ratio in config file + psy *= 8.f; + + ret.resolution = new Vector2i((int) psx, (int) psy); + } else + ret.resolution = resolution; + + ret.clampResolution(); + + if (!level.isClientSide) { + ret.setupRedstoneStatus(level, getBlockPos()); + + if (sendUpdate) + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), new S2CMessageAddScreen(this, ret)); + } + + screens.add(ret); + + if (level.isClientSide) + updateAABB(); + else + setChanged(); // level.blockEntityChanged(worldPosition); - - return ret; - } - - public Screen getScreen(BlockSide side) { - for (Screen scr : screens) { - if (scr.side == side) - return scr; - } - - return null; - } - - public int screenCount() { - return screens.size(); - } - - public Screen getScreen(int idx) { - return screens.get(idx); - } - - public void clear() { - screens.clear(); - - if (!level.isClientSide) - setChanged(); - } - - public void requestData(ServerPlayer ep) { - if (!level.isClientSide) - WDNetworkRegistry.INSTANCE.send(PacketDistributor.PLAYER.with(() -> ep), new S2CMessageAddScreen(this)); - } - - public static String url(String url) throws IOException { - System.out.println("URL received: " + url); - if (!(WebDisplays.PROXY instanceof ClientProxy)) { - List serverPlayers = WebDisplays.PROXY.getServer().getPlayerList().getPlayers(); - SyncPlugin.syncPlayers(serverPlayers); - for (ServerPlayer serverPlayer : serverPlayers) { - SyncPlugin.setPlayerString(serverPlayer, url); - } - return url; - } else { - return url; // TODO: ? - } - } - - public void setScreenURL(BlockSide side, String url) throws IOException { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Attempt to change URL of non-existing screen on side %s", side.toString()); - return; - } - - String weburl = url(url); - - weburl = WebDisplays.applyBlacklist(weburl); - scr.url = weburl; - scr.videoType = VideoType.getTypeFromURL(weburl); - - if (level.isClientSide) { - if (scr.browser != null) - scr.browser.loadURL(weburl); - } else { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.setURL(this, side, weburl)); - setChanged(); - } - } - - public void removeScreen(BlockSide side) { - int idx = -1; - for (int i = 0; i < screens.size(); i++) { - if (screens.get(i).side == side) { - idx = i; - break; - } - } - - if (idx < 0) { - Log.error("Tried to delete non-existing screen on side %s", side.toString()); - return; - } - - if (level.isClientSide) { - if (screens.get(idx).browser != null) { - screens.get(idx).browser.close(true); - screens.get(idx).browser = null; - } - } else - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), new S2CMessageScreenUpdate(this.getBlockPos(), side)); //Delete the screen - - screens.remove(idx); - - if (!level.isClientSide) { - if (screens.isEmpty()) //No more screens: remove tile entity - level.setBlockAndUpdate(getBlockPos(), BlockInit.blockScreen.get().defaultBlockState().setValue(BlockScreen.hasTE, false)); - else - setChanged(); - } - } - - public void setResolution(BlockSide side, Vector2i res) { - if (res.x < 1 || res.y < 1) { - Log.warning("Call to TileEntityScreen.setResolution(%s) with suspicious values X=%d and Y=%d", side.toString(), res.x, res.y); - return; - } - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to change resolution of non-existing screen on side %s", side.toString()); - return; - } - - scr.resolution = res; - scr.clampResolution(); - - if (level.isClientSide) { - WebDisplays.PROXY.screenUpdateResolutionInGui(new Vector3i(getBlockPos()), side, res); - - if (scr.browser != null) { - scr.browser.close(true); - scr.browser = null; //Will be re-created by renderer - } - } else { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.setResolution(this, side, res)); - setChanged(); - } - } - - private static Player getLaserUser(Screen scr) { - if (scr.laserUser != null) { - if (scr.laserUser.isRemoved() || !scr.laserUser.getItemInHand(InteractionHand.MAIN_HAND).getItem().equals(ItemInit.LASER_POINTER.get())) - scr.laserUser = null; - } - - return scr.laserUser; - } - - private static void checkLaserUserRights(Screen scr) { - if (scr.laserUser != null && (scr.rightsFor(scr.laserUser) & ScreenRights.INTERACT) == 0) - scr.laserUser = null; - } - - public void clearLaserUser(BlockSide side) { - Screen scr = getScreen(side); - - if (scr != null) - scr.laserUser = null; - } - - public void click(BlockSide side, Vector2i vec) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Attempt click non-existing screen of side %s", side.toString()); - return; - } - - if (level.isClientSide) - Log.warning("TileEntityScreen.click() from client side is useless..."); - else if (getLaserUser(scr) == null) - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.CLICK, vec)); - } - - void clickUnsafe(BlockSide side, ClickControl.ControlType action, int x, int y) { - if (level.isClientSide) { - Vector2i vec = (action == ClickControl.ControlType.UP) ? null : new Vector2i(x, y); - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, action, vec)); - } - } - - public void handleMouseEvent(BlockSide side, ClickControl.ControlType event, @Nullable Vector2i vec, int button) { - if (button > 1) return; // buttons above 1 crash the game - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Attempt inject mouse events on non-existing screen of side %s", side.toString()); - return; - } - - if (scr.browser instanceof MCEFBrowser mcefBrowser) { - if (button == 1) button = 0; - else if (button == 0) button = 1; - - if (event == ClickControl.ControlType.CLICK) { - mcefBrowser.sendMouseMove(vec.x, vec.y); //Move to target - mcefBrowser.sendMousePress(vec.x, vec.y, button); //Press - mcefBrowser.sendMouseRelease(vec.x, vec.y, button); //Release - } else if (event == ClickControl.ControlType.DOWN) { - mcefBrowser.sendMouseMove(vec.x, vec.y); //Move to target - mcefBrowser.sendMousePress(vec.x, vec.y, button); //Press - } else if (event == ClickControl.ControlType.MOVE) - mcefBrowser.sendMouseMove(vec.x, vec.y); //Move - else if (event == ClickControl.ControlType.UP) - mcefBrowser.sendMouseRelease(scr.lastMousePos.x, scr.lastMousePos.y, button); //Release - - mcefBrowser.setFocus(true); - - if (vec != null) { - scr.lastMousePos.x = vec.x; - scr.lastMousePos.y = vec.y; - } - } - } - + + return ret; + } + + public Screen getScreen(BlockSide side) { + for (Screen scr : screens) { + if (scr.side == side) + return scr; + } + + return null; + } + + public int screenCount() { + return screens.size(); + } + + public Screen getScreen(int idx) { + return screens.get(idx); + } + + public void clear() { + screens.clear(); + + if (!level.isClientSide) + setChanged(); + } + + public void requestData(ServerPlayer ep) { + if (!level.isClientSide) + WDNetworkRegistry.INSTANCE.send(PacketDistributor.PLAYER.with(() -> ep), new S2CMessageAddScreen(this)); + } + + public static String url(String url) throws IOException { + System.out.println("URL received: " + url); + if (!(WebDisplays.PROXY instanceof ClientProxy)) { + List serverPlayers = WebDisplays.PROXY.getServer().getPlayerList().getPlayers(); + SyncPlugin.syncPlayers(serverPlayers); + for (ServerPlayer serverPlayer : serverPlayers) { + SyncPlugin.setPlayerString(serverPlayer, url); + } + return url; + } else { + return url; // TODO: ? + } + } + + public void setScreenURL(BlockSide side, String url) throws IOException { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Attempt to change URL of non-existing screen on side %s", side.toString()); + return; + } + + String weburl = url(url); + + weburl = WebDisplays.applyBlacklist(weburl); + scr.url = weburl; + scr.videoType = VideoType.getTypeFromURL(weburl); + + if (level.isClientSide) { + if (scr.browser != null) + scr.browser.loadURL(weburl); + } else { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.setURL(this, side, weburl)); + setChanged(); + } + } + + public void removeScreen(BlockSide side) { + int idx = -1; + for (int i = 0; i < screens.size(); i++) { + if (screens.get(i).side == side) { + idx = i; + break; + } + } + + if (idx < 0) { + Log.error("Tried to delete non-existing screen on side %s", side.toString()); + return; + } + + if (level.isClientSide) { + if (screens.get(idx).browser != null) { + screens.get(idx).browser.close(true); + screens.get(idx).browser = null; + } + } else + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), new S2CMessageScreenUpdate(this.getBlockPos(), side)); //Delete the screen + + screens.remove(idx); + + if (!level.isClientSide) { + if (screens.isEmpty()) //No more screens: remove tile entity + level.setBlockAndUpdate(getBlockPos(), BlockInit.blockScreen.get().defaultBlockState().setValue(BlockScreen.hasTE, false)); + else + setChanged(); + } + } + + public void setResolution(BlockSide side, Vector2i res) { + if (res.x < 1 || res.y < 1) { + Log.warning("Call to TileEntityScreen.setResolution(%s) with suspicious values X=%d and Y=%d", side.toString(), res.x, res.y); + return; + } + + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to change resolution of non-existing screen on side %s", side.toString()); + return; + } + + scr.resolution = res; + scr.clampResolution(); + + if (level.isClientSide) { + WebDisplays.PROXY.screenUpdateResolutionInGui(new Vector3i(getBlockPos()), side, res); + + if (scr.browser != null) { + scr.browser.close(true); + scr.browser = null; //Will be re-created by renderer + } + } else { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.setResolution(this, side, res)); + setChanged(); + } + } + + private static Player getLaserUser(Screen scr) { + if (scr.laserUser != null) { + if (scr.laserUser.isRemoved() || !scr.laserUser.getItemInHand(InteractionHand.MAIN_HAND).getItem().equals(ItemInit.LASER_POINTER.get())) + scr.laserUser = null; + } + + return scr.laserUser; + } + + private static void checkLaserUserRights(Screen scr) { + if (scr.laserUser != null && (scr.rightsFor(scr.laserUser) & ScreenRights.INTERACT) == 0) + scr.laserUser = null; + } + + public void clearLaserUser(BlockSide side) { + Screen scr = getScreen(side); + + if (scr != null) + scr.laserUser = null; + } + + public void click(BlockSide side, Vector2i vec) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Attempt click non-existing screen of side %s", side.toString()); + return; + } + + if (level.isClientSide) + Log.warning("TileEntityScreen.click() from client side is useless..."); + else if (getLaserUser(scr) == null) + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.CLICK, vec)); + } + + void clickUnsafe(BlockSide side, ClickControl.ControlType action, int x, int y) { + if (level.isClientSide) { + Vector2i vec = (action == ClickControl.ControlType.UP) ? null : new Vector2i(x, y); + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, action, vec)); + } + } + + public void handleMouseEvent(BlockSide side, ClickControl.ControlType event, @Nullable Vector2i vec, int button) { + if (button > 1) return; // buttons above 1 crash the game + + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Attempt inject mouse events on non-existing screen of side %s", side.toString()); + return; + } + + if (scr.browser instanceof MCEFBrowser mcefBrowser) { + if (button == 1) button = 0; + else if (button == 0) button = 1; + + if (event == ClickControl.ControlType.CLICK) { + mcefBrowser.sendMouseMove(vec.x, vec.y); //Move to target + mcefBrowser.sendMousePress(vec.x, vec.y, button); //Press + mcefBrowser.sendMouseRelease(vec.x, vec.y, button); //Release + } else if (event == ClickControl.ControlType.DOWN) { + mcefBrowser.sendMouseMove(vec.x, vec.y); //Move to target + mcefBrowser.sendMousePress(vec.x, vec.y, button); //Press + } else if (event == ClickControl.ControlType.MOVE) + mcefBrowser.sendMouseMove(vec.x, vec.y); //Move + else if (event == ClickControl.ControlType.UP) + mcefBrowser.sendMouseRelease(scr.lastMousePos.x, scr.lastMousePos.y, button); //Release + + mcefBrowser.setFocus(true); + + if (vec != null) { + scr.lastMousePos.x = vec.x; + scr.lastMousePos.y = vec.y; + } + } + } + // public void updateJSRedstone(BlockSide side, Vector2i vec, int redstoneLevel) { // Screen scr = getScreen(side); // if (scr == null) { @@ -680,80 +680,80 @@ public class TileEntityScreen extends BlockEntity { // } else // WDNetworkRegistry.INSTANCE.send(PacketDistributor.PLAYER.with(() -> src), new S2CMessageJSResponse(reqId, req, 400, "Invalid request")); // } - - @Override - public void onLoad() { - if (level.isClientSide) { - WebDisplays.PROXY.trackScreen(this, true); - } - } - - @Override - public void onChunkUnloaded() { - if (level.isClientSide) { - WebDisplays.PROXY.trackScreen(this, false); - - for (Screen scr : screens) { - if (scr.browser != null) { - scr.browser.close(true); - scr.browser = null; - } - } - } - } - - private void updateAABB() { - Vector3i origin = new Vector3i(getBlockPos()); - MutableAABB box = null; - - for (Screen scr : screens) { - Vector3i f = scr.side.forward; - - int fx = Math.max(f.x, 0); - int fy = Math.max(f.y, 0); - int fz = Math.max(f.z, 0); - int ox = 0; - if (scr.side.equals(BlockSide.NORTH)) ox = 1; - int oz = 0; - if ( - scr.side.equals(BlockSide.EAST) || - scr.side.equals(BlockSide.TOP) || - scr.side.equals(BlockSide.BOTTOM) - ) oz = 1; - - if (box == null) { - box = new MutableAABB( - origin.x + fx + ox, - origin.y + fy, - origin.z + fz + oz, - - origin.x + ox + scr.side.right.x * scr.size.x + fx + scr.side.up.x * scr.size.y, - origin.y + scr.side.right.y * scr.size.x + fy + scr.side.up.y * scr.size.y, - origin.z + oz + scr.side.right.z * scr.size.x + fz + scr.side.up.z * scr.size.y - ); - } else { - box.expand( - origin.x + fx + ox, - origin.y + fy, - origin.z + fz + oz, - - origin.x + ox + scr.side.right.x * scr.size.x + fx + scr.side.up.x * scr.size.y, - origin.y + scr.side.right.y * scr.size.x + fy + scr.side.up.y * scr.size.y, - origin.z + oz + scr.side.right.z * scr.size.x + fz + scr.side.up.z * scr.size.y - ); - } - } - - if (box == null) renderBB = new AABB(worldPosition); - else renderBB = box.toMc(); - } - - @Override - @Nonnull - public net.minecraft.world.phys.AABB getRenderBoundingBox() { - return renderBB; - } - + + @Override + public void onLoad() { + if (level.isClientSide) { + WebDisplays.PROXY.trackScreen(this, true); + } + } + + @Override + public void onChunkUnloaded() { + if (level.isClientSide) { + WebDisplays.PROXY.trackScreen(this, false); + + for (Screen scr : screens) { + if (scr.browser != null) { + scr.browser.close(true); + scr.browser = null; + } + } + } + } + + private void updateAABB() { + Vector3i origin = new Vector3i(getBlockPos()); + MutableAABB box = null; + + for (Screen scr : screens) { + Vector3i f = scr.side.forward; + + int fx = Math.max(f.x, 0); + int fy = Math.max(f.y, 0); + int fz = Math.max(f.z, 0); + int ox = 0; + if (scr.side.equals(BlockSide.NORTH)) ox = 1; + int oz = 0; + if ( + scr.side.equals(BlockSide.EAST) || + scr.side.equals(BlockSide.TOP) || + scr.side.equals(BlockSide.BOTTOM) + ) oz = 1; + + if (box == null) { + box = new MutableAABB( + origin.x + fx + ox, + origin.y + fy, + origin.z + fz + oz, + + origin.x + ox + scr.side.right.x * scr.size.x + fx + scr.side.up.x * scr.size.y, + origin.y + scr.side.right.y * scr.size.x + fy + scr.side.up.y * scr.size.y, + origin.z + oz + scr.side.right.z * scr.size.x + fz + scr.side.up.z * scr.size.y + ); + } else { + box.expand( + origin.x + fx + ox, + origin.y + fy, + origin.z + fz + oz, + + origin.x + ox + scr.side.right.x * scr.size.x + fx + scr.side.up.x * scr.size.y, + origin.y + scr.side.right.y * scr.size.x + fy + scr.side.up.y * scr.size.y, + origin.z + oz + scr.side.right.z * scr.size.x + fz + scr.side.up.z * scr.size.y + ); + } + } + + if (box == null) renderBB = new AABB(worldPosition); + else renderBB = box.toMc(); + } + + @Override + @Nonnull + public net.minecraft.world.phys.AABB getRenderBoundingBox() { + return renderBB; + } + // //FIXME: Not called if enableSoundDistance is false // public void updateTrackDistance(double d, float masterVolume) { // final WebDisplays wd = WebDisplays.INSTANCE; @@ -787,158 +787,159 @@ public class TileEntityScreen extends BlockEntity { // } // } // } - - public void updateClientSideURL(CefBrowser target, String url) { - for (Screen scr : screens) { - if (scr.browser == target) { - String webUrl; - try { - webUrl = TileEntityScreen.url(url); - } catch (IOException e) { - throw new RuntimeException(e); - } - boolean blacklisted = WebDisplays.isSiteBlacklisted(url); - scr.url = blacklisted ? WebDisplays.BLACKLIST_URL : url; //FIXME: This is an invalid fix for something that CANNOT be fixed - scr.videoType = VideoType.getTypeFromURL(scr.url); - ytVolume = Float.POSITIVE_INFINITY; //Force volume update - - if (blacklisted && scr.browser != null) - scr.browser.loadURL(WebDisplays.BLACKLIST_URL); - - break; - } - } - } - - @Override - public void invalidateCaps() { - super.invalidateCaps(); - - if (level.isClientSide) - onChunkUnloaded(); - } - - public void addFriend(ServerPlayer ply, BlockSide side, NameUUIDPair pair) { - if (!level.isClientSide) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to add friend to invalid screen side %s", side.toString()); - return; - } - - if (!scr.friends.contains(pair)) { - scr.friends.add(pair); - (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); - setChanged(); - } - } - } - - public void removeFriend(ServerPlayer ply, BlockSide side, NameUUIDPair pair) { - if (!level.isClientSide) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to remove friend from invalid screen side %s", side.toString()); - return; - } - - if (scr.friends.remove(pair)) { - checkLaserUserRights(scr); - (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); - setChanged(); - } - } - } - - public void setRights(ServerPlayer ply, BlockSide side, int fr, int or) { - if (!level.isClientSide) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to change rights of invalid screen on side %s", side.toString()); - return; - } - - scr.friendRights = fr; - scr.otherRights = or; - - checkLaserUserRights(scr); - (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); - setChanged(); - } - } - - public void type(BlockSide side, String text, BlockPos soundPos) { - type(side, text, soundPos, null); - } - - public void type(BlockSide side, String text, BlockPos soundPos, @Nullable ServerPlayer sender) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to type on invalid screen on side %s", side.toString()); - return; - } - - if (level.isClientSide) { - if (scr.browser instanceof MCEFBrowser mcefBrowser) { - try { - if (text.startsWith("t")) { - for (int i = 1; i < text.length(); i++) { - char chr = text.charAt(i); - if (chr == 1) - break; - - mcefBrowser.sendKeyTyped(chr, 0); - } - } else { - TypeData[] data = WebDisplays.GSON.fromJson(text, TypeData[].class); - - for (TypeData ev : data) { - if (ev.getKeyCode() == 257) { - ev = new TypeData( - ev.getAction(), - 10, ev.getModifier(), - ev.getScanCode() - ); - } - - switch (ev.getAction()) { - case PRESS -> { - mcefBrowser.sendKeyPress(ev.getKeyCode(), ev.getScanCode(), ev.getModifier()); - if (ev.getKeyCode() == 10) - mcefBrowser.sendKeyTyped('\r', ev.getModifier()); - } - case RELEASE -> - mcefBrowser.sendKeyRelease(ev.getKeyCode(), ev.getScanCode(), ev.getModifier()); - case TYPE -> mcefBrowser.sendKeyTyped((char) ev.getKeyCode(), ev.getModifier()); // TODO: check - - default -> throw new RuntimeException("Invalid type action '" + ev.getAction() + '\''); - } - } - } - } catch (Throwable t) { - Log.warningEx("Suspicious keyboard type packet received...", t); - } - } - } else { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with( - sender != null ? - () -> point(sender, level, getBlockPos()) : - () -> point(level, getBlockPos()) - ), S2CMessageScreenUpdate.type(this, side, text)); - - if (soundPos != null) - playSoundAt(WebDisplays.INSTANCE.soundTyping, soundPos, 0.25f, 1.f); - } - } - - private void playSoundAt(SoundEvent snd, BlockPos at, float vol, float pitch) { - double x = at.getX(); - double y = at.getY(); - double z = at.getZ(); - - level.playSound(null, x + 0.5, y + 0.5, z + 0.5, snd, SoundSource.BLOCKS, vol, pitch); - } - + + public void updateClientSideURL(CefBrowser target, String url) { + for (Screen scr : screens) { + if (scr.browser == target) { + String webUrl; + try { + webUrl = TileEntityScreen.url(url); + } catch (IOException e) { + throw new RuntimeException(e); + } + boolean blacklisted = WebDisplays.isSiteBlacklisted(url); + scr.url = blacklisted ? WebDisplays.BLACKLIST_URL : url; //FIXME: This is an invalid fix for something that CANNOT be fixed + scr.videoType = VideoType.getTypeFromURL(scr.url); + ytVolume = Float.POSITIVE_INFINITY; //Force volume update + + if (blacklisted && scr.browser != null) + scr.browser.loadURL(WebDisplays.BLACKLIST_URL); + + break; + } + } + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + + if (level.isClientSide) + onChunkUnloaded(); + } + + public void addFriend(ServerPlayer ply, BlockSide side, NameUUIDPair pair) { + if (!level.isClientSide) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to add friend to invalid screen side %s", side.toString()); + return; + } + + if (!scr.friends.contains(pair)) { + scr.friends.add(pair); + (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); + setChanged(); + } + } + } + + public void removeFriend(ServerPlayer ply, BlockSide side, NameUUIDPair pair) { + if (!level.isClientSide) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to remove friend from invalid screen side %s", side.toString()); + return; + } + + if (scr.friends.remove(pair)) { + checkLaserUserRights(scr); + (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); + setChanged(); + } + } + } + + public void setRights(ServerPlayer ply, BlockSide side, int fr, int or) { + if (!level.isClientSide) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to change rights of invalid screen on side %s", side.toString()); + return; + } + + scr.friendRights = fr; + scr.otherRights = or; + + checkLaserUserRights(scr); + (new ScreenConfigData(new Vector3i(getBlockPos()), side, scr)).updateOnly().sendTo(point(level, getBlockPos())); + setChanged(); + } + } + + public void type(BlockSide side, String text, BlockPos soundPos) { + type(side, text, soundPos, null); + } + + public void type(BlockSide side, String text, BlockPos soundPos, @Nullable ServerPlayer sender) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to type on invalid screen on side %s", side.toString()); + return; + } + + if (level.isClientSide) { + if (scr.browser instanceof MCEFBrowser mcefBrowser) { + try { + if (text.startsWith("t")) { + for (int i = 1; i < text.length(); i++) { + char chr = text.charAt(i); + if (chr == 1) + break; + + mcefBrowser.sendKeyTyped(chr, 0); + } + } else { + TypeData[] data = WebDisplays.GSON.fromJson(text, TypeData[].class); + + for (TypeData ev : data) { + if (ev.getKeyCode() == 257) { + ev = new TypeData( + ev.getAction(), + 10, ev.getModifier(), + ev.getScanCode() + ); + } + + switch (ev.getAction()) { + case PRESS -> { + mcefBrowser.sendKeyPress(ev.getKeyCode(), ev.getScanCode(), ev.getModifier()); + if (ev.getKeyCode() == 10) + mcefBrowser.sendKeyTyped('\r', ev.getModifier()); + } + case RELEASE -> + mcefBrowser.sendKeyRelease(ev.getKeyCode(), ev.getScanCode(), ev.getModifier()); + case TYPE -> + mcefBrowser.sendKeyTyped((char) ev.getKeyCode(), ev.getModifier()); // TODO: check + + default -> throw new RuntimeException("Invalid type action '" + ev.getAction() + '\''); + } + } + } + } catch (Throwable t) { + Log.warningEx("Suspicious keyboard type packet received...", t); + } + } + } else { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with( + sender != null ? + () -> point(sender, level, getBlockPos()) : + () -> point(level, getBlockPos()) + ), S2CMessageScreenUpdate.type(this, side, text)); + + if (soundPos != null) + playSoundAt(WebDisplays.INSTANCE.soundTyping, soundPos, 0.25f, 1.f); + } + } + + private void playSoundAt(SoundEvent snd, BlockPos at, float vol, float pitch) { + double x = at.getX(); + double y = at.getY(); + double z = at.getZ(); + + level.playSound(null, x + 0.5, y + 0.5, z + 0.5, snd, SoundSource.BLOCKS, vol, pitch); + } + // public void updateUpgrades(BlockSide side, ItemStack[] upgrades) { // if (!level.isClientSide) { // Log.error("Tried to call TileEntityScreen.updateUpgrades() from server side..."); @@ -957,262 +958,264 @@ public class TileEntityScreen extends BlockEntity { // if (scr.browser != null) // scr.browser.runJS("if(typeof webdisplaysUpgradesChanged == \"function\") webdisplaysUpgradesChanged();", ""); // } - - private static String safeName(ItemStack is) { - return is.getItem().getName(is).getString(); - } - - //If equal is null, no duplicate check is preformed - public boolean addUpgrade(BlockSide side, ItemStack is, @Nullable Player player, boolean abortIfExisting) { - if (level.isClientSide) { - IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); - Screen scr = getScreen(side); + + private static String safeName(ItemStack is) { + return is.getItem().getName(is).getString(); + } + + //If equal is null, no duplicate check is preformed + public boolean addUpgrade(BlockSide side, ItemStack is, @Nullable Player player, boolean abortIfExisting) { + if (level.isClientSide) { + IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); + Screen scr = getScreen(side); // if (abortIfExisting && scr.upgrades.stream().anyMatch(otherStack -> itemAsUpgrade.isSameUpgrade(is, otherStack))) // return false; //Upgrade already exists - ItemStack isCopy = is.copy(); //FIXME: Duct tape fix, because the original stack will be shrinked - scr.upgrades.add(isCopy); - itemAsUpgrade.onInstall(this, side, player, isCopy); - return false; - } - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to add an upgrade on invalid screen on side %s", side.toString()); - return false; - } - - if (!(is.getItem() instanceof IUpgrade)) { - Log.error("Tried to add a non-upgrade item %s to screen (%s does not implement IUpgrade)", safeName(is), is.getItem().getClass().getCanonicalName()); - return false; - } - - if (scr.upgrades.size() >= 16) { - Log.error("Can't insert upgrade %s in screen %s at %s: too many upgrades already!", safeName(is), side.toString(), getBlockPos().toString()); - return false; - } - - IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); - if (abortIfExisting && scr.upgrades.stream().anyMatch(otherStack -> itemAsUpgrade.isSameUpgrade(is, otherStack))) - return false; //Upgrade already exists - - ItemStack isCopy = is.copy(); //FIXME: Duct tape fix, because the original stack will be shrinked - isCopy.setCount(1); - - scr.upgrades.add(isCopy); - if (player != null && !player.level().isClientSide) { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.upgrade(this, side, true, is)); - itemAsUpgrade.onInstall(this, side, player, isCopy); - playSoundAt(WebDisplays.INSTANCE.soundUpgradeAdd, getBlockPos(), 1.0f, 1.0f); - } - setChanged(); - return true; - } - - public boolean hasUpgrade(BlockSide side, ItemStack is) { - Screen scr = getScreen(side); - if (scr == null) - return false; - - if (!(is.getItem() instanceof IUpgrade)) - return false; - - IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); - return scr.upgrades.stream().anyMatch(otherStack -> itemAsUpgrade.isSameUpgrade(is, otherStack)); - } - - public boolean hasUpgrade(BlockSide side, DefaultUpgrade du) { - Screen scr = getScreen(side); - if (du == DefaultUpgrade.LASERMOUSE) { - return scr != null && scr.upgrades.stream().anyMatch(du::matchesLaserMouse); - } else if (du == DefaultUpgrade.REDINPUT) { - return scr != null && scr.upgrades.stream().anyMatch(du::matchesRedInput); - } else if (du == DefaultUpgrade.GPS) { - return scr != null && scr.upgrades.stream().anyMatch(du::matchesGps); - } else if (du == DefaultUpgrade.REDOUTPUT) { - return scr != null && scr.upgrades.stream().anyMatch(du::matchesRedOutput); - } else { - return false; - } - } - - public void removeUpgrade(BlockSide side, ItemStack is, @Nullable Player player) { - if (level.isClientSide) - return; - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Tried to remove an upgrade on invalid screen on side %s", side.toString()); - return; - } - - if (!(is.getItem() instanceof IUpgrade)) { - Log.error("Tried to remove a non-upgrade item %s to screen (%s does not implement IUpgrade)", safeName(is), is.getItem().getClass().getCanonicalName()); - return; - } - - int idxToRemove = -1; - IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); - - for (int i = 0; i < scr.upgrades.size(); i++) { - if (itemAsUpgrade.isSameUpgrade(is, scr.upgrades.get(i))) { - idxToRemove = i; - break; - } - } - - if (idxToRemove >= 0) { - dropUpgrade(scr.upgrades.get(idxToRemove), side, player); - scr.upgrades.remove(idxToRemove); - if (player != null && !player.level().isClientSide) { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.upgrade(this, side, false, is)); - playSoundAt(WebDisplays.INSTANCE.soundUpgradeDel, getBlockPos(), 1.0f, 1.0f); - } - setChanged(); - } else - Log.warning("Tried to remove non-existing upgrade %s to screen %s at %s", safeName(is), side.toString(), getBlockPos().toString()); - } - - private void dropUpgrade(ItemStack is, BlockSide side, @Nullable Player ply) { - if (!((IUpgrade) is.getItem()).onRemove(this, side, ply, is)) { //Drop upgrade item - boolean spawnDrop = true; - - if (ply != null) { - if (ply.isCreative() || ply.addItem(is)) - spawnDrop = false; //If in creative or if the item was added to the player's inventory, don't spawn drop entity - } - - if (spawnDrop) { - Vector3f pos = new Vector3f((float) this.getBlockPos().getX(), (float) this.getBlockPos().getY(), (float) this.getBlockPos().getZ()); - pos.addMul(side.backward.toFloat(), 1.5f); - - if (level != null) { - level.addFreshEntity(new ItemEntity(level, pos.x, pos.y, pos.z, is)); - } - } - } - } - - private Screen getScreenForLaserOp(BlockSide side, Player ply) { - if (level.isClientSide) - return null; - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Called laser operation on invalid screen on side %s", side.toString()); - return null; - } - - 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)) { - Log.error("Called laser operation on side %s, but it's missing the laser sensor upgrade", side.toString()); - return null; - } - - return scr; //Okay, go for it... - } - - public void laserDownMove(BlockSide side, Player ply, Vector2i pos, boolean down, int button) { - Screen scr = getScreenForLaserOp(side, ply); - - if (scr != null) { - if (button == -1) - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.MOVE, pos)); - else if (down) - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.DOWN, pos)); - else - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.UP, pos)); - } - } - - public void laserUp(BlockSide side, Player ply, int button) { - Screen scr = getScreenForLaserOp(side, ply); - - if (scr != null) { - if (getLaserUser(scr) == ply) { - scr.laserUser = null; - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.UP, null)); - } - } - } - - public void onDestroy(@Nullable Player ply) { - for (Screen scr : screens) { - scr.upgrades.forEach(is -> dropUpgrade(is, scr.side, ply)); - scr.upgrades.clear(); - } - - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.turnOff(getBlockPos(), null)); - } + ItemStack isCopy = is.copy(); //FIXME: Duct tape fix, because the original stack will be shrinked + scr.upgrades.add(isCopy); + itemAsUpgrade.onInstall(this, side, player, isCopy); + return false; + } - public void disableScreen(BlockSide side) { - Screen remove = null; - for (Screen screen : screens) { - if (screen.side == side) { - remove = screen; - break; - } - } + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to add an upgrade on invalid screen on side %s", side.toString()); + return false; + } - if (remove == null) return; + if (!(is.getItem() instanceof IUpgrade)) { + Log.error("Tried to add a non-upgrade item %s to screen (%s does not implement IUpgrade)", safeName(is), is.getItem().getClass().getCanonicalName()); + return false; + } - if (level != null && !level.isClientSide) { - final Screen scrn = remove; - remove.upgrades.forEach(is -> dropUpgrade(is, scrn.side, null)); - } + if (scr.upgrades.size() >= 16) { + Log.error("Can't insert upgrade %s in screen %s at %s: too many upgrades already!", safeName(is), side.toString(), getBlockPos().toString()); + return false; + } + + IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); + if (abortIfExisting && scr.upgrades.stream().anyMatch(otherStack -> itemAsUpgrade.isSameUpgrade(is, otherStack))) + return false; //Upgrade already exists + + ItemStack isCopy = is.copy(); //FIXME: Duct tape fix, because the original stack will be shrinked + isCopy.setCount(1); + + scr.upgrades.add(isCopy); + if (player != null && !player.level().isClientSide) { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.upgrade(this, side, true, is)); + itemAsUpgrade.onInstall(this, side, player, isCopy); + playSoundAt(WebDisplays.INSTANCE.soundUpgradeAdd, getBlockPos(), 1.0f, 1.0f); + } + setChanged(); + return true; + } + + public boolean hasUpgrade(BlockSide side, ItemStack is) { + Screen scr = getScreen(side); + if (scr == null) + return false; + + if (!(is.getItem() instanceof IUpgrade)) + return false; + + IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); + return scr.upgrades.stream().anyMatch(otherStack -> itemAsUpgrade.isSameUpgrade(is, otherStack)); + } + + public boolean hasUpgrade(BlockSide side, DefaultUpgrade du) { + Screen scr = getScreen(side); + if (du == DefaultUpgrade.LASERMOUSE) { + return scr != null && scr.upgrades.stream().anyMatch(du::matchesLaserMouse); + } else if (du == DefaultUpgrade.REDINPUT) { + return scr != null && scr.upgrades.stream().anyMatch(du::matchesRedInput); + } else if (du == DefaultUpgrade.GPS) { + return scr != null && scr.upgrades.stream().anyMatch(du::matchesGps); + } else if (du == DefaultUpgrade.REDOUTPUT) { + return scr != null && scr.upgrades.stream().anyMatch(du::matchesRedOutput); + } else { + return false; + } + } + + public void removeUpgrade(BlockSide side, ItemStack is, @Nullable Player player) { + if (level.isClientSide) + return; + + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Tried to remove an upgrade on invalid screen on side %s", side.toString()); + return; + } + + if (!(is.getItem() instanceof IUpgrade)) { + Log.error("Tried to remove a non-upgrade item %s to screen (%s does not implement IUpgrade)", safeName(is), is.getItem().getClass().getCanonicalName()); + return; + } + + int idxToRemove = -1; + IUpgrade itemAsUpgrade = (IUpgrade) is.getItem(); + + for (int i = 0; i < scr.upgrades.size(); i++) { + if (itemAsUpgrade.isSameUpgrade(is, scr.upgrades.get(i))) { + idxToRemove = i; + break; + } + } + + if (idxToRemove >= 0) { + dropUpgrade(scr.upgrades.get(idxToRemove), side, player); + scr.upgrades.remove(idxToRemove); + if (player != null && !player.level().isClientSide) { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.upgrade(this, side, false, is)); + playSoundAt(WebDisplays.INSTANCE.soundUpgradeDel, getBlockPos(), 1.0f, 1.0f); + } + setChanged(); + } else + Log.warning("Tried to remove non-existing upgrade %s to screen %s at %s", safeName(is), side.toString(), getBlockPos().toString()); + } + + private void dropUpgrade(ItemStack is, BlockSide side, @Nullable Player ply) { + if (!((IUpgrade) is.getItem()).onRemove(this, side, ply, is)) { //Drop upgrade item + boolean spawnDrop = true; + + if (ply != null) { + if (ply.isCreative() || ply.addItem(is)) + spawnDrop = false; //If in creative or if the item was added to the player's inventory, don't spawn drop entity + } + + if (spawnDrop) { + Vector3f pos = new Vector3f((float) this.getBlockPos().getX(), (float) this.getBlockPos().getY(), (float) this.getBlockPos().getZ()); + pos.addMul(side.backward.toFloat(), 1.5f); + + if (level != null) { + level.addFreshEntity(new ItemEntity(level, pos.x, pos.y, pos.z, is)); + } + } + } + } + + private Screen getScreenForLaserOp(BlockSide side, Player ply) { + if (level.isClientSide) + return null; + + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Called laser operation on invalid screen on side %s", side.toString()); + return null; + } + + 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)) { + Log.error("Called laser operation on side %s, but it's missing the laser sensor upgrade", side.toString()); + return null; + } + + return scr; //Okay, go for it... + } + + public void laserDownMove(BlockSide side, Player ply, Vector2i pos, boolean down, int button) { + Screen scr = getScreenForLaserOp(side, ply); + + if (scr != null) { + if (button == -1) + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.MOVE, pos)); + else if (down) + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.DOWN, pos)); + else + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.UP, pos)); + } + } + + public void laserUp(BlockSide side, Player ply, int button) { + Screen scr = getScreenForLaserOp(side, ply); + + if (scr != null) { + if (getLaserUser(scr) == ply) { + scr.laserUser = null; + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(ply, level, getBlockPos())), S2CMessageScreenUpdate.click(this, side, ClickControl.ControlType.UP, null)); + } + } + } + + public void onDestroy(@Nullable Player ply) { + for (Screen scr : screens) { + scr.upgrades.forEach(is -> dropUpgrade(is, scr.side, ply)); + scr.upgrades.clear(); + } + + 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(); + if (remove.browser != null) + remove.browser.close(true); + screens.remove(remove); + } + + public void setOwner(BlockSide side, Player newOwner) { + if (level.isClientSide) { + Log.error("Called TileEntityScreen.setOwner() on client..."); + return; + } + + if (newOwner == null) { + Log.error("Called TileEntityScreen.setOwner() with null owner"); + return; + } + + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Called TileEntityScreen.setOwner() on invalid screen on side %s", side.toString()); + return; + } + + scr.owner = new NameUUIDPair(newOwner.getGameProfile()); + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.owner(this, side, scr.owner)); + checkLaserUserRights(scr); + setChanged(); + } + + public void setRotation(BlockSide side, Rotation rot) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Trying to change rotation of invalid screen on side %s", side.toString()); + return; + } + + if (level.isClientSide) { + boolean oldWasVertical = scr.rotation.isVertical; + scr.rotation = rot; + + WebDisplays.PROXY.screenUpdateRotationInGui(new Vector3i(getBlockPos()), side, rot); + + if (scr.browser != null && oldWasVertical != rot.isVertical) { + scr.browser.close(true); + scr.browser = null; //Will be re-created by renderer + } + } else { + scr.rotation = rot; + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.rotation(this, side, rot)); + setChanged(); + } + } - remove.upgrades.clear(); - screens.remove(remove); - } - - public void setOwner(BlockSide side, Player newOwner) { - if (level.isClientSide) { - Log.error("Called TileEntityScreen.setOwner() on client..."); - return; - } - - if (newOwner == null) { - Log.error("Called TileEntityScreen.setOwner() with null owner"); - return; - } - - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Called TileEntityScreen.setOwner() on invalid screen on side %s", side.toString()); - return; - } - - scr.owner = new NameUUIDPair(newOwner.getGameProfile()); - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.owner(this, side, scr.owner)); - checkLaserUserRights(scr); - setChanged(); - } - - public void setRotation(BlockSide side, Rotation rot) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Trying to change rotation of invalid screen on side %s", side.toString()); - return; - } - - if (level.isClientSide) { - boolean oldWasVertical = scr.rotation.isVertical; - scr.rotation = rot; - - WebDisplays.PROXY.screenUpdateRotationInGui(new Vector3i(getBlockPos()), side, rot); - - if (scr.browser != null && oldWasVertical != rot.isVertical) { - scr.browser.close(true); - scr.browser = null; //Will be re-created by renderer - } - } else { - scr.rotation = rot; - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.rotation(this, side, rot)); - setChanged(); - } - } - // public void evalJS(BlockSide side, String code) { // Screen scr = getScreen(side); // if (scr == null) { @@ -1226,23 +1229,23 @@ public class TileEntityScreen extends BlockEntity { // } //// else WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.js(this, side, code)); // } - - public void setAutoVolume(BlockSide side, boolean av) { - Screen scr = getScreen(side); - if (scr == null) { - Log.error("Trying to toggle auto-volume on invalid screen (side %s)", side.toString()); - return; - } - - scr.autoVolume = av; - - if (level.isClientSide) - WebDisplays.PROXY.screenUpdateAutoVolumeInGui(new Vector3i(getBlockPos()), side, av); - else { - WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.autoVolume(this, side, av)); - setChanged(); - } - } + + public void setAutoVolume(BlockSide side, boolean av) { + Screen scr = getScreen(side); + if (scr == null) { + Log.error("Trying to toggle auto-volume on invalid screen (side %s)", side.toString()); + return; + } + + scr.autoVolume = av; + + if (level.isClientSide) + WebDisplays.PROXY.screenUpdateAutoVolumeInGui(new Vector3i(getBlockPos()), side, av); + else { + WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(level, getBlockPos())), S2CMessageScreenUpdate.autoVolume(this, side, av)); + setChanged(); + } + } // @Override