From f94ee494770918644891dcc2b151980ac1938f5e Mon Sep 17 00:00:00 2001 From: Tairitsu <2649111464@qq.com> Date: Wed, 13 Nov 2024 00:03:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9A=84=E4=BA=86=E4=B8=8D?= =?UTF-8?q?=E5=B0=91=E4=B8=9C=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 全息屏带宽占用优化(增量更新+数据压缩) 玻璃屏幕字符剔除支持(保留背景色把字扣掉) 添加实用的物理帧数据 --- build.gradle | 22 +- gradle.properties | 2 +- .../assets/void_power/lang/en_us.json | 1 + .../assets/void_power/lang/zh_cn.json | 3 +- .../java/com/dfdyz/void_power/Config.java | 33 +- .../com/dfdyz/void_power/VoidPowerMod.java | 9 +- .../void_power/client/gui/HologramGUI.java | 44 +- .../gui/widget/HologramTerminalWidget.java | 19 +- .../client/renderer/VPRenderTypes.java | 11 +- .../renderer/hud/VRGlassesHUDRenderer.java | 202 +++++ .../glass_screen/GlassScreenRenderState.java | 137 +++ .../glass_screen/ScreenRenderUtils.java | 91 +- .../glass_screen/ScreenRenderer.java | 29 +- .../hologram/HologramRenderer.java | 8 +- .../client/screen_cache/ScreenCacheImpl.java | 6 +- .../compat/cct/lua/LuaPhysShip.java | 71 +- .../cct/peripherals/P_EngineController.java | 55 +- .../cct/peripherals/P_HologramPeripheral.java | 825 ++++++++++++++---- .../dfdyz/void_power/events/InputEvents.java | 23 + .../dfdyz/void_power/events/RenderEvent.java | 38 +- .../dfdyz/void_power/loader/FontLoader.java | 25 + .../dfdyz/void_power/menu/HologramMenu.java | 5 +- .../void_power/mixin/MixinBugFixUtils_Kt.java | 6 +- .../void_power/mixin/MixinComputerTE.java | 29 + .../mixin/MixinPeripheralProxyTE_Kt.java | 8 +- .../void_power/network/PacketManager.java | 17 +- .../network/SP/SP_HologramRename.java | 2 - .../network/SP/SP_HologramUpdate.java | 89 -- .../network/SP/SP_HologramUpdate_A.java | 107 +++ .../network/SP/SP_HologramUpdate_B.java | 100 +++ .../dfdyz/void_power/registry/VPItems.java | 17 +- .../dfdyz/void_power/registry/VPKeyBinds.java | 46 + .../com/dfdyz/void_power/utils/ByteUtils.java | 55 ++ .../com/dfdyz/void_power/utils/Debug.java | 6 - .../com/dfdyz/void_power/utils/IntBuffer.java | 30 + .../com/dfdyz/void_power/utils/NBTUtils.java | 30 + .../dfdyz/void_power/utils/ParamUtils.java | 27 +- .../dfdyz/void_power/utils/RaycastUtils.java | 14 + .../dfdyz/void_power/utils/SyncLocker.java | 14 +- .../com/dfdyz/void_power/utils/VSUtils.java | 2 +- .../dfdyz/void_power/utils/font/ASCII.java | 4 - .../void_power/utils/font/DefaultFont.java | 12 + .../com/dfdyz/void_power/utils/font/Font.java | 37 +- .../dfdyz/void_power/utils/font/FontLib.java | 60 ++ .../dfdyz/void_power/utils/font/IFontLib.java | 7 + .../hologram/DefaultFrameBufferImpl.java | 44 + .../world/blocks/hologram/HologramTE.java | 385 ++++++-- .../world/blocks/hologram/IFrameBuffer.java | 17 + .../blocks/void_engine/VoidEngineBlock.java | 5 +- .../void_power/world/items/VRGlassesItem.java | 79 ++ .../world/physics/HologramClickManager.java | 126 +++ .../assets/void_power/lang/backup/en_us.json | 4 +- .../assets/void_power/lang/backup/zh_cn.json | 4 +- .../void_power/models/item/vr_glasses.json | 6 + .../textures/block/term_font_neg.png | Bin 0 -> 3856 bytes .../textures/gui/hud/vr_glasses_no_signal.png | Bin 0 -> 3108 bytes .../void_power/textures/item/vr_glasses.png | Bin 0 -> 243 bytes .../models/armor/vr_glasses_layer_1.png | Bin 0 -> 192 bytes .../dfdyz/void_power/utils/font}/hzk16.bin | Bin ...hologram_screen.json => glass_screen.json} | 0 .../recipes/machanical_crafting/hologram.json | 35 + src/main/resources/mixins.void_power.json | 1 - 62 files changed, 2601 insertions(+), 483 deletions(-) create mode 100644 src/main/java/com/dfdyz/void_power/client/renderer/hud/VRGlassesHUDRenderer.java create mode 100644 src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/GlassScreenRenderState.java create mode 100644 src/main/java/com/dfdyz/void_power/events/InputEvents.java create mode 100644 src/main/java/com/dfdyz/void_power/loader/FontLoader.java create mode 100644 src/main/java/com/dfdyz/void_power/mixin/MixinComputerTE.java delete mode 100644 src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate.java create mode 100644 src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_A.java create mode 100644 src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_B.java create mode 100644 src/main/java/com/dfdyz/void_power/registry/VPKeyBinds.java create mode 100644 src/main/java/com/dfdyz/void_power/utils/IntBuffer.java create mode 100644 src/main/java/com/dfdyz/void_power/utils/NBTUtils.java create mode 100644 src/main/java/com/dfdyz/void_power/utils/font/DefaultFont.java create mode 100644 src/main/java/com/dfdyz/void_power/utils/font/FontLib.java create mode 100644 src/main/java/com/dfdyz/void_power/utils/font/IFontLib.java create mode 100644 src/main/java/com/dfdyz/void_power/world/blocks/hologram/DefaultFrameBufferImpl.java create mode 100644 src/main/java/com/dfdyz/void_power/world/blocks/hologram/IFrameBuffer.java create mode 100644 src/main/java/com/dfdyz/void_power/world/items/VRGlassesItem.java create mode 100644 src/main/java/com/dfdyz/void_power/world/physics/HologramClickManager.java create mode 100644 src/main/resources/assets/void_power/models/item/vr_glasses.json create mode 100644 src/main/resources/assets/void_power/textures/block/term_font_neg.png create mode 100644 src/main/resources/assets/void_power/textures/gui/hud/vr_glasses_no_signal.png create mode 100644 src/main/resources/assets/void_power/textures/item/vr_glasses.png create mode 100644 src/main/resources/assets/void_power/textures/models/armor/vr_glasses_layer_1.png rename src/main/resources/{assets/void_power/vp_font => com/dfdyz/void_power/utils/font}/hzk16.bin (100%) rename src/main/resources/data/void_power/recipes/crafting/{hologram_screen.json => glass_screen.json} (100%) create mode 100644 src/main/resources/data/void_power/recipes/machanical_crafting/hologram.json diff --git a/build.gradle b/build.gradle index 6139bbc..21f0713 100644 --- a/build.gradle +++ b/build.gradle @@ -133,6 +133,13 @@ repositories { dir 'libs' } + maven { + url "https://cursemaven.com" + content { + includeGroup "curse.maven" + } + } + maven { url = 'https://maven.minecraftforge.net' } maven { name = 'tterrag maven' @@ -146,15 +153,6 @@ repositories { maven { url 'https://maven.valkyrienskies.org/' } - - // Add KFF Maven repository - maven { - url "https://cursemaven.com" - content { - includeGroup "curse.maven" - } - } - repositories { maven { url = "https://maven.bawnorton.com/releases" } } @@ -199,7 +197,7 @@ dependencies { implementation("org.joml:joml-primitives:1.10.0") { transitive = false } // cc:t dependencies - implementation fg.deobf("curse.maven:cc-tweaked-282001:5379173") + implementation fg.deobf("curse.maven:cc-tweaked-282001:5714507") // implementation fg.deobf("libs:peripheralium-forge:1.20.1-0.6.15") @@ -216,7 +214,9 @@ dependencies { // Toms peripheral //implementation fg.deobf("curse.maven:toms-peripheral-931210:5265063") - + // VS CW + runtimeOnly fg.deobf("curse.maven:architectury-api-419699:5137938") + runtimeOnly fg.deobf("curse.maven:clockwork-807792:5580456") annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings diff --git a/gradle.properties b/gradle.properties index 6bb051e..c7d0045 100644 --- a/gradle.properties +++ b/gradle.properties @@ -48,7 +48,7 @@ mod_name=VoidPower # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPL3 # The mod version. See https://semver.org/ -mod_version=1.1.1 +mod_version=1.2.5.alpha4 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/generated/resources/assets/void_power/lang/en_us.json b/src/generated/resources/assets/void_power/lang/en_us.json index 4625e76..e9271b9 100644 --- a/src/generated/resources/assets/void_power/lang/en_us.json +++ b/src/generated/resources/assets/void_power/lang/en_us.json @@ -3,6 +3,7 @@ "block.void_power.void_engine": "Void Engine", "block.void_power.glass_screen":"GlassScreen", "block.void_power.hologram":"Hologram", + "item.void_power.vr_glasses": "VR Glasses", "itemGroup.void_power.main": "Void Power", "gui.void_power.terminal" : "HOLOGRAM" } \ No newline at end of file diff --git a/src/generated/resources/assets/void_power/lang/zh_cn.json b/src/generated/resources/assets/void_power/lang/zh_cn.json index 0701539..081f5d2 100644 --- a/src/generated/resources/assets/void_power/lang/zh_cn.json +++ b/src/generated/resources/assets/void_power/lang/zh_cn.json @@ -3,6 +3,7 @@ "block.void_power.void_engine": "虚空引擎", "block.void_power.glass_screen":"玻璃屏幕(电脑外设)", "block.void_power.hologram":"全息显示器", + "item.void_power.vr_glasses": "VR眼镜", "itemGroup.void_power.main": "虚空动力", - "gui.void_power.terminal" : "HOLOGRAM" + "gui.void_power.terminal" : "全息显示器(终端)" } \ No newline at end of file diff --git a/src/main/java/com/dfdyz/void_power/Config.java b/src/main/java/com/dfdyz/void_power/Config.java index c733bbb..5cd6ecc 100644 --- a/src/main/java/com/dfdyz/void_power/Config.java +++ b/src/main/java/com/dfdyz/void_power/Config.java @@ -46,11 +46,29 @@ public class Config private static final ForgeConfigSpec.IntValue HOLOGRAM_RES_X_MAX = BUILDER .comment("Max width can set for a hologram.") - .defineInRange("HOLOGRAM_WIDTH_MAX", 1024, 128, 4096); + .defineInRange("HOLOGRAM_WIDTH_MAX", 1024, 128, 2048); private static final ForgeConfigSpec.IntValue HOLOGRAM_RES_Y_MAX = BUILDER .comment("Max height can set for a hologram..") - .defineInRange("HOLOGRAM_HEIGHT_MAX", 1024, 128, 4096); + .defineInRange("HOLOGRAM_HEIGHT_MAX", 1024, 128, 2048); + + private static final ForgeConfigSpec.IntValue HOLOGRAM_BUFFER_COUNT = BUILDER + .comment("Max count of frame buffer in a hologram.") + .defineInRange("HOLOGRAM_BUFFER_COUNT", 8, 2, 32); + + + private static final ForgeConfigSpec.BooleanValue WIRELESS_HUB_UNLIMITED = BUILDER + .comment("Remove wireless peripheral hub distance limited.") + .define("WIRELESS_HUB_UNLIMITED", true); + + private static final ForgeConfigSpec.IntValue HOLOGRAM_FONT_COUNT = BUILDER + .comment("Max count of font for a hologram.") + .defineInRange("HOLOGRAM_FONT_COUNT", 2, 0, 8); + + private static final ForgeConfigSpec.IntValue HOLOGRAM_FORCE_FULL_UPDATE_TICK = BUILDER + .comment("The max ticks between two sync(a tick after a call of 'hologram.Flush()') of hologram. set zero to disable forced full update.") + .defineInRange("HOLOGRAM_FORCE_FULL_UPDATE_TICK", 20, 0, 40); + static final ForgeConfigSpec SPEC = BUILDER.build(); @@ -59,10 +77,16 @@ public class Config public static double DefaultMinPeriodFactor = 1; public static boolean ForceUseVanillaShader = false; public static boolean ResetControllerWhileLeft = true; + public static int HologramFontCount = 2; + + public static int HologramMaxBufferCount = 8; + public static int ForceFullUpdateTick = 2; public static int holo_w_mx = 1024; public static int holo_h_mx = 1024; + public static boolean UnlimitDistance = true; + private static boolean validateItemName(final Object obj) { return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName)); @@ -77,9 +101,14 @@ static void onLoad(final ModConfigEvent event) ForceUseVanillaShader = SCREEN_FORCED_USE_VANILLA_SHADER.get().booleanValue(); ResetControllerWhileLeft = RESET_CONTROLLER_WHEN_LEFT.get().booleanValue(); + UnlimitDistance = WIRELESS_HUB_UNLIMITED.get(); + holo_w_mx = HOLOGRAM_RES_X_MAX.get(); holo_h_mx = HOLOGRAM_RES_Y_MAX.get(); + HologramMaxBufferCount = HOLOGRAM_BUFFER_COUNT.get(); + HologramFontCount = HOLOGRAM_FONT_COUNT.get(); + ForceFullUpdateTick = HOLOGRAM_FORCE_FULL_UPDATE_TICK.get(); } } diff --git a/src/main/java/com/dfdyz/void_power/VoidPowerMod.java b/src/main/java/com/dfdyz/void_power/VoidPowerMod.java index 52807d8..c82d9ce 100644 --- a/src/main/java/com/dfdyz/void_power/VoidPowerMod.java +++ b/src/main/java/com/dfdyz/void_power/VoidPowerMod.java @@ -13,7 +13,9 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; import net.minecraftforge.event.server.ServerStartedEvent; @@ -71,6 +73,8 @@ private void commonSetup(final FMLCommonSetupEvent event) //LOGGER.info("HELLO FROM COMMON SETUP"); } + + private void clientSetup(FMLClientSetupEvent event) { /* @@ -91,10 +95,13 @@ private void addCreative(BuildCreativeModeTabContentsEvent event) @SubscribeEvent public void onServerStarted(ServerStartedEvent event){ - LOGGER.error("ServerStarted."); + //LOGGER.error("ServerStarted."); CCUtils.context = ServerContext.get(event.getServer()); } + public static ResourceLocation getRL(String sub){ + return new ResourceLocation(MODID, sub); + } // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent //@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) diff --git a/src/main/java/com/dfdyz/void_power/client/gui/HologramGUI.java b/src/main/java/com/dfdyz/void_power/client/gui/HologramGUI.java index 9bd368e..118fd93 100644 --- a/src/main/java/com/dfdyz/void_power/client/gui/HologramGUI.java +++ b/src/main/java/com/dfdyz/void_power/client/gui/HologramGUI.java @@ -35,21 +35,28 @@ public HologramGUI(HologramMenu menu, Inventory inventory, Component p_97743_) { float GetScale(){ float w = 0.5f,h = 0.25f; - if (te.high <= 64) h = 2; - else if (te.high <= 128) h = 1; - else if (te.high <= 256) h = 0.5f; - - if (te.width <= 64) w = 4; - else if (te.width <= 128) w = 2; - else if (te.width <= 256) w = 1; + + int wi = te.getWidth(); + int hi = te.getHeight(); + + + if (hi <= 64) h = 2; + else if (hi <= 128) h = 1; + else if (hi <= 256) h = 0.5f; + + if (wi <= 64) w = 4; + else if (wi <= 128) w = 2; + else if (wi <= 256) w = 1; return Math.min(w, h); } HologramTerminalWidget getTerminal(){ terminal_scale = GetScale(); - int w = (int) (te.width * terminal_scale); - int h = (int) (te.high * terminal_scale); + int wi = te.getWidth(); + int hi = te.getHeight(); + int w = (int) (wi * terminal_scale); + int h = (int) (hi * terminal_scale); return addRenderableWidget( new HologramTerminalWidget(te, (width - w) / 2, (height - h) / 2, w, h) ); @@ -61,14 +68,14 @@ protected void init() { htw = addRenderableWidget(getTerminal()); name_editor = addRenderableWidget( - new EditBox(font, width / 2 - 128 - 20, htw.getY() - 30, 254, 16, + new EditBox(font, width / 2 - 128 - 20, 1, 254, 16, Component.literal("NAME")) ); name_editor.setValue(te.name); set_name = addRenderableWidget(Button.builder(Component.literal("Set"), this::ChangeName) - .pos(width / 2 + 128-20, htw.getY() - 31) + .pos(width / 2 + 128-20, 1) .size(40,18) .build()); @@ -89,15 +96,22 @@ public void tick() { } if(htw.ShouldResize()){ terminal_scale = GetScale(); - int w = (int) (te.width * terminal_scale); - int h = (int) (te.high * terminal_scale); + int w = (int) (te.getWidth() * terminal_scale); + int h = (int) (te.getHeight() * terminal_scale); htw.setX((width - w) / 2); htw.setY((height - h) / 2); htw.setHeight(h); htw.setWidth(w); - name_editor.setY(htw.getY() - 30); - set_name.setY(htw.getY() - 31); + if(htw.getY() + 29 < set_name.getHeight()){ + name_editor.setY(htw.getY() - 30); + set_name.setY(htw.getY() - 31); + } + else { + name_editor.setY(1); + set_name.setY(1); + } + } //htw.setFocused(true); } diff --git a/src/main/java/com/dfdyz/void_power/client/gui/widget/HologramTerminalWidget.java b/src/main/java/com/dfdyz/void_power/client/gui/widget/HologramTerminalWidget.java index 782d094..dc28272 100644 --- a/src/main/java/com/dfdyz/void_power/client/gui/widget/HologramTerminalWidget.java +++ b/src/main/java/com/dfdyz/void_power/client/gui/widget/HologramTerminalWidget.java @@ -10,6 +10,7 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; import java.util.BitSet; @@ -25,13 +26,13 @@ public HologramTerminalWidget(HologramTE te, int x, int y, int w, int h) { } public boolean ShouldResize(){ - return te.width != this.width || te.high != this.height; + return te.getWidth() != this.width || te.getHeight() != this.height; } @Override protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { if (this.visible) { - if (te.buffer.length == 0)return; + if (te.getBuffer().length == 0)return; if (te.renderCache == null)te.renderCache = new ScreenCacheImpl(te); ResourceLocation tex = te.renderCache.getTexture();; if (tex == null)return; @@ -42,7 +43,7 @@ protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, flo } @Override - protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { + protected void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { } @@ -122,8 +123,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { if (!this.inRegion(mouseX, mouseY)) { return false; } else if (button >= 0 && button <= 2) { - int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.width); - int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.high); + int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.getWidth()); + int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.getHeight()); te.SendInputPack("vp_mouse_clicked", te.name, button + 1, pxX, pxY); @@ -140,8 +141,8 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { if (!this.inRegion(mouseX, mouseY)) { return false; } else if (button >= 0 && button <= 2) { - int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.width); - int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.high); + int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.getWidth()); + int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.getHeight()); if (this.lastMouseButton == button) { te.SendInputPack("vp_mouse_released", te.name, button + 1, pxX, pxY); @@ -164,8 +165,8 @@ public boolean mouseScrolled(double mouseX, double mouseY, double delta) { if (!this.inRegion(mouseX, mouseY)) { return false; } else if (delta != 0.0) { - int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.width); - int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.high); + int pxX = (int)Math.floor((mouseX - this.getX()) / width * te.getWidth()); + int pxY = (int)Math.floor((mouseY - this.getY()) / height * te.getHeight()); te.SendInputPack("vp_mouse_scrolled", te.name, delta, pxX, pxY); this.lastMouseX = pxX; diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/VPRenderTypes.java b/src/main/java/com/dfdyz/void_power/client/renderer/VPRenderTypes.java index 1f4f219..40b0e95 100644 --- a/src/main/java/com/dfdyz/void_power/client/renderer/VPRenderTypes.java +++ b/src/main/java/com/dfdyz/void_power/client/renderer/VPRenderTypes.java @@ -22,7 +22,12 @@ public class VPRenderTypes { public static final ResourceLocation FONT = new ResourceLocation(VoidPowerMod.MODID, "textures/block/term_font.png"); - public static final RenderType TERMINAL = getText(FixedWidthFontRenderer.FONT); + + public static final ResourceLocation FONT_NEG = new ResourceLocation(VoidPowerMod.MODID, "textures/block/term_font_neg.png"); + + //public static final ResourceLocation FONT = new ResourceLocation(VoidPowerMod.MODID, "textures/block/term_font.png"); + public static final RenderType TERMINAL = getText(VPRenderTypes.FONT); + public static final RenderType TERMINAL_NEG = getText(VPRenderTypes.FONT_NEG); public static final RenderType HOLOGRAM = getHologram(FixedWidthFontRenderer.FONT); @@ -70,5 +75,7 @@ public static ShaderInstance text(){ return Config.ForceUseVanillaShader ? textShader : RenderTypes.getTerminalShader(); } - + public static ShaderInstance textNeg(){ + return Config.ForceUseVanillaShader ? textShader : RenderTypes.getTerminalShader(); + } } diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/hud/VRGlassesHUDRenderer.java b/src/main/java/com/dfdyz/void_power/client/renderer/hud/VRGlassesHUDRenderer.java new file mode 100644 index 0000000..15668ed --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/client/renderer/hud/VRGlassesHUDRenderer.java @@ -0,0 +1,202 @@ +package com.dfdyz.void_power.client.renderer.hud; + + +import com.dfdyz.void_power.VoidPowerMod; +import com.dfdyz.void_power.client.screen_cache.ScreenCacheImpl; +import com.dfdyz.void_power.registry.VPItems; +import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import com.dfdyz.void_power.world.items.VRGlassesItem; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +public class VRGlassesHUDRenderer { + + public static ItemStack current_item = ItemStack.EMPTY; + public static BlockPos bp = null; + public static ResourceLocation dim = null; + + public static boolean On = false; + + static int distance_limit = 24; + + static final ResourceLocation no_signal = new ResourceLocation(VoidPowerMod.MODID, "textures/gui/hud/vr_glasses_no_signal.png"); + public static void render(LocalPlayer player, GuiGraphics guiGraphics, float partialTicks){ + if(!_render(player, guiGraphics, partialTicks)){ + // render no signal + Window sr = Minecraft.getInstance().getWindow(); + float width = sr.getGuiScaledWidth(); + float height = sr.getGuiScaledHeight(); + if(width == 0 || height == 0) return; + + float x = 0; + float y = 0; + float w = 128; + float h = 64; + + if(width * h < height * w){ + h = width * h / w; + w = width; + y = (height - h) / 2; + } + else { + w = height * w / h; + h = height; + x = (width - w) / 2; + } + + + PoseStack poseStack = guiGraphics.pose(); + poseStack.pushPose(); + poseStack.setIdentity(); + boolean depthTestEnabled = GL11.glGetBoolean(GL11.GL_DEPTH_TEST); + boolean blendEnabled = GL11.glGetBoolean(GL11.GL_BLEND); + + RenderSystem.disableCull(); + if (depthTestEnabled) { + RenderSystem.disableDepthTest(); + } + + if (!blendEnabled) { + RenderSystem.enableBlend(); + } + + RenderSystem.setShaderTexture(0, no_signal); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderColor(1,1,1, 0.1f); + + Matrix4f matrix4f = poseStack.last().pose(); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + bufferbuilder.vertex(matrix4f, x, y, 0) + .uv(0, 0).endVertex(); + bufferbuilder.vertex(matrix4f, x, y + h, 0) + .uv(0, 1).endVertex(); + bufferbuilder.vertex(matrix4f, x + w, y + h, 0) + .uv(1, 1).endVertex(); + bufferbuilder.vertex(matrix4f, x + w, y, 0) + .uv(1, 0).endVertex(); + BufferUploader.drawWithShader(bufferbuilder.end()); + + poseStack.popPose(); + } + } + + public static boolean _render(LocalPlayer player, GuiGraphics guiGraphics, float partialTicks){ + //if (player.getItemBySlot(EquipmentSlot.HEAD).getCapability()) + if(!On) return true; + if(!Minecraft.getInstance().options.getCameraType().isFirstPerson()) return true; + + if(player == null) return false; + Level level = player.level(); + if(level == null) return false; + + ItemStack ish = player.getItemBySlot(EquipmentSlot.HEAD); + + float alpha = 1; + if(!ish.is(VPItems.VR_GLASSES.get())){ + ish = player.getMainHandItem(); + alpha = 0.5f; + } + + if(!ish.is(VPItems.VR_GLASSES.get())){ + current_item = ItemStack.EMPTY; + bp = null; + dim = null; + return true; + } + + if(ish != current_item){ + bp = VRGlassesItem.getTE(player, ish); + dim = VRGlassesItem.getDim(ish); + current_item = ish; + } + + if(bp == null || dim == null) return false; + if(!player.level().dimension().location().equals(dim)) return false; + + BlockEntity te = player.level().getBlockEntity(bp); + if(te instanceof HologramTE hte){ + if(VSGameUtilsKt.squaredDistanceToInclShips(player, bp.getX(), bp.getY(), bp.getZ()) > distance_limit * distance_limit){ + return false; + } + if (hte.getBuffer().length == 0) return false; + if (hte.renderCache == null)hte.renderCache = new ScreenCacheImpl(hte); + + ResourceLocation tex = hte.renderCache.getTexture(); + if (tex == null) return false; + + Window sr = Minecraft.getInstance().getWindow(); + float width = sr.getGuiScaledWidth(); + float height = sr.getGuiScaledHeight(); + if(width == 0 || height == 0) return false; + + float x = 0; + float y = 0; + float w = hte.getWidth(); + float h = hte.getHeight(); + if(w == 0 || h == 0) return false; + + if(width * h < height * w){ + h = width * h / w; + w = width; + y = (height - h) / 2; + } + else { + w = height * w / h; + h = height; + x = (width - w) / 2; + } + + PoseStack poseStack = guiGraphics.pose(); + poseStack.pushPose(); + poseStack.setIdentity(); + boolean depthTestEnabled = GL11.glGetBoolean(GL11.GL_DEPTH_TEST); + boolean blendEnabled = GL11.glGetBoolean(GL11.GL_BLEND); + + RenderSystem.disableCull(); + if (depthTestEnabled) { + RenderSystem.disableDepthTest(); + } + + if (!blendEnabled) { + RenderSystem.enableBlend(); + } + + RenderSystem.setShaderTexture(0, tex); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderColor(1,1,1, alpha); + + Matrix4f matrix4f = poseStack.last().pose(); + BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder(); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + bufferbuilder.vertex(matrix4f, x, y, 0) + .uv(0, 0).endVertex(); + bufferbuilder.vertex(matrix4f, x, y + h, 0) + .uv(0, 1).endVertex(); + bufferbuilder.vertex(matrix4f, x + w, y + h, 0) + .uv(1, 1).endVertex(); + bufferbuilder.vertex(matrix4f, x + w, y, 0) + .uv(1, 0).endVertex(); + BufferUploader.drawWithShader(bufferbuilder.end()); + + + poseStack.popPose(); + } + return true; + } + +} diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/GlassScreenRenderState.java b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/GlassScreenRenderState.java new file mode 100644 index 0000000..6b49f5e --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/GlassScreenRenderState.java @@ -0,0 +1,137 @@ +package com.dfdyz.void_power.client.renderer.tileentities.glass_screen; + +import com.google.errorprone.annotations.concurrent.GuardedBy; +import com.mojang.blaze3d.platform.GlStateManager; +import dan200.computercraft.client.render.monitor.MonitorRenderState; +import dan200.computercraft.client.render.vbo.DirectBuffers; +import dan200.computercraft.client.render.vbo.DirectVertexBuffer; +import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; +import net.minecraft.core.BlockPos; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL31; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class GlassScreenRenderState implements ClientMonitor.RenderState{ + + @GuardedBy("allMonitors") + private static final Set allMonitors = new HashSet(); + + public long lastRenderFrame = -1L; + @Nullable + public BlockPos lastRenderPos = null; + public int tboBuffer; + public int tboTexture; + public int tboUniform; + @Nullable + public DirectVertexBuffer backgroundBuffer; + @Nullable + public DirectVertexBuffer foregroundBuffer; + @Nullable + public DirectVertexBuffer foregroundNegBuffer; + + public GlassScreenRenderState() { + } + + public boolean createBuffer(MonitorRenderer renderer) { + switch (renderer) { + case TBO: + if (this.tboBuffer != 0) { + return false; + } + + this.deleteBuffers(); + this.tboBuffer = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData(35882, this.tboBuffer, 35044); + this.tboTexture = GlStateManager._genTexture(); + GL11.glBindTexture(35882, this.tboTexture); + GL31.glTexBuffer(35882, 33330, this.tboBuffer); + GL11.glBindTexture(35882, 0); + this.tboUniform = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData(35345, this.tboUniform, 35044); + this.addMonitor(); + return true; + case VBO: + if (this.backgroundBuffer != null) { + return false; + } + + this.deleteBuffers(); + this.backgroundBuffer = new DirectVertexBuffer(); + this.foregroundBuffer = new DirectVertexBuffer(); + this.foregroundNegBuffer = new DirectVertexBuffer(); + this.addMonitor(); + return true; + default: + return false; + } + } + + + private void deleteBuffers() { + if (this.tboBuffer != 0) { + DirectBuffers.deleteBuffer(35882, this.tboBuffer); + this.tboBuffer = 0; + } + + if (this.tboTexture != 0) { + GlStateManager._deleteTexture(this.tboTexture); + this.tboTexture = 0; + } + + if (this.tboUniform != 0) { + DirectBuffers.deleteBuffer(35345, this.tboUniform); + this.tboUniform = 0; + } + + if (this.backgroundBuffer != null) { + this.backgroundBuffer.close(); + this.backgroundBuffer = null; + } + + if (this.foregroundBuffer != null) { + this.foregroundBuffer.close(); + this.foregroundBuffer = null; + } + + if (this.foregroundNegBuffer != null) { + this.foregroundNegBuffer.close(); + this.foregroundNegBuffer = null; + } + } + + private void addMonitor() { + synchronized(allMonitors) { + allMonitors.add(this); + } + } + + @Override + public void close() { + if (this.tboBuffer != 0 || this.backgroundBuffer != null) { + synchronized(allMonitors) { + allMonitors.remove(this); + } + + this.deleteBuffers(); + } + + } + + public static void destroyAll() { + synchronized(allMonitors) { + Iterator iterator = allMonitors.iterator(); + + while(iterator.hasNext()) { + GlassScreenRenderState monitor = iterator.next(); + monitor.deleteBuffers(); + iterator.remove(); + } + + } + } +} diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderUtils.java b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderUtils.java index b1dfeee..be54167 100644 --- a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderUtils.java +++ b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderUtils.java @@ -14,54 +14,104 @@ import java.nio.ByteBuffer; public class ScreenRenderUtils { - private static void drawChar(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, int index, byte[] colour) { - if (index != 0 && index != 32) { - int column = index % 16; - int row = index / 16; + private static void drawChar(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, int index, int colour) { + if (index != 0) { + int idx = index == 32 ? 128 : index; + int column = idx % 16; + int row = idx / 16; int xStart = 1 + column * 8; int yStart = 1 + row * 11; quad(emitter, x, y, x + 6.0F, y + 9.0F, 0.0F, colour, (float)xStart / 256.0F, (float)yStart / 256.0F, (float)(xStart + 6) / 256.0F, (float)(yStart + 9) / 256.0F); } } + private static void drawQuad(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, float width, float height, Palette palette, char colourIndex, char noBG_colourIdx) { if(noBG_colourIdx != colourIndex){ - byte[] colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(colourIndex, Colour.BLACK)); + int colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(colourIndex, Colour.BLACK)); quad(emitter, x, y, x + width, y + height, 0.0F, colour, 0.9765625F, 0.9765625F, 0.984375F, 0.984375F); } } private static void drawQuad(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, float width, float height, Palette palette, char colourIndex) { - byte[] colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(colourIndex, Colour.BLACK)); + int colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(colourIndex, Colour.BLACK)); quad(emitter, x, y, x + width, y + height, 0.0F, colour, 0.9765625F, 0.9765625F, 0.984375F, 0.984375F); } public static void drawString(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, TextBuffer text, TextBuffer textColour, Palette palette) { for(int i = 0; i < text.length(); ++i) { - byte[] colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(textColour.charAt(i), Colour.BLACK)); + int colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(textColour.charAt(i), Colour.BLACK)); int index = text.charAt(i); if (index > 255) { index = '?'; } + drawChar(emitter, x + (float)(i * 6), y, index, colour); + } + } + public static void drawString(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, TextBuffer text, TextBuffer textColour, Palette palette, char cull_colorIdx) { + char col = ' '; + for(int i = 0; i < text.length(); ++i) { + col = textColour.charAt(i); + if(col == cull_colorIdx) { + continue; + } + int colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(col, Colour.BLACK)); + int index = text.charAt(i); + if (index > 255) { + index = '?'; + } drawChar(emitter, x + (float)(i * 6), y, index, colour); } } - public static void drawTerminalForeground(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, Terminal terminal) { + + public static void drawStringNeg(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, TextBuffer text, TextBuffer textColour, TextBuffer bgColor, Palette palette, char cull_colorIdx) { + char col = ' ', bgcol = ' '; + for(int i = 0; i < text.length(); ++i) { + col = textColour.charAt(i); + bgcol = bgColor.charAt(i); + + if(col == cull_colorIdx && bgcol != cull_colorIdx){ + int colour = palette.getRenderColours(FixedWidthFontRenderer.getColour(bgcol, Colour.BLACK)); + int index = text.charAt(i); + if (index > 255) { + index = '?'; + } + drawChar(emitter, x + (float)(i * 6), y, index, colour); + } + } + } + + public static void drawTerminalForeground(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, Terminal terminal, char cull_color) { + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + for(int i = 0; i < height; ++i) { + float rowY = y + (float)(9 * i); + //todo + //drawString(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), palette); + drawString(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), palette, cull_color); + } + + } + + public static void drawTerminalForegroundNeg(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, Terminal terminal, char cull_color) { Palette palette = terminal.getPalette(); int height = terminal.getHeight(); for(int i = 0; i < height; ++i) { float rowY = y + (float)(9 * i); - drawString(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), palette); + //todo + //drawString(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), palette); + drawStringNeg(emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i), terminal.getBackgroundColourLine(i), palette, cull_color); } } - private static void drawBackground(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, TextBuffer backgroundColour, Palette palette, float leftMarginSize, float rightMarginSize, float height, char noBG_colourIdx) { + private static void drawBackground(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, TextBuffer backgroundColour, TextBuffer foregroundColor, Palette palette, float leftMarginSize, float rightMarginSize, float height, char noBG_colourIdx) { if (leftMarginSize > 0.0F) { drawQuad(emitter, x - leftMarginSize, y, leftMarginSize, height, palette, backgroundColour.charAt(0), noBG_colourIdx); } @@ -75,6 +125,11 @@ private static void drawBackground(DirectFixedWidthFontRenderer.QuadEmitter emit for(int i = 0; i < backgroundColour.length(); ++i) { char colourIndex = backgroundColour.charAt(i); + char colourIndex2 = foregroundColor.charAt(i); + + if(colourIndex2 == noBG_colourIdx){ + colourIndex = colourIndex2; + } if (colourIndex != blockColour) { if (blockColour != 0) { drawQuad(emitter, @@ -83,7 +138,6 @@ private static void drawBackground(DirectFixedWidthFontRenderer.QuadEmitter emit (float)(6 * (i - blockStart)), height, palette, blockColour, noBG_colourIdx); } - blockColour = colourIndex; blockStart = i; } @@ -98,21 +152,19 @@ private static void drawBackground(DirectFixedWidthFontRenderer.QuadEmitter emit public static void drawTerminalBackground(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, Terminal terminal, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize, char noBG_color) { Palette palette = terminal.getPalette(); int height = terminal.getHeight(); - drawBackground(emitter, x, y - topMarginSize, terminal.getBackgroundColourLine(0), palette, leftMarginSize, rightMarginSize, topMarginSize, noBG_color); - drawBackground(emitter, x, y + (float) (height * 9), terminal.getBackgroundColourLine(height - 1), palette, leftMarginSize, rightMarginSize, bottomMarginSize, noBG_color);; - + drawBackground(emitter, x, y - topMarginSize, terminal.getBackgroundColourLine(0), terminal.getTextColourLine(0), palette, leftMarginSize, rightMarginSize, topMarginSize, noBG_color); + drawBackground(emitter, x, y + (float) (height * 9), terminal.getBackgroundColourLine(height - 1), terminal.getTextColourLine(height - 1), palette, leftMarginSize, rightMarginSize, bottomMarginSize, noBG_color);; for (int i = 0; i < height; ++i) { float rowY = y + (float) (9 * i); - drawBackground(emitter, x, rowY, terminal.getBackgroundColourLine(i), palette, leftMarginSize, rightMarginSize, 9.0F, noBG_color); + drawBackground(emitter, x, rowY, terminal.getBackgroundColourLine(i), terminal.getTextColourLine(i), palette, leftMarginSize, rightMarginSize, 9.0F, noBG_color); } - } public static void drawCursor(DirectFixedWidthFontRenderer.QuadEmitter emitter, float x, float y, Terminal terminal) { if (FixedWidthFontRenderer.isCursorVisible(terminal)) { - byte[] colour = terminal.getPalette().getRenderColours(15 - terminal.getTextColour()); + int colour = terminal.getPalette().getRenderColours(15 - terminal.getTextColour()); drawChar(emitter, x + (float) (terminal.getCursorX() * 6), y + (float) (terminal.getCursorY() * 9), 95, colour); } @@ -122,7 +174,7 @@ public static int getVertexCount(Terminal terminal) { return (terminal.getHeight() + 2) * (terminal.getWidth() + 2) * 2; } - private static void quad(DirectFixedWidthFontRenderer.QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2) { + private static void quad(DirectFixedWidthFontRenderer.QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, int rgba, float u1, float v1, float u2, float v2) { buffer.quad(x1, y1, x2, y2, z, rgba, u1, v1, u2, v2); } @@ -187,9 +239,6 @@ static void quad(ByteBuffer buffer, float x1, float y1, float x2, float y2, floa } } - - - // Empty Terminal private static void quad(FixedWidthFontRenderer.QuadEmitter c, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int light) { Matrix4f poseMatrix = c.poseMatrix(); diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderer.java b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderer.java index 2d2af92..bb530ab 100644 --- a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderer.java +++ b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/glass_screen/ScreenRenderer.java @@ -56,7 +56,7 @@ protected void renderSafe(GlassScreenTE monitor, float partialTicks, PoseStack t if (originTerminal == null || originTE == null) return; var origin = originTerminal.getOrigin(); - var renderState = originTerminal.getRenderState(MonitorRenderState::new); + var renderState = originTerminal.getRenderState(GlassScreenRenderState::new); var monitorPos = monitor.getBlockPos(); // Ensure each monitor terminal is rendered only once. We allow rendering a specific tile @@ -133,7 +133,7 @@ protected void renderSafe(GlassScreenTE monitor, float partialTicks, PoseStack t } private static void renderTerminal( - Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin, + Matrix4f matrix, ClientMonitor monitor, GlassScreenRenderState renderState, Terminal terminal, float xMargin, float yMargin, GlassScreenTE te, boolean enableTransparent, char noBG_color ) { //int width = terminal.getWidth(), height = terminal.getHeight(); @@ -146,6 +146,7 @@ private static void renderTerminal( var backgroundBuffer = assertNonNull(renderState.backgroundBuffer); var foregroundBuffer = assertNonNull(renderState.foregroundBuffer); + var foregroundNegBuffer = assertNonNull(renderState.foregroundNegBuffer); if (redraw) { var size = ScreenRenderUtils.getVertexCount(terminal); @@ -159,12 +160,18 @@ private static void renderTerminal( renderToBuffer(backgroundBuffer, size, sink -> ScreenRenderUtils.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin, enableTransparent ? noBG_color : 'z')); + // renderToBuffer(foregroundBuffer, size, sink -> { - ScreenRenderUtils.drawTerminalForeground(sink, 0, 0, terminal); + ScreenRenderUtils.drawTerminalForeground(sink, 0, 0, terminal, enableTransparent ? noBG_color : 'z'); // If the cursor is visible, we append it to the end of our buffer. When rendering, we can either // render n or n+1 quads and so toggle the cursor on and off. ScreenRenderUtils.drawCursor(sink, 0, 0, terminal); }); + + + renderToBuffer(foregroundNegBuffer, size, sink -> { + ScreenRenderUtils.drawTerminalForegroundNeg(sink, 0, 0, terminal, enableTransparent ? noBG_color : 'z'); + }); } // Our VBO doesn't transform its vertices with the provided pose stack, which means that the inverse view @@ -174,7 +181,7 @@ private static void renderTerminal( RenderSystem.setInverseViewRotationMatrix(IDENTITY_NORMAL); RenderSystem.disableCull(); - RenderTypes.TERMINAL.setupRenderState(); + VPRenderTypes.TERMINAL.setupRenderState(); // Render background geometry backgroundBuffer.bind(); backgroundBuffer.drawWithShader(matrix, RenderSystem.getProjectionMatrix(), VPRenderTypes.text()); @@ -191,11 +198,23 @@ private static void renderTerminal( FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink() ? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount() ); + RenderTypes.TERMINAL.clearRenderState(); + + + VPRenderTypes.TERMINAL_NEG.setupRenderState(); + foregroundNegBuffer.bind(); + foregroundNegBuffer.drawWithShader( + matrix, RenderSystem.getProjectionMatrix(), VPRenderTypes.text(), + // As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each + // // quad has an index count of 6. + FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink() + ? foregroundNegBuffer.getIndexCount() + 6 : foregroundNegBuffer.getIndexCount() + ); // Clear state RenderSystem.polygonOffset(0.0f, -0.0f); RenderSystem.disablePolygonOffset(); - RenderTypes.TERMINAL.clearRenderState(); + VPRenderTypes.TERMINAL_NEG.clearRenderState(); VertexBuffer.unbind(); RenderSystem.enableCull(); RenderSystem.setInverseViewRotationMatrix(oldInverseRotation); diff --git a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/hologram/HologramRenderer.java b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/hologram/HologramRenderer.java index ca15ebd..b52a13f 100644 --- a/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/hologram/HologramRenderer.java +++ b/src/main/java/com/dfdyz/void_power/client/renderer/tileentities/hologram/HologramRenderer.java @@ -28,8 +28,8 @@ public HologramRenderer(BlockEntityRendererProvider.Context context){ protected void renderSafe(HologramTE te, float partialTicks, PoseStack stack, MultiBufferSource bufferSource, int plight, int overlay) { - if (te.buffer.length == 0)return; - if (te.renderCache == null)te.renderCache = new ScreenCacheImpl(te); + if (te.getBuffer().length == 0)return; + if (te.renderCache == null) te.renderCache = new ScreenCacheImpl(te); ResourceLocation tex = te.renderCache.getTexture(); if (tex == null)return; @@ -61,8 +61,8 @@ protected void renderSafe(HologramTE te, float partialTicks, PoseStack stack, Mu VertexConsumer buf = bufferSource.getBuffer(RenderType.entityTranslucent(tex)); float z = 0F; - float w = te.width / 32.f * te.scalex; - float h = te.high / 32.f * te.scaley; + float w = te.getWidth() / 32.f * te.scalex; + float h = te.getHeight() / 32.f * te.scaley; int light = 0xf000f0; buf.vertex(mat, w, h, z).color(1.0F, 1.0F, 1.0F, 1.0F).uv(1.0F, 0.0F).overlayCoords(overlay).uv2(light).normal(nor, 0.0F, 0.0F, 1.0F).endVertex(); diff --git a/src/main/java/com/dfdyz/void_power/client/screen_cache/ScreenCacheImpl.java b/src/main/java/com/dfdyz/void_power/client/screen_cache/ScreenCacheImpl.java index 02434c8..4f82c26 100644 --- a/src/main/java/com/dfdyz/void_power/client/screen_cache/ScreenCacheImpl.java +++ b/src/main/java/com/dfdyz/void_power/client/screen_cache/ScreenCacheImpl.java @@ -27,7 +27,7 @@ public class ScreenCacheImpl implements IScreenCache { public ScreenCacheImpl(HologramTE be) { this.be = be; this.needsUpdate = true; - dynTex = new DynamicTexture(be.width, be.high, true); + dynTex = new DynamicTexture(be.getWidth(), be.getHeight(), true); loc = Minecraft.getInstance().getTextureManager().register(VoidPowerMod.MODID, dynTex); } @@ -41,12 +41,12 @@ public void cleanup() { } public ResourceLocation getTexture() { - if (be == null || be.buffer.length == 0) return null; + if (be == null || be.getBuffer().length == 0) return null; Minecraft mc = Minecraft.getInstance(); if(mc.getTextureManager().getTexture(loc) == null) mc.getTextureManager().register(loc, dynTex); if (needsUpdate) { - load(be.width, be.high, be.buffer); + load(be.getWidth(), be.getHeight(), be.getBuffer()); needsUpdate = false; } return loc; diff --git a/src/main/java/com/dfdyz/void_power/compat/cct/lua/LuaPhysShip.java b/src/main/java/com/dfdyz/void_power/compat/cct/lua/LuaPhysShip.java index b8ba751..f23ed9a 100644 --- a/src/main/java/com/dfdyz/void_power/compat/cct/lua/LuaPhysShip.java +++ b/src/main/java/com/dfdyz/void_power/compat/cct/lua/LuaPhysShip.java @@ -3,14 +3,19 @@ import com.dfdyz.void_power.utils.CCUtils; import com.dfdyz.void_power.utils.VSUtils; +import com.dfdyz.void_power.world.blocks.engine_controller.EngineControllerBlock; +import com.dfdyz.void_power.world.blocks.engine_controller.EngineControllerTE; import dan200.computercraft.api.lua.LuaFunction; +import net.minecraft.core.Direction; import net.minecraft.util.Mth; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; import org.joml.*; import org.valkyrienskies.core.impl.game.ships.PhysInertia; import org.valkyrienskies.core.impl.game.ships.PhysShipImpl; import org.valkyrienskies.physics_api.PoseVel; import java.lang.Math; +import java.util.List; import java.util.Map; @@ -18,13 +23,46 @@ public class LuaPhysShip { private final PhysShipImpl physShip; private final ShipPhysStateSnapshot shipSnapshot; - public LuaPhysShip(ShipPhysStateSnapshot physShip, PhysShipImpl ship){ + //private final Quaternionf rot; + private final Matrix3d ctrl_rotation; + + static final Vector3d Up = new Vector3d(0,1,0); + + public LuaPhysShip(ShipPhysStateSnapshot physShip, PhysShipImpl ship, EngineControllerTE te){ this.shipSnapshot = physShip; this.physShip = ship; + //this.rot = te.getBlockState().getValue(EngineControllerBlock.FACING).getRotation(); + Matrix3d rm = shipSnapshot.rot.get(new Matrix3d()); + + var face = te.getBlockState().getValue(HorizontalDirectionalBlock.FACING); + if(face == Direction.NORTH){ + ctrl_rotation = rm; + } + else if(face == Direction.SOUTH){ + ctrl_rotation = new Matrix3d( + -rm.m00, rm.m01, -rm.m02, + -rm.m10, rm.m11, -rm.m12, + -rm.m20, rm.m21, -rm.m22 + ); + } + else if(face == Direction.EAST) { + ctrl_rotation = new Matrix3d( + -rm.m02, rm.m01, rm.m00, + -rm.m12, rm.m11, rm.m10, + -rm.m22, rm.m21, rm.m20 + ); + } + else { + ctrl_rotation = new Matrix3d( + rm.m02, rm.m01, -rm.m00, + rm.m12, rm.m11, -rm.m10, + rm.m22, rm.m21, -rm.m20 + ); + } } @LuaFunction - public Map getInertia() { + public final Map getInertia() { return Map.of( "momentOfInertiaTensor", CCUtils.dumpMat3(shipSnapshot.tensor), "mass", shipSnapshot.mass @@ -39,8 +77,8 @@ public record ShipPhysStateSnapshot(Vector3dc vel, Vector3dc omg, Vector3dc pos, } - @LuaFunction - public Map getPoseVel(){ + @LuaFunction() + public final Map getShipPoseVel(){ return Map.of( "velocity", CCUtils.dumpVec3(shipSnapshot.vel), "omega", CCUtils.dumpVec3(shipSnapshot.omg), @@ -48,11 +86,24 @@ public Map getPoseVel(){ "rot", CCUtils.dumpVec4(shipSnapshot.rot), "yaw", shipSnapshot.yaw, "pitch", shipSnapshot.pitch, - "roll", shipSnapshot.roll, - "up", CCUtils.dumpVec3(shipSnapshot.rot.transform(new Vector3d(0, 1, 0))) + "roll", shipSnapshot.roll + ); + } + + + @LuaFunction + public final Map getControllerFacesVec(){ + return Map.of( + "right", CCUtils.dumpVec3(ctrl_rotation.m00(), ctrl_rotation.m10(), ctrl_rotation.m20()), + "up", CCUtils.dumpVec3(ctrl_rotation.m01(), ctrl_rotation.m11(), ctrl_rotation.m21()), + "front", CCUtils.dumpVec3(-ctrl_rotation.m02(), -ctrl_rotation.m12(), -ctrl_rotation.m22()) ); } + @LuaFunction + public final List> getControllerRotationMat(){ + return CCUtils.dumpMat3(ctrl_rotation); + } public static ShipPhysStateSnapshot createSnapshot(PhysShipImpl ship){ double[][] rotMatrix = VSUtils.getRotationMatrixRaw(ship); @@ -63,9 +114,9 @@ public static ShipPhysStateSnapshot createSnapshot(PhysShipImpl ship){ new Vector3d(poseVel.getOmega()), new Vector3d(poseVel.getPos()), new Quaterniond(poseVel.getRot()), - Mth.atan2(-rotMatrix[0][2], rotMatrix[2][2]), - Math.asin(rotMatrix[1][2]), + Mth.atan2(rotMatrix[0][2], rotMatrix[2][2]), Mth.atan2(rotMatrix[1][0], rotMatrix[1][1]), + Mth.atan2(rotMatrix[1][2], rotMatrix[1][1]), new Matrix3d(inertia.getMomentOfInertiaTensor()), inertia.getShipMass() ); @@ -77,12 +128,12 @@ public static ShipPhysStateSnapshot createSnapshot(PhysShipImpl ship){ } @LuaFunction - public boolean isStatic(){ + public final boolean isStatic(){ return this.physShip.isStatic(); } @LuaFunction - public boolean doFluidDrag() { + public final boolean doFluidDrag() { return this.physShip.getDoFluidDrag(); } } diff --git a/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_EngineController.java b/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_EngineController.java index 5f76014..4f029da 100644 --- a/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_EngineController.java +++ b/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_EngineController.java @@ -10,17 +10,14 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.shared.computer.core.ServerComputer; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix4dc; -import org.joml.Quaterniondc; -import org.joml.Vector3d; -import org.joml.Vector4d; +import org.joml.*; +import org.joml.primitives.AABBi; import org.valkyrienskies.core.api.ships.ServerShip; -import org.valkyrienskies.core.api.ships.properties.ShipInertiaData; import org.valkyrienskies.core.impl.game.ships.PhysShipImpl; +import java.lang.Math; import java.util.List; import java.util.Map; import java.util.Objects; @@ -62,7 +59,7 @@ public void detach(IComputerAccess computer) { public void PushEvent(PhysShipImpl physShip){ LuaPhysShip.ShipPhysStateSnapshot snapshot = LuaPhysShip.createSnapshot(physShip); computers.forEach((c) -> { - c.queueEvent("phys_tick", new Object[]{new LuaPhysShip(snapshot, physShip)}); + c.queueEvent("phys_tick", new Object[]{new LuaPhysShip(snapshot, physShip, te)}); }); } @@ -195,7 +192,7 @@ public Map getPosition(){ return CCUtils.dumpVec3(te.getShip().getTransform().getPositionInWorld()); } return CCUtils.dumpVec3(0,0,0); - } + }//▀▄ private List> getRotationMatrix(ServerShip ship){ Matrix4dc transform = ship.getTransform().getShipToWorld(); @@ -268,4 +265,46 @@ public void applyRotDependentForceToPos(double px, double py, double pz, double applier.applyRotDependentForceToPos(new Vector3d(fx,fy,fz), new Vector3d(px,py,pz)); } } + + @LuaFunction + public boolean isStatic(){ + if(te.hasShip()){ + return te.getShip().isStatic(); + } + return true; + } + + @LuaFunction + public Map getScale(){ + if(te.hasShip()){ + Vector3d s = te.getShip().getShipToWorld().getScale(new Vector3d()); + return CCUtils.dumpVec3(s); + } + return null; + } + + @LuaFunction + public Map getSize(){ + if(te.hasShip()){ + var aabb = te.getShip().getShipAABB(); + if(aabb == null) aabb = new AABBi(0, 0, 0, 0, 0, 0); + return CCUtils.dumpVec3( + aabb.maxX() - aabb.minX(), + aabb.maxY() - aabb.minY(), + aabb.maxZ() - aabb.minZ() + ); + } + return null; + } + + @LuaFunction + public Map getShipCenter(){ //getShipyardPosition + if(te.hasShip()){ + Vector3dc s = te.getShip().getTransform().getPositionInShip(); + return CCUtils.dumpVec3(s); + } + return null; + } + + } diff --git a/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_HologramPeripheral.java b/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_HologramPeripheral.java index d4ba03b..80955eb 100644 --- a/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_HologramPeripheral.java +++ b/src/main/java/com/dfdyz/void_power/compat/cct/peripherals/P_HologramPeripheral.java @@ -1,77 +1,225 @@ package com.dfdyz.void_power.compat.cct.peripherals; import com.dfdyz.void_power.Config; -import com.dfdyz.void_power.network.PacketManager; -import com.dfdyz.void_power.network.SP.SP_HologramUpdate; -import com.dfdyz.void_power.utils.Debug; import com.dfdyz.void_power.utils.ParamUtils; -import com.dfdyz.void_power.utils.SyncLocker; +import com.dfdyz.void_power.utils.font.DefaultFont; import com.dfdyz.void_power.utils.font.Font; +import com.dfdyz.void_power.utils.font.FontLib; +import com.dfdyz.void_power.utils.font.IFontLib; +import com.dfdyz.void_power.world.blocks.hologram.DefaultFrameBufferImpl; import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import com.dfdyz.void_power.world.blocks.hologram.IFrameBuffer; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.errorprone.annotations.concurrent.GuardedBy; import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; -import dan200.computercraft.api.lua.LuaTable; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.core.BlockPos; import org.jetbrains.annotations.Nullable; -import org.valkyrienskies.core.impl.shadow.M; -import org.valkyrienskies.core.impl.shadow.S; -import org.yaml.snakeyaml.error.Mark; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class P_HologramPeripheral implements IPeripheral{ - public int dirty_x, dirty_y, dirty_ex, dirty_ey; + //public int dirty_x, dirty_y, dirty_ex, dirty_ey; - public SyncLocker shouldFullUpdate = new SyncLocker<>(true); + //public SyncLocker shouldFullUpdate = new SyncLocker<>(true); + + protected final HashMap fontlibs = new HashMap<>(); protected HologramTE te; + private IFrameBuffer currentBuffer; + + protected IFrameBuffer[] buffers; + public P_HologramPeripheral(HologramTE te){ this.te = te; - //resize(te.width, te.high); - dirty_x = te.width; - dirty_ex = 0; - dirty_y = te.high; - dirty_ey = 0; + //resize(currentBuffer.getWidth(), currentBuffer.getHigh()); + currentBuffer = te; + buffers = new IFrameBuffer[Config.HologramMaxBufferCount]; + Arrays.fill(buffers, null); + } + + @LuaFunction + public final int CreateFrameBuffer(int w, int h){ + int idx = -1; + for (int i = 0; i < buffers.length; i++) { + if(buffers[i] == null){ + buffers[i] = new DefaultFrameBufferImpl(w,h); + idx = i; + break; + } + } + return idx; + } + + @LuaFunction + public final int GetMaxFrameBufferCount(){ + return buffers.length; + } + + @LuaFunction + public final int GetFrameBufferCount(){ + int cnt = 0; + for (IFrameBuffer buffer : buffers) { + if (buffer != null) { + ++cnt; + } + } + return cnt; + } + + @LuaFunction + public final void FreeAllFrameBuffer(){ + currentBuffer = te; + Arrays.fill(buffers, null); + } + + @LuaFunction + public final void SetCurrentFrameBuffer(int idx) throws LuaException { + if(idx < 0){ + currentBuffer = te; + } + else if(idx < buffers.length){ + if(buffers[idx] != null){ + currentBuffer = buffers[idx]; + } + else throw new LuaException("Buffer [" + idx + "] not exist."); + } + else throw new LuaException("Buffer id out of range(, " + (buffers.length - 1) + "]"); + } + + @LuaFunction + public final Map DumpFrameBuffer(){ + Map map = new HashMap<>(); + map.put("w", currentBuffer.getWidth()); + map.put("h", currentBuffer.getHeight()); + map.put("pixels", ParamUtils.dumpIntArray(currentBuffer.getBuffer())); + return map; + } + + + @LuaFunction + public final void FreeFrameBuffer(int idx) throws LuaException { + if(idx >= 0 && idx < buffers.length){ + if(currentBuffer == buffers[idx]) currentBuffer = te; + buffers[idx] = null; + } + else throw new LuaException("Buffer id out of range[0, " + (buffers.length - 1) + "]"); } @LuaFunction public final void Resize(int w, int h) throws LuaException { synchronized (SYNC_LOCK){ if(w > Config.holo_w_mx || h > Config.holo_h_mx) throw new LuaException("Max resolution is %d x %d, out of range.".formatted(Config.holo_w_mx, Config.holo_h_mx)); - te.resize(w, h); - dirty_x = te.width; - dirty_ex = 0; - dirty_y = te.high; - dirty_ey = 0; + currentBuffer = currentBuffer.resize(w, h); } } @LuaFunction - public void SetClearColor(IArguments param) throws LuaException { - te.initColor = ParamUtils.convertColor(param.getInt(0)); + public final void SetClearColor(IArguments param) throws LuaException { + currentBuffer.setInitColor(ParamUtils.convertColor(param.getInt(0))); } - @LuaFunction - public String GetName(){ + public final String GetName(){ return te.name; } @LuaFunction - public void Rename(String n){ + public final void Rename(String n){ te.Rename(n); } + @LuaFunction + public final Map GetAllInvalidBuffer(){ + Map table = Maps.newHashMap(); + int idx = 0; + for (int i = 0; i < buffers.length; i++) { + if(buffers[i] != null){ + table.put((++idx)*1.0, i*1.0); + } + } + return table; + } + + + @LuaFunction + public final void BlitFrameBuffer(IArguments param) throws LuaException { + int ax = param.getInt(0); + int ay = param.getInt(1); + int bufferId = param.getInt(2); + int mode = 0; + if(param.count() == 4){ + mode = param.getInt(3); + } + + IFrameBuffer fb = getBuffer(bufferId); + if(fb == null) throw new LuaException("Invalid frame buffer."); + if(fb == currentBuffer) return; + int w = fb.getWidth(); + int h = fb.getHeight(); + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); + + try { + int[] buffer = currentBuffer.getBuffer(); + int[] fbuffer = fb.getBuffer(); + int col = -1, idx; + int edgeD = Math.min(high, ay+h); + if(mode == 1){ //cutout + for(int y = Math.max(ay, 0); y < edgeD; ++y){ + int offO = (y-ay) * w; + int offD = y * width; + int edgeR = Math.min(width ,ax+w); + for(int x = Math.max(ax, 0); x < edgeR; ++x){ + idx = offO + x - ax; + col = fbuffer[idx]; + if((col & 0xFF) > 0){ + buffer[offD + x] = col; + } + } + } + } + else if(mode == 0){ //solid + for(int y = Math.max(ay, 0); y < edgeD; ++y){ + int offO = (y-ay) * w; + int offD = y * width; + int edgeR = Math.min(width, ax+w); + for(int x = Math.max(ax, 0); x < edgeR; ++x){ + idx = offO + x - ax; + buffer[offD + x] = fbuffer[idx]; + } + } + } + else if(mode == 2){ //blend + for(int y = Math.max(ay, 0); y < edgeD; ++y){ + int offO = (y-ay) * w; + int offD = y * width; + int edgeR = Math.min(width ,ax+w); + for(int x = Math.max(ax, 0); x < edgeR; ++x){ + idx = offO + x - ax; + buffer[offD + x] = ParamUtils.convertColor(ParamUtils.blendColor(fbuffer[idx], ParamUtils.convertColor(buffer[offD + x]))); + } + } + } + }catch (Exception e){ + e.printStackTrace(); + throw new LuaException(e.toString()); + } + + } + + IFrameBuffer getBuffer(int idx){ + if(idx < 0) return te; + else if(idx < buffers.length) return buffers[idx]; + else return null; + } + @LuaFunction public final void Blit(IArguments param) throws LuaException { if(param.count() < 5) throw new LuaException("Need more than 5 argument at, got " + param.count() + "."); @@ -80,18 +228,22 @@ public final void Blit(IArguments param) throws LuaException { ay = param.getInt(1); w = param.getInt(2); h = param.getInt(3); + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); + int mode = param.count() == 6 ? param.getInt(5) : 0; try { Map src_raw = param.getTable(4); - int[] buffer = te.buffer; + int[] buffer = currentBuffer.getBuffer(); int col = -1, idx; - int edgeD = Math.min(te.high, ay+h); + int edgeD = Math.min(high, ay+h); if(mode == 1){ //cutout for(int y = Math.max(ay, 0); y < edgeD; ++y){ int offO = (y-ay) * w; - int offD = y * te.width; - int edgeR = Math.min(te.width ,ax+w); + int offD = y * width; + int edgeR = Math.min(width ,ax+w); for(int x = Math.max(ax, 0); x < edgeR; ++x){ idx = offO + x - ax; if(src_raw.containsKey(idx * 1.0)){ @@ -106,8 +258,8 @@ public final void Blit(IArguments param) throws LuaException { else if(mode == 0){ //solid for(int y = Math.max(ay, 0); y < edgeD; ++y){ int offO = (y-ay) * w; - int offD = y * te.width; - int edgeR = Math.min(te.width ,ax+w); + int offD = y * width; + int edgeR = Math.min(width, ax+w); for(int x = Math.max(ax, 0); x < edgeR; ++x){ idx = offO + x - ax; if(src_raw.containsKey(idx * 1.0)){ @@ -120,8 +272,8 @@ else if(mode == 0){ //solid else if(mode == 2){ //blend for(int y = Math.max(ay, 0); y < edgeD; ++y){ int offO = (y-ay) * w; - int offD = y * te.width; - int edgeR = Math.min(te.width ,ax+w); + int offD = y * width; + int edgeR = Math.min(width ,ax+w); for(int x = Math.max(ax, 0); x < edgeR; ++x){ idx = offO + x - ax; if(src_raw.containsKey(idx * 1.0)){ @@ -131,46 +283,386 @@ else if(mode == 2){ //blend } } } - - //Debug.PrintIntArray(buffer, te.width); - MarkDirtyXYWH(ax, ay, w, h); }catch (Exception e){ - MarkDirtyXYWH(ax, ay, w, h); e.printStackTrace(); throw new LuaException(e.toString()); } } + // refer https://blog.51cto.com/u_15273495/2914191 @LuaFunction - public void Text(IArguments param) throws LuaException { + public final void DrawTriangle(IArguments param) throws LuaException { + int x0 = param.getInt(0); + int y0 = param.getInt(1); + int x1 = param.getInt(2); + int y1 = param.getInt(3); + int x2 = param.getInt(4); + int y2 = param.getInt(5); + + int color0 = param.getInt(6); + int mode = 0; + if(param.count() > 7){ + mode = param.getInt(7); + } + + int color1 = color0; + int color2 = color0; + if(param.count() > 8){ + color1 = param.getInt(7); + color2 = param.getInt(8); + mode = 0; + } + + if(param.count() > 9){ + mode = param.getInt(9); + } + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); + + int sx = Math.max(0, Math.min(x0, Math.min(x1, x2))); + int ex = Math.min(width, Math.max(x0, Math.max(x1, x2))); + + int sy = Math.max(0, Math.min(y0, Math.min(y1, y2))); + int ey = Math.min(high, Math.max(y0, Math.max(y1, y2))); + + float area = PerpDot(x0, y0, + x1, y1, + x2, y2); + + int col; + int[] buffer = currentBuffer.getBuffer(); + if(mode == 2){ // blend + for(int y = sy; y < ey; ++y){ + int offD = y * width; + for(int x = sx; x < ex; ++x){ + float e0 = PerpDot(x1, y1, x2, y2, x, y)/ area; + float e1 = PerpDot(x2, y2, x0, y0, x, y)/ area; + float e2 = PerpDot(x0, y0, x1, y1, x, y)/ area; + + if (e0 >= 0 && e1 >= 0 && e2 >= 0){ // inside + col = LerpCol(color0, color1, color2, e0, e1, e2); + buffer[offD + x] = + ParamUtils.convertColor( + ParamUtils.blendColor( + col, + ParamUtils.convertColor(buffer[offD + x]) + ) + ); + } + } + } + } + else { + for(int y = sy; y < ey; ++y){ + int offD = y * width; + for(int x = sx; x < ex; ++x){ + float e0 = PerpDot(x1, y1, x2, y2, x, y)/ area; + float e1 = PerpDot(x2, y2, x0, y0, x, y)/ area; + float e2 = PerpDot(x0, y0, x1, y1, x, y)/ area; + + if (e0 >= 0 && e1 >= 0 && e2 >= 0){ // inside + col = LerpCol(color0, color1, color2, e0, e1, e2); + buffer[offD + x] = ParamUtils.convertColor(col); + } + } + } + } + } + + @LuaFunction + public final void DrawLine(IArguments param) throws LuaException { + int r_ma_x = te.getWidth()*2; + int r_mi_x = -te.getWidth(); + int r_ma_y = te.getHeight()*2; + int r_mi_y = -te.getHeight(); + int x0 = ParamUtils.rangeCheck(param.getInt(0), r_mi_x, r_ma_x, 0); + int y0 = ParamUtils.rangeCheck(param.getInt(1), r_mi_y, r_ma_y, 1); + int x1 = ParamUtils.rangeCheck(param.getInt(2), r_mi_x, r_ma_x, 2); + int y1 = ParamUtils.rangeCheck(param.getInt(3), r_mi_y, r_ma_y, 3); + int color = param.getInt(4); + int mode = 0; + if(param.count() > 5){ + mode = param.getInt(5); + } + int dx = Math.abs(x1 - x0); + int dy = Math.abs(y1 - y0); + int[] buf = currentBuffer.getBuffer(); + int width = currentBuffer.getWidth(); + int height = currentBuffer.getHeight(); + int col = ParamUtils.convertColor(color); + if(mode != 2){ + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + int e = 0; + for (int i = 0; i < dx + dy; i++) { + if(x0 >= 0 && x0 < width + && y0 >= 0 && y0 < height + ){ + buf[x0 + y0 * width] = col; + } + int e1 = e + dy; + int e2 = e - dx; + if (Math.abs(e1) < Math.abs(e2)) { + x0 += sx; + e = e1; + } else { + y0 += sy; + e = e2; + } + } + }else { + int sgnX = x0 < x1 ? 1 : -1; + int sgnY = y0 < y1 ? 1 : -1; + int e = 0; + for (int i = 0; i < dx + dy; i++) { + if (x0 >= 0 && x0 < width + && y0 >= 0 && y0 < height + ) { + buf[x0 + y0 * width] = ParamUtils.convertColor(ParamUtils.blendColor( + color, ParamUtils.convertColor(buf[x0 + y0 * width]) + )); + } + int e1 = e + dy; + int e2 = e - dx; + if (Math.abs(e1) < Math.abs(e2)) { + x0 += sgnX; + e = e1; + } else { + y0 += sgnY; + e = e2; + } + } + } + + } + + @LuaFunction + public final void DrawPixel(IArguments param) throws LuaException { + int x = param.getInt(0); + int y = param.getInt(1); + + int color = param.getInt(2); + int mode = 0; + if(param.count() > 3){ + mode = param.getInt(3); + } + + int width = currentBuffer.getWidth(); + int[] buf = currentBuffer.getBuffer(); + if(x >= 0 && x < width + && y >= 0 && y < currentBuffer.getHeight()){ + if(mode == 2){ + buf[x + y * width] = ParamUtils.convertColor(ParamUtils.blendColor( + color, ParamUtils.convertColor(buf[x + y * width]) + )); + } + else { + buf[x + y * width] = ParamUtils.convertColor(color); + } + } + } + + static void NotFinish() throws LuaException { + throw new LuaException("This function is not finish on this version of mod."); + } + + record Vertex(int x, int y, float u, float v, Color color){ + static Vertex dumpFrom(Map table) throws LuaException { + try { + return new Vertex((int)((double)table.get(1.0)), + (int)((double) table.get(2.0)), + (float)((double) table.get(3.0)), + (float)((double)table.get(4.0)), + Color.fromRBGA32((int)((double) table.get(5.0))) + ); + }catch (Exception e){ + throw new LuaException("Vertex format error."); + } + } + } + + record Color(float r, float g, float b, float a){ + static Color fromRBGA32(int c){ + float r = ((c >> 24) & 0xFF) / 255.f; + float g = ((c >> 16) & 0xFF) / 255.f; + float b = ((c >> 8) & 0xFF) / 255.f; + float a = (c & 0xFF) / 255.f; + return new Color(r,g,b,a); + } + + public int getRGBA32(){ + return ((((int)(r * 0xFF)) & 0xFF) << 24) | + ((((int)(g * 0xFF)) & 0xFF) << 16) | + ((((int)(b * 0xFF)) & 0xFF) << 8) | + ((((int)(a * 0xFF)) & 0xFF)); + } + + public Color mul(float r, float g, float b, float a){ + return new Color(this.r * r, this.g * g, this.b * b, this.a * a); + } + } + + @LuaFunction + public final void DrawTriangleWithTexture(IArguments param) throws LuaException { + IFrameBuffer texture = getBuffer(param.getInt(3)); + if(texture == null){ + throw new LuaException("Frame buffer not allocate."); + } + + if(texture == currentBuffer){ + throw new LuaException("Can't set current frame buffer as texture to sampler."); + } + + Vertex v0,v1,v2; + v0 = Vertex.dumpFrom(param.getTable(0)); + v1 = Vertex.dumpFrom(param.getTable(1)); + v2 = Vertex.dumpFrom(param.getTable(2)); + + int mode = 0; + if(param.count() > 4){ + mode = param.getInt(4); + } + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); + + int sx = Math.max(0, Math.min(v0.x, Math.min(v1.x, v2.x))); + int ex = Math.min(width, Math.max(v0.x, Math.max(v1.x, v2.x))); + + int sy = Math.max(0, Math.min(v0.y, Math.min(v1.y, v2.y))); + int ey = Math.min(high, Math.max(v0.y, Math.max(v1.y, v2.y))); + + float area = PerpDot(v0.x, v0.y, + v1.x, v1.y, + v2.x, v2.y); + + float u,v,r,g,b,a; + + int[] buffer = currentBuffer.getBuffer(); + if(mode == 2){ // blend + for(int y = sy; y < ey; ++y){ + int offD = y * width; + for(int x = sx; x < ex; ++x){ + float e0 = PerpDot(v1.x, v1.y, v2.x, v2.y, x, y)/ area; + float e1 = PerpDot(v2.x, v2.y, v0.x, v0.y, x, y)/ area; + float e2 = PerpDot(v0.x, v0.y, v1.x, v1.y, x, y)/ area; + + if (e0 >= 0 && e1 >= 0 && e2 >= 0){ // inside + r = LerpChannel(v0.color.r, v1.color.r, v2.color.r, e0, e1, e2); + g = LerpChannel(v0.color.g, v1.color.g, v2.color.g, e0, e1, e2); + b = LerpChannel(v0.color.b, v1.color.b, v2.color.b, e0, e1, e2); + a = LerpChannel(v0.color.a, v1.color.a, v2.color.a, e0, e1, e2); + u = v0.u * e0 + v1.u * e1 + v2.u * e2; + v = v0.v * e0 + v1.v * e1 + v2.v * e2; + Color s = Color.fromRBGA32(sampler(texture, u, v)).mul(r,g,b,a); + buffer[offD + x] = + ParamUtils.convertColor( + ParamUtils.blendColor( + s.getRGBA32(), + ParamUtils.convertColor(buffer[offD + x]) + ) + ); + } + } + } + } + else { + for(int y = sy; y < ey; ++y){ + int offD = y * width; + for(int x = sx; x < ex; ++x){ + float e0 = PerpDot(v1.x, v1.y, v2.x, v2.y, x, y)/ area; + float e1 = PerpDot(v2.x, v2.y, v0.x, v0.y, x, y)/ area; + float e2 = PerpDot(v0.x, v0.y, v1.x, v1.y, x, y)/ area; + + if (e0 >= 0 && e1 >= 0 && e2 >= 0){ // inside + r = LerpChannel(v0.color.r, v1.color.r, v2.color.r, e0, e1, e2); + g = LerpChannel(v0.color.g, v1.color.g, v2.color.g, e0, e1, e2); + b = LerpChannel(v0.color.b, v1.color.b, v2.color.b, e0, e1, e2); + a = LerpChannel(v0.color.a, v1.color.a, v2.color.a, e0, e1, e2); + u = v0.u * e0 + v1.u * e1 + v2.u * e2; + v = v0.v * e0 + v1.v * e1 + v2.v * e2; + Color s = Color.fromRBGA32(sampler(texture, u, v)); + buffer[offD + x] = ParamUtils.convertColor(s.mul(r,g,b,a).getRGBA32()); + } + } + } + } + } + + + + int sampler(IFrameBuffer texture, float _u, float _v){ + int width = texture.getWidth(); + float u,v; + u = Math.min(1, Math.max(0, _u)); + v = Math.min(1, Math.max(0, _v)); + + int x = (int) ((width - 1) * u); + int y = (int) ((texture.getHeight() - 1) * (1 - v)); + return ParamUtils.convertColor(texture.getBuffer()[y * width + x]); + } + + + int LerpCol(int c0, int c1, int c2, float e0, float e1, float e2){ + int r = (int) (((c0 >> 24) & 0xFF) * e0 + ((c1 >> 24) & 0xFF) * e1 + ((c2 >> 24) & 0xFF) * e2) & 0xFF; + int g = (int) (((c0 >> 16) & 0xFF) * e0 + ((c1 >> 16) & 0xFF) * e1 + ((c2 >> 16) & 0xFF) * e2) & 0xFF; + int b = (int) (((c0 >> 8) & 0xFF) * e0 + ((c1 >> 8) & 0xFF) * e1 + ((c2 >> 8) & 0xFF) * e2) & 0xFF; + int a = (int) ((c0 & 0xFF) * e0 + (c1 & 0xFF) * e1 + (c2 & 0xFF) * e2) & 0xFF; + return (r << 24) | (g << 16) | (b << 8) | (a); + } + + float LerpChannel(float c0, float c1, float c2, float e0, float e1, float e2){ + return c0 * e0 + c1 * e1 + c2 * e2; + } + + float PerpDot(float x0, float y0, float x1 ,float y1, float x2, float y2){ + return (x2 - x1) * (y0 - y1) - (y2 - y1) * (x0 - x1); + } + + @LuaFunction + public final void Text(IArguments param) throws LuaException { int ax = param.getInt(0); int ay = param.getInt(1); - String text = ParamUtils.unicodeToCN(param.getString(2)); + String text = ParamUtils.unicodeToStr(param.getString(2)); int color = param.getInt(3); int mode = param.getInt(4); + IFontLib font = DefaultFont.Instance; + if(param.count() > 5){ + String ft_lib = param.getString(5); + if(fontlibs.containsKey(ft_lib)){ + font = fontlibs.get(ft_lib); + } + else { + throw new LuaException("Font %s is not exist.".formatted(ft_lib)); + } + } + int tmpx = ax; - int[] buffer = te.buffer; + int[] buffer = currentBuffer.getBuffer(); + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); if(mode == 0 || mode == 1){ // cutout color = ParamUtils.convertColor(color); for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); - if (tmpx > te.width) continue; + if (tmpx > width) continue; if (ch == '\n') { ay += 16; - if (ay > te.high) break; + if (ay > high) break; tmpx = ax; continue; } - Font.CharMat cm = Font.getMat(ch); - int edgeR = Math.min(ay + cm.bitmap.length, te.high); - MarkDirtyXYWH(tmpx, ay, cm.width, cm.bitmap.length); + Font.CharMat cm = font.get(ch); + int edgeR = Math.min(ay + cm.bitmap.length, high); for (int y = Math.max(ay, 0); y < edgeR; y++) { - int offD = y * te.width; - int edgeD = Math.min(te.width, tmpx + cm.width); + int offD = y * width; + int edgeD = Math.min(width, tmpx + cm.width); for (int x = Math.max(tmpx, 0); x < edgeD; x++) { if(cm.bitmap[y-ay][x-tmpx]){ buffer[offD + x] = color; @@ -184,19 +676,18 @@ public void Text(IArguments param) throws LuaException { else if(mode == 2){ // blend for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); - if (tmpx > te.width) continue; + if (tmpx > width) continue; if (ch == '\n') { ay += 16; - if (ay > te.high) break; + if (ay > high) break; tmpx = ax; continue; } - Font.CharMat cm = Font.getMat(ch); - int edgeR = Math.min(ay + cm.bitmap.length, te.high); - MarkDirtyXYWH(tmpx, ay, cm.width, cm.bitmap.length); + Font.CharMat cm = font.get(ch); + int edgeR = Math.min(ay + cm.bitmap.length, high); for (int y = Math.max(ay, 0); y < edgeR; y++) { - int offD = y * te.width; - int edgeD = Math.min(te.width, tmpx + cm.width); + int offD = y * width; + int edgeD = Math.min(width, tmpx + cm.width); for (int x = Math.max(tmpx, 0); x < edgeD; x++) { if(cm.bitmap[y-ay][x-tmpx]){ buffer[offD + x] = ParamUtils.convertColor(ParamUtils.blendColor(color, ParamUtils.convertColor(buffer[offD + x]))); @@ -209,9 +700,38 @@ else if(mode == 2){ // blend } + @LuaFunction + public final void SetPixel(IArguments args) throws LuaException { + int x = args.getInt(0); + int y = args.getInt(1); + int c = args.getInt(2); + int w = currentBuffer.getWidth(); + if(x >= 0 && x < w && y >= 0 && y < currentBuffer.getHeight()){ + currentBuffer.getBuffer()[y*w + x] = ParamUtils.convertColor(c); + } + else throw new LuaException("Position out of range."); + } + + @LuaFunction + public final double GetPixel(IArguments args) throws LuaException { + int x = args.getInt(0); + int y = args.getInt(1); + int w = currentBuffer.getWidth(); + if(x >= 0 && x < w && y >= 0 && y < currentBuffer.getHeight()){ + return ParamUtils.convertColor(currentBuffer.getBuffer()[y*w + x]); + } + else throw new LuaException("Position out of range."); + } + + @LuaFunction + public final Object[] GetBlockPos(){ + BlockPos bp = te.getBlockPos(); + return new Object[]{ bp.getX(), bp.getY(), bp.getZ() }; + } @LuaFunction - public void SetScale(double x, double y){ + public final void SetScale(double x, double y) throws LuaException { + if(x > 3 || y > 3) throw new LuaException("Too large, max is 3."); synchronized (SYNC_LOCK) { te.scalex = (float) x; te.scaley = (float) y; @@ -220,12 +740,12 @@ public void SetScale(double x, double y){ } @LuaFunction - public void Flush(){ + public final void Flush(){ te.needSync.set(true); } @LuaFunction - public void SetRotation(double yaw, double pitch, double roll){ + public final void SetRotation(double yaw, double pitch, double roll){ synchronized (SYNC_LOCK) { te.rotYaw = (float) yaw; te.rotPitch = (float) pitch; @@ -241,13 +761,10 @@ public void PushEvent(String event, Object... data){ }); } - public void KeyUp(int key){ - - } - @LuaFunction - public void SetTranslation(double x, double y, double z){ + public final void SetTranslation(double x, double y, double z) throws LuaException { + if(x > 16 || y > 16 || z > 16) throw new LuaException("Too far, max is 16."); synchronized (SYNC_LOCK) { te.offx = (float) x; te.offy = (float) y; @@ -256,29 +773,28 @@ public void SetTranslation(double x, double y, double z){ te.transformDirty.set(true); } - - public boolean isDirtyUnsafe(){ - return dirty_x < dirty_ex && dirty_y < dirty_ey; - } - @LuaFunction - public void Fill(IArguments param) throws LuaException { + public final void Fill(IArguments param) throws LuaException { if(param.count() < 5) throw new LuaException("Need 5 argument, got " + param.count() + "."); int ax, ay, w, h; ax = param.getInt(0); ay = param.getInt(1); w = param.getInt(2); h = param.getInt(3); + + int width = currentBuffer.getWidth(); + int high = currentBuffer.getHeight(); + int mode = param.count() == 6 ? param.getInt(5) : 0; try { int color = param.getInt(4); - int[] buffer = te.buffer; - int edgeD = Math.min(te.high, ay+h); + int[] buffer = currentBuffer.getBuffer(); + int edgeD = Math.min(high, ay+h); if(mode == 0 || mode == 1){ //solid color = ParamUtils.convertColor(color); for(int y = Math.max(ay, 0); y < edgeD; ++y){ - int offD = y * te.width; - int edgeR = Math.min(te.width ,ax+w); + int offD = y * width; + int edgeR = Math.min(width ,ax+w); for(int x = Math.max(ax, 0); x < edgeR; ++x){ buffer[offD + x] = color; } @@ -286,8 +802,8 @@ public void Fill(IArguments param) throws LuaException { } else if (mode == 2){ //blend for(int y = Math.max(ay, 0); y < edgeD; ++y){ - int offD = y * te.width; - int edgeR = Math.min(te.width ,ax+w); + int offD = y * width; + int edgeR = Math.min(width ,ax+w); for(int x = Math.max(ax, 0); x < edgeR; ++x){ buffer[offD + x] = ParamUtils.convertColor(ParamUtils.blendColor(color, ParamUtils.convertColor(buffer[offD + x]))); } @@ -296,8 +812,7 @@ else if (mode == 2){ //blend } catch (LuaException e) { throw new RuntimeException(e); } - MarkDirtyXYWH(ax, ay, w, h); - System.out.println(dirty_ex+" "+dirty_ey); + //System.out.println(dirty_ex+" "+dirty_ey); //System.out.println(ax + " " + ay + " " + (ax+w) + " " + (ay+h)); } @@ -306,109 +821,105 @@ else if (mode == 2){ //blend @GuardedBy("SYNC_LOCK") public final Object SYNC_LOCK = new Object(); - int[] PollDirtyBuffer(){ - if(!isDirtyUnsafe()) return null; - int w = dirty_ex - dirty_x; - int[] b = new int[w * (dirty_ey-dirty_y)]; - for (int y = dirty_y; y < dirty_ey; y++) { - int offb = (y-dirty_y) * w - dirty_x; - int offo = y* te.width; - for (int x = dirty_x; x < dirty_ex; x++) { - b[offb + x] = te.buffer[offo + x]; - } - } - return b; + @Override + public String getType() { + return "hologram"; } - public void SendLazyPack(HologramTE te){ - synchronized (SYNC_LOCK){ - // System.out.println("Dirty Update"); - SP_HologramUpdate p = GetLazyPack(te); - - if(p != null){ - //System.out.println("Dirty Update2"); - // Debug.PrintMsg(p); - PacketManager.sendToAllPlayerTrackingThisBlock(p, te); + void FillBuffer(int ax, int ay, int w, int h, int color_raw){ + //int col = ParamUtils.convertColor(color); + int[] buffer = currentBuffer.getBuffer(); + int width = currentBuffer.getWidth(); + int edgeD = Math.min(currentBuffer.getHeight(), ay + h); + for(int y = Math.max(ay, 0); y < edgeD; ++y) { + int offD = y * w; + int edgeR = Math.min(width, ax + w); + for (int x = Math.max(ax, 0); x < edgeR; ++x) { + buffer[offD + x] = color_raw; } } } - SP_HologramUpdate GetLazyPack(HologramTE te){ - int[] buffer = PollDirtyBuffer(); - //System.out.println(buffer != null); - if(buffer == null) return null; - SP_HologramUpdate pack = new SP_HologramUpdate( - te, dirty_x, dirty_y, - dirty_ex-dirty_x, - dirty_ey-dirty_y, - buffer - ); - //Debug.PrintMsg(pack); - dirty_x = te.width; - dirty_ex = 0; - dirty_y = te.high; - dirty_ey = 0; - return pack; - + @LuaFunction + public final void Clear(){ + Arrays.fill(currentBuffer.getBuffer(), currentBuffer.getInitColor()); } - public void SendFullPack(HologramTE te){ - synchronized (SYNC_LOCK){ - PacketManager.sendToAllPlayerTrackingThisBlock(new SP_HologramUpdate(te), te); + @LuaFunction + public final String CreateFont(String name) throws LuaException { + if(name.isEmpty()){ + throw new LuaException("Empty string is not allowed."); } - } - - public void MarkDirtyXYWH(int x, int y, int w, int h){ - synchronized (SYNC_LOCK){ - dirty_x = Math.min(x, dirty_x); - dirty_y = Math.min(y, dirty_y); - dirty_ex = Math.max(x+w, dirty_ex); - dirty_ey = Math.max(y+h, dirty_ey); - - dirty_x = Math.max(dirty_x, 0); - dirty_y = Math.max(dirty_y, 0); - dirty_ex = Math.min(dirty_ex, te.width); - dirty_ey = Math.min(dirty_ey, te.high); + if(fontlibs.containsKey(name)){ + return ""; + } + else { + if(fontlibs.size() < Config.HologramFontCount){ + fontlibs.put(name, new FontLib()); + return name; + } + else { + return null; + } } } + @LuaFunction + public final void PutCharPointMat(IArguments param) throws LuaException { + String name = param.getString(0); + FontLib fl = null; + if(fontlibs.containsKey(name)){ + fl = fontlibs.get(name); + } + else { + throw new LuaException("Font '%s' is not registered.".formatted(name)); + } + String orgc = param.getString(1); + String ch = ParamUtils.unicodeToStr(orgc); + if(ch.length() > 1){ + throw new LuaException("'%s' is not a ascii char or unicode char.".formatted(orgc)); + } - @Override - public String getType() { - return "hologram"; - } - - void FillBuffer(int ax, int ay, int w, int h, int color){ - int col = ParamUtils.convertColor(color); - int edgeD = Math.min(te.high, ay + h); - for(int y = Math.max(ay, 0); y < edgeD; ++y) { - int offD = y * w; - int edgeR = Math.min(te.width, ax + w); - for (int x = Math.max(ax, 0); x < edgeR; ++x) { - te.buffer[offD + x] = col; + int width = param.getInt(2); + int height = param.getInt(3); + Map mat = param.getTable(4); + + double idx; + boolean[][] cmat = new boolean[height][width]; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + idx = i * width + j + 1; + if(mat.containsKey(idx)){ + cmat[i][j] = ((Double)mat.get(idx)) > 0.5; + } + else { + throw new LuaException("Point mat error."); + } } } + fl.put(ch.charAt(0), cmat); } @LuaFunction - public void Clear(){ - FillBuffer(0,0,te.width,te.high,te.initColor); - shouldFullUpdate.set(true); + public final void DeleteFont(IArguments param) throws LuaException { + if(param.count() == 0){ + fontlibs.clear(); + } + else { + fontlibs.remove(param.getString(0)); + } } - - - @Override public void attach(IComputerAccess computer) { computers.add(computer); - System.out.println("A_ " + computer.getID()); + //System.out.println("A_ " + computer.getID()); } @Override public void detach(IComputerAccess computer) { computers.remove(computer); - System.out.println("D_ " + computer.getID()); + //System.out.println("D_ " + computer.getID()); } @Override diff --git a/src/main/java/com/dfdyz/void_power/events/InputEvents.java b/src/main/java/com/dfdyz/void_power/events/InputEvents.java new file mode 100644 index 0000000..253433a --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/events/InputEvents.java @@ -0,0 +1,23 @@ +package com.dfdyz.void_power.events; + +import com.dfdyz.void_power.registry.VPKeyBinds; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import static com.dfdyz.void_power.registry.VPKeyBinds.kbs; + +@Mod.EventBusSubscriber(value = Dist.CLIENT) +public class InputEvents { + + @SubscribeEvent + public static void KeyEvent(InputEvent.Key event){ + for (VPKeyBinds.KeyBind kb : kbs){ + if(event.getKey() == kb.km.getKey().getValue()){ + kb.callback.accept(event); + } + } + } + +} diff --git a/src/main/java/com/dfdyz/void_power/events/RenderEvent.java b/src/main/java/com/dfdyz/void_power/events/RenderEvent.java index e5cdcc9..6674326 100644 --- a/src/main/java/com/dfdyz/void_power/events/RenderEvent.java +++ b/src/main/java/com/dfdyz/void_power/events/RenderEvent.java @@ -2,48 +2,42 @@ import com.dfdyz.void_power.VoidPowerMod; +import com.dfdyz.void_power.client.renderer.hud.VRGlassesHUDRenderer; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.GameRenderer; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderGuiEvent; import net.minecraftforge.client.event.RenderLevelStageEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.loading.FMLEnvironment; +import org.valkyrienskies.core.impl.shadow.M; + -/* @Mod.EventBusSubscriber( modid = VoidPowerMod.MODID, - value = {Dist.CLIENT}, - bus = Mod.EventBusSubscriber.Bus.MOD + value = {Dist.CLIENT} ) - - */ - - public class RenderEvent { -/* @SubscribeEvent - public static void OnPlayerRightClick(RenderLevelStageEvent event){ - if(event.getStage() == RenderLevelStageEvent.Stage.AFTER_PARTICLES){ - - - - - - - } - }*/ - - - - + public static void OnPlayerRightClick(RenderGuiEvent.Pre event){ + GuiGraphics gg = event.getGuiGraphics(); + Minecraft mc = Minecraft.getInstance(); + LocalPlayer player = mc.player; + float pt = event.getPartialTick(); + + VRGlassesHUDRenderer.render(player, gg, pt); + } diff --git a/src/main/java/com/dfdyz/void_power/loader/FontLoader.java b/src/main/java/com/dfdyz/void_power/loader/FontLoader.java new file mode 100644 index 0000000..ad47404 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/loader/FontLoader.java @@ -0,0 +1,25 @@ +package com.dfdyz.void_power.loader; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; + +import java.util.Map; + +public class FontLoader extends SimpleJsonResourceReloadListener { + + public static FontLoader Instance = new FontLoader(); + static Gson gson = new Gson(); + + FontLoader() { + super(gson, "vp_font_loader"); + } + + @Override + protected void apply(Map resourceLocationJsonElementMap, ResourceManager resourceManager, ProfilerFiller profilerFiller) { + + } +} diff --git a/src/main/java/com/dfdyz/void_power/menu/HologramMenu.java b/src/main/java/com/dfdyz/void_power/menu/HologramMenu.java index 19958ab..503a85b 100644 --- a/src/main/java/com/dfdyz/void_power/menu/HologramMenu.java +++ b/src/main/java/com/dfdyz/void_power/menu/HologramMenu.java @@ -51,6 +51,9 @@ public HologramMenu(int windowId, HologramTE te){ @Override public boolean stillValid(@NotNull Player player) { - return te != null && !te.isRemoved() && te.canPlayerUse(player); + return te != null && + te.getLevel() != null && + te.getLevel().getBlockEntity(te.getBlockPos()) == te + && !te.isRemoved(); } } diff --git a/src/main/java/com/dfdyz/void_power/mixin/MixinBugFixUtils_Kt.java b/src/main/java/com/dfdyz/void_power/mixin/MixinBugFixUtils_Kt.java index 56f1e2f..46b3014 100644 --- a/src/main/java/com/dfdyz/void_power/mixin/MixinBugFixUtils_Kt.java +++ b/src/main/java/com/dfdyz/void_power/mixin/MixinBugFixUtils_Kt.java @@ -10,9 +10,10 @@ import java.util.Arrays; import java.util.Map; -@Mixin(value = BugFixUtil.class, remap = false) +//@Mixin(value = BugFixUtil.class, remap = false) public abstract class MixinBugFixUtils_Kt { + /* @Inject(method = "isCollisionBoxToBig", at = @At("RETURN"), cancellable = true) public void TraceCall(AABB aabb, CallbackInfoReturnable cir){ if(cir.getReturnValue()){ @@ -25,7 +26,6 @@ public void TraceCall(AABB aabb, CallbackInfoReturnable cir){ cir.cancel(); } } - - + */ } diff --git a/src/main/java/com/dfdyz/void_power/mixin/MixinComputerTE.java b/src/main/java/com/dfdyz/void_power/mixin/MixinComputerTE.java new file mode 100644 index 0000000..84d3906 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/mixin/MixinComputerTE.java @@ -0,0 +1,29 @@ +package com.dfdyz.void_power.mixin; + +import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity; +import dan200.computercraft.shared.computer.core.ServerComputer; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.valkyrienskies.core.api.ships.ServerShip; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +//@Mixin(ComputerBlockEntity.class) +public abstract class MixinComputerTE { + + /* + @Inject( + method = "createComputer", + at = @At("RETURN"), + remap = false + ) + private void cc_vs$addShipAPI(int id, CallbackInfoReturnable cir) { + //ServerComputer computer = cir.getReturnValue(); + //ServerLevel level = computer.getLevel(); + //BlockPos pos = computer.getPosition(); + + }*/ +} diff --git a/src/main/java/com/dfdyz/void_power/mixin/MixinPeripheralProxyTE_Kt.java b/src/main/java/com/dfdyz/void_power/mixin/MixinPeripheralProxyTE_Kt.java index f83c654..d421e2f 100644 --- a/src/main/java/com/dfdyz/void_power/mixin/MixinPeripheralProxyTE_Kt.java +++ b/src/main/java/com/dfdyz/void_power/mixin/MixinPeripheralProxyTE_Kt.java @@ -1,6 +1,7 @@ package com.dfdyz.void_power.mixin; +import com.dfdyz.void_power.Config; import com.dfdyz.void_power.utils.VSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; @@ -17,6 +18,11 @@ public abstract class MixinPeripheralProxyTE_Kt { @Inject(method = "isPosApplicable", at = @At("HEAD"), cancellable = true) public void distCheckVSPatch(BlockPos pos, CallbackInfoReturnable cir){ + if(Config.UnlimitDistance){ + cir.setReturnValue(true); + cir.cancel(); + } + /* BlockEntity te = (BlockEntity)(Object)this; Level level = te.getLevel(); int max = PeripheralWorksConfig.INSTANCE.getPeripheralProxyMaxRange(); @@ -25,6 +31,6 @@ public void distCheckVSPatch(BlockPos pos, CallbackInfoReturnable cir){ < max * max); //System.out.println(VSUtils.GetBlockDistanceSqrBetween(serverLevel, te.getBlockPos(), pos)); cir.cancel(); - } + }*/ } } diff --git a/src/main/java/com/dfdyz/void_power/network/PacketManager.java b/src/main/java/com/dfdyz/void_power/network/PacketManager.java index bfc7e44..32d26b2 100644 --- a/src/main/java/com/dfdyz/void_power/network/PacketManager.java +++ b/src/main/java/com/dfdyz/void_power/network/PacketManager.java @@ -4,10 +4,7 @@ import com.dfdyz.void_power.network.CP.CP_HologramInputEvent; import com.dfdyz.void_power.network.CP.CP_HologramRename; import com.dfdyz.void_power.network.CP.CP_HologramUpdateRequest; -import com.dfdyz.void_power.network.SP.SP_HologramPoseUpdate; -import com.dfdyz.void_power.network.SP.SP_HologramRename; -import com.dfdyz.void_power.network.SP.SP_HologramUpdate; -import com.dfdyz.void_power.network.SP.SP_UpdateGlassScreen; +import com.dfdyz.void_power.network.SP.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; @@ -26,7 +23,7 @@ public class PacketManager { }) .clientAcceptedVersions(PacketManager.VERSION::equals).serverAcceptedVersions(PacketManager.VERSION::equals).simpleChannel(); - public static final String VERSION = "1.2"; + static final String VERSION = "1.3"; public PacketManager() { } @@ -68,9 +65,13 @@ public static void Init(){ SP_UpdateGlassScreen::encode, SP_UpdateGlassScreen::decode, SP_UpdateGlassScreen::handler, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); - CHANNEL.registerMessage(index++, SP_HologramUpdate.class, - SP_HologramUpdate::encode, SP_HologramUpdate::decode, - SP_HologramUpdate::handler, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); + CHANNEL.registerMessage(index++, SP_HologramUpdate_A.class, + SP_HologramUpdate_A::encode, SP_HologramUpdate_A::decode, + SP_HologramUpdate_A::handler, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); + + CHANNEL.registerMessage(index++, SP_HologramUpdate_B.class, + SP_HologramUpdate_B::encode, SP_HologramUpdate_B::decode, + SP_HologramUpdate_B::handler, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); CHANNEL.registerMessage(index++, SP_HologramPoseUpdate.class, SP_HologramPoseUpdate::encode, SP_HologramPoseUpdate::decode, diff --git a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramRename.java b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramRename.java index a21ffd0..1eb7194 100644 --- a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramRename.java +++ b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramRename.java @@ -47,9 +47,7 @@ public static void handler(SP_HologramRename msg, Supplier ctx.enqueueWork(() -> { BlockEntity be = Minecraft.getInstance().level.getExistingBlockEntity(msg.te); if(be instanceof HologramTE te){ - System.out.println("RENAME"); te.Rename(msg.name); - System.out.println("SUCESS RENAME"); } }); } diff --git a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate.java b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate.java deleted file mode 100644 index 2a8b120..0000000 --- a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.dfdyz.void_power.network.SP; - - -import com.dfdyz.void_power.utils.Debug; -import com.dfdyz.void_power.world.blocks.hologram.HologramTE; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent; - -import java.util.function.Supplier; - -// lazy update -public class SP_HologramUpdate { - public BlockPos te; - public boolean lazy = true; - public short x, y, w, h; - public int[] buffer; - - public SP_HologramUpdate(){ - - } - - // full pack - public SP_HologramUpdate(HologramTE te){ - this(te, 0,0, te.width, te.high, te.buffer); - lazy = false; - } - - // lazy pack - public SP_HologramUpdate(HologramTE te, int x, int y, int w, int h, int[] lazy_buffer){ - this.te = te.getBlockPos(); - - this.x = (short) x; - this.y= (short) y; - this.w = (short) w; - this.h = (short) h; - - this.buffer = lazy_buffer; - } - public boolean checkPack(){ - return buffer.length == w*h; - } - - public static SP_HologramUpdate decode(FriendlyByteBuf buf) { - //System.out.println("Received_DEC"); - SP_HologramUpdate data = new SP_HologramUpdate(); - data.te = buf.readBlockPos(); - data.lazy = buf.readBoolean(); - - data.x = buf.readShort(); - data.y = buf.readShort(); - data.w = buf.readShort(); - data.h = buf.readShort(); - - int len = data.w*data.h; - data.buffer = new int[len]; - - for (int i = 0; i < len; i++) { - data.buffer[i] = buf.readInt(); - } - return data; - } - - public void encode(FriendlyByteBuf buf) { - buf.writeBlockPos(te); - buf.writeBoolean(lazy); - buf.writeShort(x); - buf.writeShort(y); - buf.writeShort(w); - buf.writeShort(h); - //Debug.PrintIntArray(buffer); - for (int i = 0; i < buffer.length; i++) { - buf.writeInt(buffer[i]); - } - } - - public static void handler(SP_HologramUpdate msg, Supplier context){ - NetworkEvent.Context ctx = context.get(); - ctx.setPacketHandled(true); - ctx.enqueueWork(() -> { - BlockEntity be = Minecraft.getInstance().level.getBlockEntity(msg.te); - if(be instanceof HologramTE te){ - te.handleLazyUpdatePack(msg); - } - }); - } -} diff --git a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_A.java b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_A.java new file mode 100644 index 0000000..3071150 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_A.java @@ -0,0 +1,107 @@ +package com.dfdyz.void_power.network.SP; + +import com.dfdyz.void_power.VoidPowerMod; +import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import com.google.common.collect.Lists; +import io.netty.buffer.Unpooled; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.network.NetworkEvent; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.function.Supplier; + +import static com.dfdyz.void_power.utils.ByteUtils.*; + +@SuppressWarnings("rawtypes") +public class SP_HologramUpdate_A { + public final BlockPos te; + public final short width, height; + public final int[] buffer; + + public SP_HologramUpdate_A(HologramTE te, int[] buffer){ + this.te = te.getBlockPos(); + width = (short) te.getWidth(); + height = (short) te.getHeight(); + this.buffer = buffer; + } + + public SP_HologramUpdate_A(FriendlyByteBuf buf){ + te = buf.readBlockPos(); + width = buf.readShort(); + height = buf.readShort(); + int[] buffer = null; + + byte[] compressed = buf.readByteArray(); + + try { + buffer = decompress(compressed); + } catch (IOException e) { + System.out.println("decompress Filed"); + System.out.println(e.getMessage()); + throw new RuntimeException(e); + } + + //System.out.println("Compressed size: " + compressed.length / 1024.f + "kb"); + //System.out.println("Data size: " + buffer.length * 4 / 1024.f + "kb"); + + this.buffer = buffer; + + /* + ranges = buf.readVarIntArray(); + elems = buf.readVarIntArray(); + */ + } + + public void encode(FriendlyByteBuf buf) { + buf.writeBlockPos(te); + buf.writeShort(width); + buf.writeShort(height); + try { + buf.writeByteArray(compress(buffer)); + } catch (IOException e) { + System.out.println(e.getMessage()); + throw new RuntimeException(e); + } + } + + public static SP_HologramUpdate_A decode(FriendlyByteBuf buf){ + return new SP_HologramUpdate_A(buf); + } + + public void handle(HologramTE te){ + int curr = 0; + int[] bf = te.getBuffer(); + while (curr < buffer.length){ + int offset = buffer[curr++]; + int len = buffer[curr++]; + if (len >= 0) System.arraycopy(buffer, curr, bf, offset, len); + curr += len; + } + } + + public static void handler(SP_HologramUpdate_A msg, Supplier context){ + NetworkEvent.Context ctx = context.get(); + ctx.setPacketHandled(true); + ctx.enqueueWork(() -> { + BlockEntity be = Minecraft.getInstance().level.getBlockEntity(msg.te); + if(be instanceof HologramTE te){ + te.resize(msg.width, msg.height); + //System.out.println("Handle A."); + try{ + msg.handle(te); + } catch (Exception e) { + + e.printStackTrace(); + } + te.UpdateRenderCache(); + //System.out.println("handled A"); + } + }); + } +} diff --git a/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_B.java b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_B.java new file mode 100644 index 0000000..21f4ee6 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/network/SP/SP_HologramUpdate_B.java @@ -0,0 +1,100 @@ +package com.dfdyz.void_power.network.SP; + +import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.network.NetworkEvent; + +import java.io.IOException; +import java.util.function.Supplier; + +import static com.dfdyz.void_power.utils.ByteUtils.compress; +import static com.dfdyz.void_power.utils.ByteUtils.decompress; + +@SuppressWarnings("rawtypes") +public class SP_HologramUpdate_B { + public final BlockPos te; + public final short width, height; + public final int[] buffer; + + public SP_HologramUpdate_B(HologramTE te, int[] buffer){ + this.te = te.getBlockPos(); + width = (short) te.getWidth(); + height = (short) te.getHeight(); + this.buffer = buffer; + } + + public SP_HologramUpdate_B(FriendlyByteBuf buf){ + te = buf.readBlockPos(); + width = buf.readShort(); + height = buf.readShort(); + int[] buffer = null; + + byte[] compressed = buf.readByteArray(); + try { + buffer = decompress(compressed); + } catch (IOException e) { + System.out.println("decompress Filed"); + System.out.println(e.getMessage()); + throw new RuntimeException(e); + } + + //System.out.println("Compressed size: " + compressed.length / 1024.f + "kb"); + //System.out.println("Data size: " + buffer.length * 4 / 1024.f + "kb"); + + this.buffer = buffer; + + /* + ranges = buf.readVarIntArray(); + elems = buf.readVarIntArray(); + */ + } + + public void encode(FriendlyByteBuf buf) { + buf.writeBlockPos(te); + buf.writeShort(width); + buf.writeShort(height); + try { + buf.writeByteArray(compress(buffer)); + } catch (IOException e) { + System.out.println(e.getMessage()); + throw new RuntimeException(e); + } + } + + public static SP_HologramUpdate_B decode(FriendlyByteBuf buf){ + return new SP_HologramUpdate_B(buf); + } + + public void handle(HologramTE te){ + int curr = 0; + int[] bf = te.getBuffer(); + while (curr < buffer.length){ + int pos = buffer[curr++]; + bf[pos] = buffer[curr++]; + } + } + + public static void handler(SP_HologramUpdate_B msg, Supplier context){ + NetworkEvent.Context ctx = context.get(); + ctx.setPacketHandled(true); + ctx.enqueueWork(() -> { + BlockEntity be = Minecraft.getInstance().level.getBlockEntity(msg.te); + if(be instanceof HologramTE te){ + te.resize(msg.width, msg.height); + //System.out.println("Handle B."); + try{ + msg.handle(te); + } catch (Exception e) { + e.printStackTrace(); + } + te.UpdateRenderCache(); + //System.out.println("handled B"); + } + }); + } + + +} diff --git a/src/main/java/com/dfdyz/void_power/registry/VPItems.java b/src/main/java/com/dfdyz/void_power/registry/VPItems.java index b70401f..7a6f7d0 100644 --- a/src/main/java/com/dfdyz/void_power/registry/VPItems.java +++ b/src/main/java/com/dfdyz/void_power/registry/VPItems.java @@ -1,17 +1,28 @@ package com.dfdyz.void_power.registry; +import com.dfdyz.void_power.VoidPowerMod; +import com.dfdyz.void_power.world.items.VRGlassesItem; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.armor.AllArmorMaterials; +import com.simibubi.create.content.equipment.armor.DivingHelmetItem; +import com.tterrag.registrate.util.entry.ItemEntry; +import net.minecraft.resources.ResourceLocation; + import static com.dfdyz.void_power.VoidPowerMod.REGISTRATE; +import static com.simibubi.create.AllTags.forgeItemTag; public class VPItems { - static { REGISTRATE.setCreativeTab(VPCreativeTabs.TAB); } + public static final ItemEntry VR_GLASSES = REGISTRATE + .item(VRGlassesItem.ID, + p -> new VRGlassesItem(AllArmorMaterials.COPPER, p, VoidPowerMod.getRL(VRGlassesItem.ID))) + .tag(forgeItemTag("armors/helmets")) + .register(); public static void register(){ } - - } diff --git a/src/main/java/com/dfdyz/void_power/registry/VPKeyBinds.java b/src/main/java/com/dfdyz/void_power/registry/VPKeyBinds.java new file mode 100644 index 0000000..0b0ea4b --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/registry/VPKeyBinds.java @@ -0,0 +1,46 @@ +package com.dfdyz.void_power.registry; + +import com.dfdyz.void_power.client.renderer.hud.VRGlassesHUDRenderer; +import net.minecraft.client.KeyMapping; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.client.event.RegisterKeyMappingsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.lwjgl.glfw.GLFW; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) +public class VPKeyBinds { + + public static final List kbs = new ArrayList<>(); + public static final KeyBind TOGGLE_VR_GLASSES = new KeyBind("vr_glasses", GLFW.GLFW_KEY_I, (event) -> { + boolean pressed = !(event.getAction() == 0); + if(pressed){ + VRGlassesHUDRenderer.On = !VRGlassesHUDRenderer.On; + } + }); + + + public static class KeyBind{ + static final String TAB_TITLE = "Void Power"; + public final KeyMapping km; + public final Consumer callback; + public KeyBind(String name, int default_key, Consumer callback){ + this.callback = callback; + km = new KeyMapping("key_bind." + name, default_key, TAB_TITLE); + kbs.add(this); + } + } + + + @SubscribeEvent + public static void register(RegisterKeyMappingsEvent event) { + kbs.forEach((e)->{ + event.register(e.km); + }); + } +} diff --git a/src/main/java/com/dfdyz/void_power/utils/ByteUtils.java b/src/main/java/com/dfdyz/void_power/utils/ByteUtils.java index b6cd99d..b7dc494 100644 --- a/src/main/java/com/dfdyz/void_power/utils/ByteUtils.java +++ b/src/main/java/com/dfdyz/void_power/utils/ByteUtils.java @@ -7,9 +7,18 @@ import net.minecraft.network.FriendlyByteBuf; import org.joml.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.Math; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; public class ByteUtils { @@ -30,4 +39,50 @@ public static String decodeString(FriendlyByteBuf buf){ return str; } + public static byte[] compress(byte[] data) { + Deflater deflater = new Deflater(); + deflater.setInput(data); + deflater.finish(); + + byte[] compressedData = new byte[data.length]; + int compressedDataLength = deflater.deflate(compressedData); + + return Arrays.copyOf(compressedData, compressedDataLength); + } + + public static byte[] compress(int[] data) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try (DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(byteArrayOutputStream)) { + for (int number : data) { + deflaterOutputStream.write((number >> 24) & 0xFF); + deflaterOutputStream.write((number >> 16) & 0xFF); + deflaterOutputStream.write((number >> 8) & 0xFF); + deflaterOutputStream.write(number & 0xFF); + } + } + return byteArrayOutputStream.toByteArray(); + } + + public static int[] decompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try (InflaterInputStream inflaterInputStream = new InflaterInputStream(new java.io.ByteArrayInputStream(compressedData))) { + byte[] buffer = new byte[1024]; + int length; + while ((length = inflaterInputStream.read(buffer)) != -1) { + byteArrayOutputStream.write(buffer, 0, length); + } + } + byte[] decompressedData = byteArrayOutputStream.toByteArray(); + + int[] result = new int[decompressedData.length / 4]; + for (int i = 0; i < result.length; i++) { + result[i] = ((decompressedData[i * 4] & 0xFF) << 24) | + ((decompressedData[i * 4 + 1] & 0xFF) << 16) | + ((decompressedData[i * 4 + 2] & 0xFF) << 8) | + (decompressedData[i * 4 + 3] & 0xFF); + } + return result; + } + + public static final int maxLengthPerPack = 256 * 256 - 16; } diff --git a/src/main/java/com/dfdyz/void_power/utils/Debug.java b/src/main/java/com/dfdyz/void_power/utils/Debug.java index 3417731..2676bdc 100644 --- a/src/main/java/com/dfdyz/void_power/utils/Debug.java +++ b/src/main/java/com/dfdyz/void_power/utils/Debug.java @@ -1,6 +1,5 @@ package com.dfdyz.void_power.utils; -import com.dfdyz.void_power.network.SP.SP_HologramUpdate; import java.util.Map; @@ -20,11 +19,6 @@ public static void PrintIntArray(int[] array, int line){ System.out.println(a); } - public static void PrintMsg(SP_HologramUpdate msg){ - System.out.println(msg.x + " " + msg.y + " " + msg.w + " " + msg.h + (msg.lazy ? "Lazy" : "Full")); - //PrintIntArray(msg.buffer, msg.w); - } - public static void PrintMap(Map map){ map.entrySet().forEach((entry -> { System.out.println(entry.getKey() + ", " + ((int)(double)entry.getValue())); diff --git a/src/main/java/com/dfdyz/void_power/utils/IntBuffer.java b/src/main/java/com/dfdyz/void_power/utils/IntBuffer.java new file mode 100644 index 0000000..19e1aa0 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/utils/IntBuffer.java @@ -0,0 +1,30 @@ +package com.dfdyz.void_power.utils; + +import java.util.Arrays; + +public class IntBuffer { + + final int[] buf; + int top = 0; + + public IntBuffer(int capability) { + this.buf = new int[capability]; + } + + public void push(int value){ + buf[top++] = value; + } + + public int getCount(){ + return top; + } + + public void clear(){ + top = 0; + } + + public int[] getCutData(){ + return Arrays.copyOf(buf, top); + } + +} diff --git a/src/main/java/com/dfdyz/void_power/utils/NBTUtils.java b/src/main/java/com/dfdyz/void_power/utils/NBTUtils.java new file mode 100644 index 0000000..601d769 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/utils/NBTUtils.java @@ -0,0 +1,30 @@ +package com.dfdyz.void_power.utils; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.Tag; + +import javax.annotation.Nullable; + +public class NBTUtils { + + public static Tag NBT(BlockPos bp){ + return new IntArrayTag(new int[]{ + bp.getX(),bp.getY(),bp.getZ() + }); + } + + + public static @Nullable BlockPos BlockPos(Tag tag){ + if(tag instanceof IntArrayTag){ + int[] a = ((IntArrayTag)tag).getAsIntArray(); + return new BlockPos(a[0], a[1], a[2]); + } + else { + return null; + } + } + + +} diff --git a/src/main/java/com/dfdyz/void_power/utils/ParamUtils.java b/src/main/java/com/dfdyz/void_power/utils/ParamUtils.java index bdb2603..4d834ab 100644 --- a/src/main/java/com/dfdyz/void_power/utils/ParamUtils.java +++ b/src/main/java/com/dfdyz/void_power/utils/ParamUtils.java @@ -2,7 +2,8 @@ import dan200.computercraft.api.lua.LuaException; -import java.awt.*; +import java.util.HashMap; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -28,6 +29,20 @@ public static int convertColor(int col){ return Integer.reverseBytes(col); } + + + + public static float rangeCheck(float x, float l, float r, int idx) throws LuaException { + if(x > r || x < l) throw new LuaException("Param " + idx + " out of range."); + return x; + } + + + public static int rangeCheck(int x, int l, int r, int idx) throws LuaException { + if(x > r || x < l) throw new LuaException("Param " + idx + " out of range."); + return x; + } + public static int blendColor(int up, int down){ float aup = (up & 0xFF) / 255.f; float adown = (down & 0xFF) / 255.f; @@ -41,7 +56,7 @@ public static int blendColor(int up, int down){ ((int)(((up >> 24) & 0xFF) * a0 + ((down >> 24) & 0xFF) * a1) << 24); } - public static String unicodeToCN(String str) { + public static String unicodeToStr(String str) { Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))"); Matcher matcher = pattern.matcher(str); char ch; @@ -52,6 +67,12 @@ public static String unicodeToCN(String str) { return str; } - + public static Map dumpIntArray(int[] array){ + Map map = new HashMap<>(); + for (int i = 0; i < array.length; i++) { + map.put(i * 1.0, convertColor(array[i])); + } + return map; + } } diff --git a/src/main/java/com/dfdyz/void_power/utils/RaycastUtils.java b/src/main/java/com/dfdyz/void_power/utils/RaycastUtils.java index ee238bc..8b16baf 100644 --- a/src/main/java/com/dfdyz/void_power/utils/RaycastUtils.java +++ b/src/main/java/com/dfdyz/void_power/utils/RaycastUtils.java @@ -1,4 +1,18 @@ package com.dfdyz.void_power.utils; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; + public class RaycastUtils { + + + public static BlockPos GetBlockPos(Vec3 pos){ + int i = Mth.floor(pos.x); + int j = Mth.floor(pos.y); + int k = Mth.floor(pos.z); + return new BlockPos(i,j,k); + } + + } diff --git a/src/main/java/com/dfdyz/void_power/utils/SyncLocker.java b/src/main/java/com/dfdyz/void_power/utils/SyncLocker.java index ac361a5..e43bd7a 100644 --- a/src/main/java/com/dfdyz/void_power/utils/SyncLocker.java +++ b/src/main/java/com/dfdyz/void_power/utils/SyncLocker.java @@ -7,18 +7,14 @@ public SyncLocker(T init){ value = init; } - public void set(T value){ - synchronized (this){ - this.value = value; - } + public synchronized void set(T value){ + this.value = value; } public T getThenSet(T value){ - synchronized (this){ - T org = this.value; - this.value = value; - return org; - } + T org = this.value; + set(value); + return org; } public T get(){ diff --git a/src/main/java/com/dfdyz/void_power/utils/VSUtils.java b/src/main/java/com/dfdyz/void_power/utils/VSUtils.java index 2ae5874..335e2cc 100644 --- a/src/main/java/com/dfdyz/void_power/utils/VSUtils.java +++ b/src/main/java/com/dfdyz/void_power/utils/VSUtils.java @@ -10,6 +10,7 @@ import org.valkyrienskies.core.api.ships.ServerShip; import org.valkyrienskies.core.impl.game.ships.PhysShipImpl; import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.world.RaycastUtilsKt; public class VSUtils { @@ -78,5 +79,4 @@ public static double GetBlockDistanceSqrBetween(@NotNull ServerLevel serverLevel else return bp1.distSqr(bp2); } - } diff --git a/src/main/java/com/dfdyz/void_power/utils/font/ASCII.java b/src/main/java/com/dfdyz/void_power/utils/font/ASCII.java index 15cbe5d..21abc39 100644 --- a/src/main/java/com/dfdyz/void_power/utils/font/ASCII.java +++ b/src/main/java/com/dfdyz/void_power/utils/font/ASCII.java @@ -4,10 +4,6 @@ import static com.dfdyz.void_power.utils.font.Font.all_2_4; public class ASCII { - - - - static boolean[][] get(int[] data){ boolean[][] arr = new boolean[16][8]; int byteCount; diff --git a/src/main/java/com/dfdyz/void_power/utils/font/DefaultFont.java b/src/main/java/com/dfdyz/void_power/utils/font/DefaultFont.java new file mode 100644 index 0000000..db5d3b8 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/utils/font/DefaultFont.java @@ -0,0 +1,12 @@ +package com.dfdyz.void_power.utils.font; + +import dan200.computercraft.api.lua.LuaException; + +public class DefaultFont implements IFontLib{ + public static final DefaultFont Instance = new DefaultFont(); + + @Override + public Font.CharMat get(char ch) throws LuaException { + return Font.getMat(ch); + } +} diff --git a/src/main/java/com/dfdyz/void_power/utils/font/Font.java b/src/main/java/com/dfdyz/void_power/utils/font/Font.java index b5fb4ec..7064a8c 100644 --- a/src/main/java/com/dfdyz/void_power/utils/font/Font.java +++ b/src/main/java/com/dfdyz/void_power/utils/font/Font.java @@ -3,14 +3,16 @@ import com.google.common.collect.Maps; import net.minecraft.client.Minecraft; +import net.minecraft.client.player.Input; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; public class Font { - public static final HashMap Char_Mat_MAP = Maps.newHashMap(); public static class CharMat{ @@ -25,6 +27,7 @@ public CharMat(boolean[][] bitmap){ width = bitmap[0].length; } + /* public void Print(){ for (int i = 0; i < bitmap.length; i++) { for (int j = 0; j < width; j++) { @@ -32,7 +35,7 @@ public void Print(){ } System.out.println("\n"); } - } + }*/ public CharMat(){ this.bitmap = new boolean[16][8]; @@ -99,29 +102,25 @@ public static CharMat getMat(char ch){ static int all_2_4 = 2; static int all_32_128 = 32; - @SuppressWarnings({"OptionalGetWithoutIsPresent", "ResultOfMethodCallIgnored"}) + @SuppressWarnings({"ResultOfMethodCallIgnored"}) protected static byte[] read(int areaCode, int posCode) throws IOException { byte[] data = null; try { int area = areaCode - 0xa0; int pos = posCode - 0xa0; - - InputStream in = Minecraft.getInstance().getResourceManager() - .getResource( - new ResourceLocation("void_power","vp_font/hzk16.bin") - ) - .get().open(); - long offset = all_32_128 * ((area - 1) * 94 + pos - 1); + InputStream in = Font.class.getResourceAsStream("hzk16.bin"); + long offset = all_32_128 * ((area - 1) * 94L + pos - 1); in.skip(offset); data = new byte[all_32_128]; in.read(data, 0, all_32_128); in.close(); - } catch (Exception ex) { + } catch (IOException ex) { throw ex; } return data; } + @SuppressWarnings("CallToPrintStackTrace") protected static int[] getByteCode(String str) { int[] byteCode = new int[2]; try { @@ -133,23 +132,9 @@ protected static int[] getByteCode(String str) { } return byteCode; } - public static InputStream hzkFile; - public static void Init(){ - try { - hzkFile = Minecraft.getInstance().getResourceManager() - .getResource( - new ResourceLocation("void_power","vp_font/hzk16.bin") - ) - .get().open(); - } catch (IOException e) { - throw new RuntimeException(e); - } + public static void Init() { ASCII.Init(); } - static void PrintChar(char ch){ - getMat(ch).Print(); - } - } diff --git a/src/main/java/com/dfdyz/void_power/utils/font/FontLib.java b/src/main/java/com/dfdyz/void_power/utils/font/FontLib.java new file mode 100644 index 0000000..c13b540 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/utils/font/FontLib.java @@ -0,0 +1,60 @@ +package com.dfdyz.void_power.utils.font; + +import com.google.common.collect.Maps; +import dan200.computercraft.api.lua.LuaException; + +import java.util.HashMap; + +public class FontLib implements IFontLib{ + public final HashMap char_map = Maps.newHashMap(); + + public FontLib(){ + + } + + public void put(char ch, boolean[][] charMat){ + char_map.put(ch, new Font.CharMat(charMat)); + } + + public Font.CharMat get(char ch) throws LuaException { + if(char_map.containsKey(ch)){ + return char_map.get(ch); + } + else { + if(char_map.containsKey('?')){ + return char_map.get('?'); + } + if(ch >= 256){ + throw new LuaException(String.format( + "Char %s is not in lib. And not define default char '?'.", + convertToUnicodeStr(ch) + )); + } + else { + throw new LuaException(String.format("Char %s is not in lib. And not define default char '?'.", ""+ch)); + } + } + } + + + static String convertToUnicodeStr(char c) + { + StringBuffer sb = new StringBuffer(12); + int j; + String tmp; + sb.setLength(0); + sb.append("\\u"); + j = (c >>>8); //取出高8位 + tmp = Integer.toHexString(j); + if (tmp.length() == 1) sb.append("0"); + sb.append(tmp); + j = (c & 0xFF); //取出低8位 + tmp = Integer.toHexString(j); + if (tmp.length() == 1) + sb.append("0"); + sb.append(tmp); + return (new String(sb)); + } + + +} diff --git a/src/main/java/com/dfdyz/void_power/utils/font/IFontLib.java b/src/main/java/com/dfdyz/void_power/utils/font/IFontLib.java new file mode 100644 index 0000000..33ffd07 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/utils/font/IFontLib.java @@ -0,0 +1,7 @@ +package com.dfdyz.void_power.utils.font; + +import dan200.computercraft.api.lua.LuaException; + +public interface IFontLib { + Font.CharMat get(char ch) throws LuaException; +} diff --git a/src/main/java/com/dfdyz/void_power/world/blocks/hologram/DefaultFrameBufferImpl.java b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/DefaultFrameBufferImpl.java new file mode 100644 index 0000000..e1ced6c --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/DefaultFrameBufferImpl.java @@ -0,0 +1,44 @@ +package com.dfdyz.void_power.world.blocks.hologram; + +public class DefaultFrameBufferImpl implements IFrameBuffer{ + protected final int w,h; + protected final int[] buffer; + protected int initColor = 0x000000FF; + + public DefaultFrameBufferImpl(int w, int h){ + this.w = w; + this.h = h; + this.buffer = new int[w*h]; + } + + + @Override + public int[] getBuffer() { + return buffer; + } + + @Override + public int getWidth() { + return w; + } + + @Override + public int getHeight() { + return h; + } + + @Override + public IFrameBuffer resize(int w, int h) { + return new DefaultFrameBufferImpl(w,h); + } + + @Override + public int getInitColor() { + return initColor; + } + + @Override + public void setInitColor(int col) { + initColor = col; + } +} diff --git a/src/main/java/com/dfdyz/void_power/world/blocks/hologram/HologramTE.java b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/HologramTE.java index 02f73e1..75ebe08 100644 --- a/src/main/java/com/dfdyz/void_power/world/blocks/hologram/HologramTE.java +++ b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/HologramTE.java @@ -1,19 +1,21 @@ package com.dfdyz.void_power.world.blocks.hologram; +import com.dfdyz.void_power.Config; import com.dfdyz.void_power.client.screen_cache.IScreenCache; import com.dfdyz.void_power.compat.cct.peripherals.P_HologramPeripheral; import com.dfdyz.void_power.menu.HologramMenu; import com.dfdyz.void_power.network.CP.CP_HologramInputEvent; -import com.dfdyz.void_power.network.CP.CP_HologramRename; import com.dfdyz.void_power.network.CP.CP_HologramUpdateRequest; import com.dfdyz.void_power.network.PacketManager; import com.dfdyz.void_power.network.SP.SP_HologramPoseUpdate; import com.dfdyz.void_power.network.SP.SP_HologramRename; -import com.dfdyz.void_power.network.SP.SP_HologramUpdate; -import com.dfdyz.void_power.utils.Debug; +import com.dfdyz.void_power.network.SP.SP_HologramUpdate_A; +import com.dfdyz.void_power.network.SP.SP_HologramUpdate_B; +import com.dfdyz.void_power.utils.IntBuffer; import com.dfdyz.void_power.utils.ParamUtils; import com.dfdyz.void_power.utils.SyncLocker; +import com.google.errorprone.annotations.concurrent.GuardedBy; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; @@ -38,23 +40,25 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.UUID; +import java.util.*; -public class HologramTE extends SmartBlockEntity implements MenuProvider { +import static com.dfdyz.void_power.utils.ByteUtils.maxLengthPerPack; + +public class HologramTE extends SmartBlockEntity implements MenuProvider, IFrameBuffer{ public Behavior behavior; public P_HologramPeripheral peripheral; protected LazyOptional peripheralCap; - public int[] buffer; - public int width = 16, high = 16; - public int initColor = 0x00A0FF6F; + private int[] buffer; + private int[] buffer_last; + + private int width = 16, high = 16; + protected int initColor = ParamUtils.convertColor(0x00A0FF6F); public float offx = 0, offy = 0, offz = 0; public float rotYaw = 0, rotPitch = 0, rotRoll = 0; public float scalex = 1, scaley = 1; public final SyncLocker transformDirty = new SyncLocker<>(false); - public final SyncLocker needSync = new SyncLocker<>(true); public String name = UUID.randomUUID().toString(); @@ -68,7 +72,7 @@ public HologramTE(BlockEntityType type, BlockPos pos, BlockState state) { public P_HologramPeripheral getPeripheral(){ if(peripheral == null){ - System.out.println("New at " + getBlockPos().toShortString()); + //System.out.println("New at " + getBlockPos().toShortString()); peripheral = new P_HologramPeripheral(this); } return peripheral; @@ -92,31 +96,262 @@ public Direction getDirection() { @OnlyIn(Dist.CLIENT) public void clientSync(){ if(needSync.getThenSet(false)){ - // todo - // sync packet PacketManager.sendToServer(new CP_HologramUpdateRequest(this)); } } + /* + public Vec3 TryClick(Player player){ + // W.I.P. + return Vec3.ZERO; + } + */ + + public void UpdateRenderCache(){ + if(renderCache != null){ + renderCache.invalidate(); + } + } + + int force_full_sync_ticker = 0; public void serverSync(){ if(peripheral == null) return; + if(force_full_sync_ticker < Config.ForceFullUpdateTick){ + ++force_full_sync_ticker; + } if(needSync.getThenSet(false)){ - //todo - //sync when screen update - if(peripheral.shouldFullUpdate.getThenSet(false)){ - peripheral.SendFullPack(this); + if(Config.ForceFullUpdateTick > 0 && force_full_sync_ticker >= Config.ForceFullUpdateTick){ + force_full_sync_ticker = 0; + FullSyncPack(); } else { - peripheral.SendLazyPack(this); - + NoFullSyncPack(); } - //peripheral.SendFullPack(this); } if(transformDirty.getThenSet(false)){ PacketManager.sendToAllPlayerTrackingThisBlock(new SP_HologramPoseUpdate(this), this); } } + public void FullSyncPack(){ + // System.out.println("Full Update"); + int[] buffer = this.buffer; + int offset = 0; + + while (offset < buffer.length){ + int[] bf; + + if(buffer.length > offset + maxLengthPerPack){ + bf = new int[maxLengthPerPack+2]; + System.arraycopy(buffer, offset, bf, 2, maxLengthPerPack); + bf[0] = offset; + bf[1] = maxLengthPerPack; + } + else { + int l = buffer.length - offset; + bf = new int[l + 2]; + System.arraycopy(buffer, offset, bf, 2, l); + bf[0] = offset; + bf[1] = l; + } + + offset += maxLengthPerPack; + + PacketManager.sendToAllPlayerTrackingThisBlock(new SP_HologramUpdate_A( + this, + bf + ), this); + } + + System.arraycopy(buffer, 0, buffer_last, 0, buffer.length); + } + + public void NoFullSyncPack(){ + //System.out.println("NoFull Update"); + int[] buffer = this.buffer; + int[] buffer_last = this.buffer_last; + + if(buffer_last == null){ + if(getLevel() != null && !getLevel().isClientSide){ + this.buffer_last = buffer.clone(); + } + return; + } + + // todo + // 统计变更并计算判断需要什么方法来更新 + int dirty_len = 0; + int range_start = -1, range_len = 0; + int capability = maxLengthPerPack; + + // 数据格式 offset, len, c_0, c_1, ....., c_(len-1) + IntBuffer range_buffer = new IntBuffer(maxLengthPerPack + 16); + + // 数据格式 offset, color + IntBuffer sparse_buffer = new IntBuffer(maxLengthPerPack + 4); + + int currColor; + boolean dirty; + + for (int i = 0; i < buffer.length; i++) { + currColor = buffer[i]; + dirty = currColor != buffer_last[i]; + if(dirty){ // 变更 + ++dirty_len; + + if(range_start < 0){ + range_start = i; + range_len = 0; + } + + //System.out.print(i + " "); + } + + if(range_start >= 0) ++range_len; + + if(dirty){ + if(range_len - dirty_len == 1){ + dirty_len = range_len; + } + } + else { + if(range_len > 0){ + if(range_len - dirty_len >= 2){ + // ? 1 0 0 ? ? + // 变更情况 ? 1 0 0 ? ? ? + // 需要写入 + if(dirty_len > 1){ + // 变更情况 ? 1 1 0 0 ? ? ? + // 截断并记录 + //System.out.println("Push"); + // 当前包足够 + //System.out.printf("Push Range %d, %d\n", range_start, range_start + dirty_len); + if(dirty_len + 2 < capability){ + range_buffer.push(range_start); + range_buffer.push(dirty_len); + + int t_len = range_start + dirty_len; + for (int j = range_start; j < t_len; j++) { + range_buffer.push(buffer[j]); + } + capability -= dirty_len + 2; + } + else { // 包满了 + //System.out.println("Overflow"); + while (dirty_len > 0){ + int len = Math.min(dirty_len, capability); + range_buffer.push(range_start); + range_buffer.push(len); + + int t_len = range_start + len; + for (int j = range_start; j < t_len; j++) { + range_buffer.push(buffer[j]); + } + + dirty_len -= len; + + // 发包 + //System.out.println("FP"); + if(len == capability){ + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_A(this, range_buffer.getCutData()), + this); + + range_buffer.clear(); + capability = maxLengthPerPack; + range_start += len; + } + else { + capability -= len + 2; + } + } + } + } + else { + // 变更情况 ? 0 1 0 0 ? ? ? (只变更了一位) + // 记录离散点 + //System.out.printf("Push Point %d\n", range_start); + sparse_buffer.push(range_start); + sparse_buffer.push(buffer[range_start]); + + // todo + // 如果离散点缓冲满了,发包 + if(sparse_buffer.getCount() >= maxLengthPerPack){ + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_B(this, sparse_buffer.getCutData()), + this); + + sparse_buffer.clear(); + } + } + dirty_len = 0; + range_start = -1; + range_len = 0; + } + } + } + } + + if(sparse_buffer.getCount() > 0){ + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_B(this, sparse_buffer.getCutData()), + this); + sparse_buffer.clear(); + } + + if(range_start >= 0){ + //System.out.println("Overflow end."); + if(dirty_len + 2 < capability){ + range_buffer.push(range_start); + range_buffer.push(dirty_len); + + int t_len = range_start + dirty_len; + for (int j = range_start; j < t_len; j++) { + range_buffer.push(buffer[j]); + } + + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_A(this, range_buffer.getCutData()), + this); + + range_buffer.clear(); + } + else { + //System.out.println("Overflow2"); + while (dirty_len > 0){ + int len = Math.min(dirty_len, capability); + range_buffer.push(range_start); + range_buffer.push(len); + + int t_len = range_start + len; + for (int j = range_start; j < t_len; j++) { + range_buffer.push(buffer[j]); + } + + dirty_len -= capability; + range_start += capability; + // 发包 + //System.out.println("FP2"); + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_A(this, range_buffer.getCutData()), + this); + + range_buffer.clear(); + } + } + } + else { + //System.out.println("FP2"); + if(range_buffer.getCount() > 0){ + PacketManager.sendToAllPlayerTrackingThisBlock( + new SP_HologramUpdate_A(this, range_buffer.getCutData()), + this); + range_buffer.clear(); + } + } + System.arraycopy(buffer, 0, buffer_last, 0, buffer.length); + } + @Override public void invalidate() { super.invalidate(); @@ -135,7 +370,6 @@ public void initialize() { super.initialize(); needSync.set(true); transformDirty.set(true); - if(peripheral != null) peripheral.shouldFullUpdate.set(true); } @Override @@ -151,19 +385,17 @@ public void BlitBuffer(int ax, int ay, int w, int h, int[] src){ int offO = (y - ay) * w; int offD = y * width; int edgeR = Math.min(width, ax+w); - for(int x = Math.max(ax, 0); x < edgeR; ++x){ - buffer[offD + x] = src[offO + x - ax]; - } + if (edgeR - Math.max(ax, 0) >= 0) + System.arraycopy(src, offO + Math.max(ax, 0) - ax, buffer, offD + Math.max(ax, 0), edgeR - Math.max(ax, 0)); } } - public int[] MergeBuffer(int w, int h, int[] org, int[] dist){ + public int[] MergeBuffer(int w, int h, int[] org, int[] dist, int initColor){ int[] d = dist; - int init = ParamUtils.convertColor(initColor); if(d == null){ d = new int[w*h]; for (int i = 0; i < w*h; i++) { - d[i] = init; + d[i] = initColor; } } for(int y = 0; y < high && y < h; ++y){ @@ -176,52 +408,83 @@ public int[] MergeBuffer(int w, int h, int[] org, int[] dist){ return d; } - void FillBuffer(int ax, int ay, int w, int h, int color){ - color = ParamUtils.convertColor(color); + void FillBuffer(int ax, int ay, int w, int h, int raw_color){ int[] buffer = this.buffer; for(int y = Math.max(ay, 0); y < high && y < h; ++y) { int offD = y * w; for (int x = Math.max(ax, 0); x < width && x < w; ++x) { - buffer[offD + x] = color; + buffer[offD + x] = raw_color; } } } - public void resize(int w, int h){ + @Override + public IFrameBuffer resize(int w, int h){ if(buffer == null){ buffer = new int[w * h]; FillBuffer(0,0,w,h,initColor); - //Debug.PrintIntArray(buffer); } + if(buffer_last == null && buffer != null){ + if(getLevel() != null && !getLevel().isClientSide){ + buffer_last = buffer.clone(); + } + } + + if(w != width || h != high){ - buffer = MergeBuffer(w,h,buffer, null); + buffer = MergeBuffer(w,h,buffer, null, initColor); + if(getLevel() != null && !getLevel().isClientSide){ + buffer_last = MergeBuffer(w,h, buffer_last, null, initColor+1); + } width = w; high = h; - if(peripheral != null) { - peripheral.shouldFullUpdate.set(true); - } } + return this; } - public void handleLazyUpdatePack(SP_HologramUpdate msg){ - //System.out.println("Received Update Pack"); - if(!msg.lazy){ - resize(msg.w, msg.h); - } - try{ - BlitBuffer(msg.x, msg.y, msg.w, msg.h, msg.buffer); - }catch (Exception e){ - e.printStackTrace(); - } + @Override + public int getInitColor() { + return initColor; + } - if(renderCache != null) renderCache.invalidate(); - //Debug.PrintMsg(msg); - //Debug.PrintIntArray(buffer, width); - //System.out.println("Received Update Pack 2"); + @Override + public void setInitColor(int col) { + initColor = col; } + //todo public void returnFullUpdatePack(ServerPlayer player){ - PacketManager.sendToPlayer(new SP_HologramUpdate(this), player); + int[] buffer = this.buffer; + int offset = 0; + + while (offset < buffer.length){ + int[] bf; + + if(buffer.length > offset + maxLengthPerPack){ + bf = new int[maxLengthPerPack+2]; + System.arraycopy(buffer, offset, bf, 2, maxLengthPerPack); + bf[0] = offset; + bf[1] = maxLengthPerPack; + } + else { + int l = buffer.length - offset; + bf = new int[l + 2]; + System.arraycopy(buffer, offset, bf, 2, l); + bf[0] = offset; + bf[1] = l; + } + + offset += maxLengthPerPack; + + PacketManager.sendToPlayer( + new SP_HologramUpdate_A( + this, + bf + ), + player); + + } + PacketManager.sendToPlayer(new SP_HologramPoseUpdate(this), player); } @@ -244,6 +507,26 @@ public AbstractContainerMenu createMenu(int i, @NotNull Inventory inventory, @No return new HologramMenu(i, this); } + @Override + public int[] getBuffer() { + return buffer; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return high; + } + + @Override + public boolean isTE(){ + return true; + } + public static class Behavior extends BlockEntityBehaviour{ public static final BehaviourType TYPE = new BehaviourType<>(); diff --git a/src/main/java/com/dfdyz/void_power/world/blocks/hologram/IFrameBuffer.java b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/IFrameBuffer.java new file mode 100644 index 0000000..3bc7d69 --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/world/blocks/hologram/IFrameBuffer.java @@ -0,0 +1,17 @@ +package com.dfdyz.void_power.world.blocks.hologram; + + +public interface IFrameBuffer { + int[] getBuffer(); + int getWidth(); + int getHeight(); + + IFrameBuffer resize(int w, int h); + + int getInitColor(); + void setInitColor(int col); + + default boolean isTE(){ + return false; + } +} diff --git a/src/main/java/com/dfdyz/void_power/world/blocks/void_engine/VoidEngineBlock.java b/src/main/java/com/dfdyz/void_power/world/blocks/void_engine/VoidEngineBlock.java index 55e9068..30fcc92 100644 --- a/src/main/java/com/dfdyz/void_power/world/blocks/void_engine/VoidEngineBlock.java +++ b/src/main/java/com/dfdyz/void_power/world/blocks/void_engine/VoidEngineBlock.java @@ -16,9 +16,12 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.energy.IEnergyStorage; public class VoidEngineBlock extends HorizontalKineticBlock implements IBE { + public static final String ID = "void_engine"; + public VoidEngineBlock(Properties properties) { super(properties); } @@ -36,7 +39,7 @@ public boolean skipRendering(BlockState p_60532_, BlockState p_60533_, Direction @Override public VoxelShape getShape(BlockState state, BlockGetter blockReader, BlockPos pos, CollisionContext context) { - return VPShapes.VOID_ENGINE.get(state.getValue(HORIZONTAL_FACING)) ; + return VPShapes.VOID_ENGINE.get(state.getValue(HORIZONTAL_FACING)); } @Override diff --git a/src/main/java/com/dfdyz/void_power/world/items/VRGlassesItem.java b/src/main/java/com/dfdyz/void_power/world/items/VRGlassesItem.java new file mode 100644 index 0000000..63f67cb --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/world/items/VRGlassesItem.java @@ -0,0 +1,79 @@ +package com.dfdyz.void_power.world.items; + +import com.dfdyz.void_power.registry.VPItems; +import com.dfdyz.void_power.utils.NBTUtils; +import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import com.simibubi.create.content.equipment.armor.BaseArmorItem; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + + +public class VRGlassesItem extends BaseArmorItem { + public static final EquipmentSlot SLOT = EquipmentSlot.HEAD; + public static final ArmorItem.Type TYPE = ArmorItem.Type.HELMET; + public static final String ID = "vr_glasses"; + + public VRGlassesItem(ArmorMaterial armorMaterial, Properties properties, ResourceLocation textureLoc) { + super(armorMaterial, TYPE, properties, textureLoc); + } + + @Override + public void verifyTagAfterLoad(CompoundTag tag) { + + } + + static final String T_VR_HUB = "vr_hub_pos"; + static final String T_VR_DIM = "vr_hub_dim"; + + public static BlockPos getTE(Player player, ItemStack item){ + CompoundTag nbt = item.getOrCreateTag(); + if(nbt.contains(T_VR_HUB)){ + return NBTUtils.BlockPos(nbt.get(T_VR_HUB)); + } + return null; + } + + public static ResourceLocation getDim(ItemStack item){ + CompoundTag nbt = item.getOrCreateTag(); + if(nbt.contains(T_VR_DIM)){ + return new ResourceLocation(nbt.getString(T_VR_DIM)); + } + return null; + } + + @Override + public @NotNull InteractionResult useOn(UseOnContext uoc) { + BlockPos bp = uoc.getClickedPos(); + Player player = uoc.getPlayer(); + if(player != null && player.isShiftKeyDown() && uoc.getLevel().getBlockEntity(bp) instanceof HologramTE){ + CompoundTag nbt = uoc.getItemInHand().getOrCreateTag(); + nbt.put(T_VR_HUB, NBTUtils.NBT(bp)); + nbt.putString(T_VR_DIM, uoc.getLevel().dimension().location().toString()); + System.out.println("Bind."); + } + return super.useOn(uoc); + } + + @Override + public @NotNull InteractionResultHolder use(@NotNull Level level, Player player, InteractionHand hand) { + if(player.isShiftKeyDown()) return InteractionResultHolder.success(player.getItemInHand(hand)); + return super.use(level, player, hand); + } +} diff --git a/src/main/java/com/dfdyz/void_power/world/physics/HologramClickManager.java b/src/main/java/com/dfdyz/void_power/world/physics/HologramClickManager.java new file mode 100644 index 0000000..0294fdb --- /dev/null +++ b/src/main/java/com/dfdyz/void_power/world/physics/HologramClickManager.java @@ -0,0 +1,126 @@ +package com.dfdyz.void_power.world.physics; + +import com.dfdyz.void_power.world.blocks.hologram.HologramTE; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import org.joml.primitives.AABBd; +import org.joml.primitives.AABBdc; +import org.valkyrienskies.core.api.ships.LoadedShip; +import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; +import org.valkyrienskies.mod.common.world.RaycastUtilsKt; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + + +public class HologramClickManager { + /* + public static final Map> ManagedTE = Maps.newHashMap(); + + public static void AddHologram(HologramTE hologramTE){ + if(hologramTE.getLevel() != null){ + ChunkPos cp = hologramTE.getLevel().getChunkAt(hologramTE.getBlockPos()).getPos(); + Set s; + if(!ManagedTE.containsKey(cp)){ + s = Sets.newHashSet(); + ManagedTE.put(cp, s); + } + else { + s = ManagedTE.get(cp); + } + s.add(hologramTE); + } + } + + public static void Clean(){ + List should_remove = Lists.newLinkedList(); + ManagedTE.forEach((k, v) -> { + v.removeIf(BlockEntity::isRemoved); + if(v.isEmpty()){ + should_remove.add(k); + } + }); + should_remove.forEach(ManagedTE::remove); + } + + public static void RayCastHologram(Player player){ + if (player.level() == null) return; + Vec3 from = player.getEyePosition(); + Vec3 to = player.getForward().multiply(64, 64, 64).add(from); + + + BlockHitResult bhr = RaycastUtilsKt.clipIncludeShips(player.level(), + new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player), true); + + double distance = 64; + if(bhr.getType() != HitResult.Type.MISS){ + distance = bhr.getLocation().distanceTo(from); + } + + + // for minecraft + RCH rch0 = RayCastHologramAroundChunk(player.chunkPosition(), player, distance); + // for vs + AABBdc clipAABB = (new AABBd(VectorConversionsMCKt.toJOML(from), + VectorConversionsMCKt.toJOML(to))).correctBounds(); + + Iterator ships = VSGameUtilsKt.getShipObjectWorld(player.level()) + .getLoadedShips().getIntersecting(clipAABB).iterator(); + + // todo + + + + } + + static final int[][] map = new int[][]{ + {0, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 0}, + {-1, 1}, {1, -1}, {-1, -1}, {1, 1} + }; + + public record RCH(HologramTE te, Vec3 pos, double d){ + public RCH Lower(RCH a, RCH b){ + return a.d < b.d ? a : b; + } + } + + public static RCH RayCastHologramAroundChunk(ChunkPos pos, Player player, double d){ + AtomicReference te = new AtomicReference<>(); + AtomicReference a_clicked = new AtomicReference<>(); + AtomicReference d_ = new AtomicReference<>(d); + for (int i = 0; i < map.length; i++) { + ChunkPos cp = new ChunkPos(pos.x + map[i][0], pos.z + map[i][1]); + if(ManagedTE.containsKey(cp)){ + Set s = ManagedTE.get(cp); + s.forEach((e) -> { + Vec3 clicked = e.TryClick(player); + if(clicked != null){ + //todo + + // check + if(clicked.distanceTo(player.getEyePosition()) < d_.get()){ + d_.set(d); + te.set(e); + a_clicked.set(clicked); + } + } + }); + } + } + return new RCH(te.get(), a_clicked.get(), d_.get()); + } + */ + +} diff --git a/src/main/resources/assets/void_power/lang/backup/en_us.json b/src/main/resources/assets/void_power/lang/backup/en_us.json index c888197..af3d598 100644 --- a/src/main/resources/assets/void_power/lang/backup/en_us.json +++ b/src/main/resources/assets/void_power/lang/backup/en_us.json @@ -2,5 +2,7 @@ "block.void_power.engine_controller": "Engine Controller", "block.void_power.void_engine": "Void Engine", "block.void_power.glass_screen":"GlassScreen", - "itemGroup.void_power.main": "Void Power" + "item.void_power.vr_glasses": "VR Glasses", + "itemGroup.void_power.main": "Void Power", + "key_bind.vr_glasses": "Toggle VR Glasses" } \ No newline at end of file diff --git a/src/main/resources/assets/void_power/lang/backup/zh_cn.json b/src/main/resources/assets/void_power/lang/backup/zh_cn.json index 34872df..eee54f9 100644 --- a/src/main/resources/assets/void_power/lang/backup/zh_cn.json +++ b/src/main/resources/assets/void_power/lang/backup/zh_cn.json @@ -2,5 +2,7 @@ "block.void_power.engine_controller": "引擎控制器(电脑外设)", "block.void_power.void_engine": "虚空引擎", "block.void_power.glass_screen":"玻璃屏幕(电脑外设)", - "itemGroup.void_power.main": "虚空动力" + "item.void_power.vr_glasses": "VR Glasses", + "itemGroup.void_power.main": "虚空动力", + "key_bind.vr_glasses": "开关VR研究" } \ No newline at end of file diff --git a/src/main/resources/assets/void_power/models/item/vr_glasses.json b/src/main/resources/assets/void_power/models/item/vr_glasses.json new file mode 100644 index 0000000..9ad4bfa --- /dev/null +++ b/src/main/resources/assets/void_power/models/item/vr_glasses.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "void_power:item/vr_glasses" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/void_power/textures/block/term_font_neg.png b/src/main/resources/assets/void_power/textures/block/term_font_neg.png new file mode 100644 index 0000000000000000000000000000000000000000..d4f21c8009b029912fa1fb23f048ac720b381e36 GIT binary patch literal 3856 zcmdT{X;72N)_xOKbpWF>s1QKVaWoS^K~xep!30Ec8ChgUhh0Dr2q8d%8=%OdEGnBb z5F7=9tO3HNII>DeSRx4_2tt661PFm)&BeJhRbSOtb?@)ne@<7QuG7`$IsH7R6EE4K z6}Io+4gi3HwUy-+003=GL4dsMmT?LF-5UTD8P=BOS0i)y?4gM9qdUzmuaMRyy4)rM zw`Z4j-#u8|6FdDm!93{l8M7RQaBF}xi5kMVG6v5sRv@DQi@DF>iJ6xp*h|dk@8*-J zO1^bqGuC`mS@k$?xytq?5u03ho111-Ctg8y1$7CD%gN>@60A}Q!b7*w?3NVIIU2?KFrKISen*E>RMJS8}MW+V2r(I)qiya3G9Xj zWTRD<)mlQPEPm#vwOmnGi1IQv->4ItwAyilC$d*e-|N?*fwo`WJ(%(@G4E{Jto*{G z%8>9zxC8EdT94<+fP2JpCU4(?1BaJW`|B;R0uOzQQDrf%lT@mfm~K>p{yiQ0Rm5;HCg>)fcHL}J<#-giR_hBM5Xrxo(298HK2jK9TpTsK$*jj*C*%~|Q$Qi!ukPEFUR0`@j?y*i9@a}5WwTwRaKFC(wlD@@H z@MUIiaha{gG;(D9$_q^T_z}i-%_Q(>_3W8)BdeIp=Tv;L?y6@3CUD8L9*kkkRb9Q_ zxR3`#l|@$}GEDEKFcbQH%jwVCAAmDon*^O^q*~zenYVk#C+VI^yKUs`? z`ng9+6r>NHBlY3zcX~55`Pd(Y)J)SCm<)<-|JeR6Frn(613gMogAE9;$E3XPKAuOu zVP*c3tOBm3^k&`hugdif=gx*32vMrVQqFDs2GIcbWnh0=GOfhv<5xk-UuPVI-k1e)Ahp`;#@erlL--XQxE%ZV8b#d+_km4i)FikB=~JV@8Rwo_<>+#!E$Q<# z27gUk)g1|wq1TlJNqkis+ZNNQpZauuP`#YszMV{P})oSPzwktPga8i6c-d%4O5|7p6__y8o( z`G|Y5#>%={ys%&!fqNU41UVS{rFM z!Y+az7cN^G^(KtWt|!orpKD4x)Z*J>u8xlYtH%pdg8irUa|e#PQ`(KaQhvHY(xW6f z%4zz2uxLZ2ui2PuTL_>kV{cym7XETUl0miGIx@sH}8T7^e( z;dL!RB#vweqNn{*c!XlhQ;z664lF=9Fr&cuJm_AWTy+;PyRQYrpHfIQ4<9{HyoMw?^;)Vdvfosif*G!rm9v+y!IhQb) z_C@~>{X%&FSpA2AD0V>mTjeEjO1j~bvaAvHV&Z`^bf8QVMcIascfnCS-xxL-b7_m1 z^I5*tl%Hc2m?;iEYP!)ZZrG&h`{BwA2i|Dj`V-fHQT0JX z=Zl*QmFf6_y2mwXmw~8}+rY?`!By9{&ThjU)XR{JU$dut-QCT z?pvj9;d|`1qULJSsS2AwpUokksiB3Eb(+r-40B}+yB7rfRnwp4fP)|90jnec_=~nF zVX!$XEXTfC>eha%q|%n`u7DIzn4aJs;=-n=I35(BDf6{gv`EPSfE&?RwBTi^?F z#6DHUib$I&(#;Dk8TkbkF0kfTvGABbq=()d_eNVd4T%Hp07zSBnS`$_nmMq37A>{w z22Ag-#LYqh)X9$Y2K#!<)9&9LZWR6WdVRp_oL5SN0G{C_1|-lnuIjHTv(3XJD*>Ot%$hJXeB2bb&$7EkOx4H1fK{7p5F1rmdf-FtyV8ig|u&} z%4}|E;}>Ftihpi7=p!ymr%mW@bCCk^6`RB_jGP~8pEd@kMwD0k(L=OT6k+^^+EPR< zT2(qKJlz29>K~t(-=oy=gd_6|`aaLA3YsS>M&$0%EQJu-9`>9!GlOgg9NY{7OCNT5t-h8jLtfM7ReNZj*}O6WH2tha z-5mk|v-2a{_70ubf?N1aINJE-5e;D%0`4BZaFlg>_MwQ(^ni|Ai}DVKIv$^%$R&=P z=f(H93p0)r z`=#IF7JOqi0*lqq5X7q2X7wIzAqfMo^?fFh+_h>n=%Mg6Xj2nONZ<4@ulfl&5t`+CNx5@K`G2=%Sm#`nm zU>wUa){QMoJ=zh3`7>!grXC-3O*lI;J-223!d4eC@@`;B<%On-Jb)6glesZ&P@TIAaS(xCBavr!C;xW^IF0 z9>;Fl$A0~Ae@;g0ohLdLsq&3}a|!=u^?&I2Z#2HOp8vEb-$?&IxL-Hz+2iXaskn;z lTOj_!-v1Knf6u+4v|sXWb}Zfc%+^mAus&;RNjl?k=U*P(Kh^*M literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/void_power/textures/gui/hud/vr_glasses_no_signal.png b/src/main/resources/assets/void_power/textures/gui/hud/vr_glasses_no_signal.png new file mode 100644 index 0000000000000000000000000000000000000000..15c443633a69e6cda65ba691307d334a2495ce66 GIT binary patch literal 3108 zcmbW3S2!Dt!^K01sJ)4zHlZj=lo}DARciHBQmd)eVZ2eJc8wxNW487VwL*<5tx>hb zEM6fo`YI|hDiuQg``!I7zN_!zob&vi=iHpTlWb#c%5fQd82|uqn47`v{$$J_8G?X+ zd}cm6`cE*R>`Y;RM*NlSKfvT|WMu>ZG-t4#c`*NB)&Mgn6aXM7`@do^x0Bfi0N6Us z;YJRjuH<|c2LVU$&_xEZpd6IM&%fI zHU2+1yB5MoJ$q9X0Cs~>?n{7LP7 z#Pf`@w@ZZ`dkOPI)?FMRA`-v8Ew9x(cq-`cHuh1|Qj6gK4^@~$VjS5kh;aanDM(y69VCm6@I{NX9OAR!%E$eo@&7aI^_ zHB^Vn!+|JsuOAR7B8#+=e`d6Ag~Ai}`udsCosrU$%xuK_FV}g)iJydm4()2H!kG1z z8~evJ(k}X8Tv8A3z0jIL7+%_#(a55Q{`$nOG)9=g;J zowWNSC$Y3_h?__Jl7Xc23-!z@Pv#QQwuWnMQn`FZ6o%BaN7tjq^^dkA&6iLYI9!dP z!+yaf(j1t@9qyAE1lQjh zV6x-4PG1Hhy6k)>&--dkIT_FRzN{`B+%Gw@=hjdE&5af`-Dr|9+3=s1aG#xjGdvcu z{=2Ph5E^mh5z!iSJ+~=}Z+qc%KT2o1ma(Qz1Lj#J%gzqow;AS175-He^o@w)o@Es& zDvd#c#Kbe!7z}y|KN#!lN2|oi#=gq~-#9x)_61mt^RftRRBB>`pJOBS3uSRgN1A(c zGe=mN{p$H&0aM2T!K0h!R#VT8`00tX68ILbLU=2Wo!*$xkElHG-kLfu5z$gAgj{3$72 z8?bx{Slot(oQl5Q69c@PaQyfa?OM|xQ&w9WVXSmc~%1n|16k}i@rO-2AF9%Q8ev%(| zO}BUrDJOSBSP_1^xbHI+GCl!0(Zv^vG9n0eG`ehH4>DOA7xb@Gv7dNJs|Zp&W#b$h z1x_r%GrPlW^p=+!lWUuS+UV!2s~FJk;!ha}q~X2W>gq;P%5tphEe&^X`~Dt;{o@zi z1$bzbdUjEiQQ4*AugpaS3~=9&tNJkZMR(#ae*M*H)AshqwBZ;Ia45LxQ#TXeAUPq+ zK3!o&Q$e+Zx8LS-^AJa>=tqg4u1Sd*At^_-^CJ_eL35s!B_p8Yr8@?l40|6BIIHih zfbL|BT_CLyai>fya;qmIKUTj-CTiHnE!iZs03|$sjv$!5a0$)4m7$Ps+S)W`*8C;>WxKt;o-2Lp5CS?C(vbjTfDS>oRiK4KZusb zfF&;Lq{bK}PqfjRBxh;Ew4(i;NX)Dc(Mmo-c5{2{E*h?>uQW%BvowQzmHHflif=XX z%#jVIgfo&P*o^PywCh(7Q_0bSlU8mS2|tBUik`mHzq23syTu$JkNe6H`c2-iFlT3I zp@ZYQdsp>6>K8+f30{xwNB?_ z7;#8`jAU|qmtQ4k+gTC4LXOadVcAM~Aehrckf~S#7?a+hJa$s83;kw!D~i>m3QHI8 zb0l5=oc`KZZ=dx6chBi_x!`DxoMU^Y=_{7Ncef4`V)O}6p~n{=0p{L}wyqvu;>=30 zr2LaPXKONfdiHujoiOjUsts~D7Wthh9|rjcx6NGXvZG3UQZW7`B%;|iH{IzMorQqVdyk;ht)bOkpI;5n`I|_v_s3a7Q1esvjVrt&DuXZX?TU7nS zk1hKulgLuwXx|tRg24Ma-)F+wJo%QL>d6i4KG?R!#e8oJWA&Of&UCQhmJg0CXZ8J?*YjomV209iqvlu(?eo_9fz`DbNV5Q|#vml}fh2IQejNU;BX8DHyG(hP(h4 z;45kt#kK!-DV<&>yklvr5zLqRgbvtjR9Oh^-J*}f1>bcjeM5@HN)aZ%v)?b&IO)10 z&*JfKegf@mEH7X^2;^vZe5r`_&&ZE^y$>6E2pSE>x{7vU&qzO=+Tf2zK zs7f*{psc1z0C%KbuJPNkMV{5U*x^Mys#+B39VO{)yah|P%yi43Lm zNNhO(;P^Dx?r~?^s)q1rE6)UO^W}x!(IPG-zafuBdpL z<>mU&Py2!P(gKUe^wt35xL=z}66<6~(op3vxlqh!-_nA7uyVW+8d-MDXGLl)R9H7K z#oBFc$t~=}zFRi_M(|t|o?9$I&wQSvV-p*uDb}qO&FWfmaa|SqbzbCWluHGQVaf`d zox6{`hjM<(YNFLJ-f+K*d&oK!?hzOwZU(9FS^arf#1kUJt2Eyoi_VLzywhgA-Jk-M zXBW-MbkLdd=lk|;BwJRF8NK6PtiWe_@VmWqC*k(4wp6%nd+ATLsV1S>jD~<+zCgtl z#E!YR$!(>Jm!@TVdT%t@S>Vhz%Ich=4s~{)qCOB?T2$=rtjw$p^|fm5{D{nT`~We@ zE-@DwAM5K$6bwBLt3E6@`?v)1&7(`JPCDJRm?nU9ZF#03& z<631g*|^RZkN*e9C!3SJErxM`D>{1jSEoc6jtygFy_~n2TiBDdzhezP5WXrV+q(&a+US{#J&619w93&5Bx=32e_? zoYB0^z|Qia&AG$&e_u9cUZ|eoI)75}I*FQWp~|w4O5ThH-7NEBm&ABU&RNQE!TQ2N z)k|MPcqF^;F?uR|n)I&ZLl?iGpuS3~?}j7)>gH9vi>_W4TjG*;anb1n3s1>SN@U5!?6BoYyu%l!L(lB3d=2M-yu{$?>gTe~DWM4f({)xl literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/void_power/textures/models/armor/vr_glasses_layer_1.png b/src/main/resources/assets/void_power/textures/models/armor/vr_glasses_layer_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ea178adf840c9635eefbac0ac0d546d91f665cd7 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0WiR6&^0Gf3qFP%zZf#W5tq`R%2RybT6C3#@w z=YW|Gt5Z?C!xFEFyN|`+_G4h+(V8A~?nQfY