diff --git a/package.json b/package.json index b9b5dc59..31c179dc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "devDependencies": { "@types/node": "^22.9.3", "esbuild": "^0.24.0", - "execa": "^5.5.1", + "execa": "^5.1.1", "glob": "^11.0.0", "tsx": "^4.19.2" }, diff --git a/src/generated/resources/assets/kasuga_lib/models/panel/arrow.geo.json b/src/generated/resources/assets/kasuga_lib/models/panel/arrow.geo.json new file mode 100644 index 00000000..0cbe9948 --- /dev/null +++ b/src/generated/resources/assets/kasuga_lib/models/panel/arrow.geo.json @@ -0,0 +1,71 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 16, + "texture_height": 16, + "visible_bounds_width": 2, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "bone", + "pivot": [0, 1.5, 0], + "cubes": [ + { + "origin": [-0.5, 0, -0.5], + "size": [1, 11, 1], + "uv": { + "north": {"uv": [1, 1], "uv_size": [1, 11]}, + "east": {"uv": [0, 1], "uv_size": [1, 11]}, + "south": {"uv": [3, 1], "uv_size": [1, 11]}, + "west": {"uv": [2, 1], "uv_size": [1, 11]}, + "up": {"uv": [1, 0], "uv_size": [1, 1]}, + "down": {"uv": [2, 1], "uv_size": [1, -1]} + } + }, + { + "origin": [-0.75, 12, -0.75], + "size": [1.5, 1, 1.5], + "uv": { + "north": {"uv": [5, 4], "uv_size": [1, 1]}, + "east": {"uv": [4, 4], "uv_size": [1, 1]}, + "south": {"uv": [7, 4], "uv_size": [1, 1]}, + "west": {"uv": [6, 4], "uv_size": [1, 1]}, + "up": {"uv": [5, 3], "uv_size": [1, 1]}, + "down": {"uv": [6, 4], "uv_size": [1, -1]} + } + }, + { + "origin": [-1, 11, -1], + "size": [2, 1, 2], + "uv": { + "north": {"uv": [6, 2], "uv_size": [2, 1]}, + "east": {"uv": [4, 2], "uv_size": [2, 1]}, + "south": {"uv": [10, 2], "uv_size": [2, 1]}, + "west": {"uv": [8, 2], "uv_size": [2, 1]}, + "up": {"uv": [6, 0], "uv_size": [2, 2]}, + "down": {"uv": [8, 2], "uv_size": [2, -2]} + } + }, + { + "origin": [-0.5, 13, -0.5], + "size": [1, 1, 1], + "uv": { + "north": {"uv": [5, 6], "uv_size": [1, 1]}, + "east": {"uv": [4, 6], "uv_size": [1, 1]}, + "south": {"uv": [7, 6], "uv_size": [1, 1]}, + "west": {"uv": [6, 6], "uv_size": [1, 1]}, + "up": {"uv": [5, 5], "uv_size": [1, 1]}, + "down": {"uv": [6, 6], "uv_size": [1, -1]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/models/panel/arrow.json b/src/generated/resources/assets/kasuga_lib/models/panel/arrow.json new file mode 100644 index 00000000..5d8c93fe --- /dev/null +++ b/src/generated/resources/assets/kasuga_lib/models/panel/arrow.json @@ -0,0 +1,6 @@ +{ + "loader": "kasuga_lib:bedrock_model", + "model": "kasuga_lib:panel/arrow", + "texture": "kasuga_lib:panel/arrow_texture", + "render_type": "translucent" +} \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/models/panel/panel.geo.json b/src/generated/resources/assets/kasuga_lib/models/panel/panel.geo.json new file mode 100644 index 00000000..f0769885 --- /dev/null +++ b/src/generated/resources/assets/kasuga_lib/models/panel/panel.geo.json @@ -0,0 +1,35 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 128, + "texture_height": 128, + "visible_bounds_width": 3, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.25, 0] + }, + "bones": [ + { + "name": "bb_main", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-11, 0, -14], + "size": [22, 0, 28], + "uv": { + "north": {"uv": [28, 28], "uv_size": [22, 0]}, + "east": {"uv": [0, 28], "uv_size": [28, 0]}, + "south": {"uv": [78, 28], "uv_size": [22, 0]}, + "west": {"uv": [50, 28], "uv_size": [28, 0]}, + "up": {"uv": [28, 0], "uv_size": [22, 28]}, + "down": {"uv": [28, 28], "uv_size": [22, -28]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/models/panel/panel.json b/src/generated/resources/assets/kasuga_lib/models/panel/panel.json new file mode 100644 index 00000000..685f58c0 --- /dev/null +++ b/src/generated/resources/assets/kasuga_lib/models/panel/panel.json @@ -0,0 +1,6 @@ +{ + "loader": "kasuga_lib:bedrock_model", + "model": "kasuga_lib:panel/panel", + "texture": "kasuga_lib:panel/panel_texture", + "render_type": "translucent" +} \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/textures/panel/arrow_texture.png b/src/generated/resources/assets/kasuga_lib/textures/panel/arrow_texture.png new file mode 100644 index 00000000..31405d57 Binary files /dev/null and b/src/generated/resources/assets/kasuga_lib/textures/panel/arrow_texture.png differ diff --git a/src/generated/resources/assets/kasuga_lib/textures/panel/panel_texture.png b/src/generated/resources/assets/kasuga_lib/textures/panel/panel_texture.png new file mode 100644 index 00000000..f6e2584b Binary files /dev/null and b/src/generated/resources/assets/kasuga_lib/textures/panel/panel_texture.png differ diff --git a/src/generated/resources/kasuga.mixins.json b/src/generated/resources/kasuga.mixins.json index deb340ba..c8cc9371 100644 --- a/src/generated/resources/kasuga.mixins.json +++ b/src/generated/resources/kasuga.mixins.json @@ -14,6 +14,7 @@ "client.MixinBlockModel$Deserializer", "client.MixinBlockModelBinding", "client.MixinBlockModelShaper", + "client.MixinLevelRenderer", "client.MixinModelBakery", "client.MixinTextureManager" ], diff --git a/src/main/java/kasuga/lib/core/KasugaLibClient.java b/src/main/java/kasuga/lib/core/KasugaLibClient.java index 97bd80ff..7a833627 100644 --- a/src/main/java/kasuga/lib/core/KasugaLibClient.java +++ b/src/main/java/kasuga/lib/core/KasugaLibClient.java @@ -1,15 +1,19 @@ package kasuga.lib.core; +import kasuga.lib.core.client.model.BedrockModelLoader; +import kasuga.lib.core.client.model.model_json.UnbakedBedrockModel; import kasuga.lib.core.client.render.texture.ImageMask; import kasuga.lib.core.client.render.texture.StaticImage; import kasuga.lib.core.client.render.texture.StaticImageHolder; import kasuga.lib.core.util.LazyRecomputable; import kasuga.lib.core.util.data_type.Pair; +import kasuga.lib.core.util.projectile.PanelRenderer; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import java.io.IOException; +import java.util.HashSet; import static kasuga.lib.KasugaLib.MOD_ID; @@ -19,5 +23,13 @@ public class KasugaLibClient { public static final StaticImageHolder NO_IMG = new StaticImageHolder(new ResourceLocation(MOD_ID, "textures/gui/no_img.png")); + public static final LazyRecomputable panel = + BedrockModelLoader.fromFile(new ResourceLocation(MOD_ID, "panel/panel")); + + public static final LazyRecomputable arrow = + BedrockModelLoader.fromFile(new ResourceLocation(MOD_ID, "panel/arrow")); + + public static final HashSet PANEL_RENDERERS = new HashSet<>(); + public static void invoke() {} } diff --git a/src/main/java/kasuga/lib/core/addons/node/AssetReader.java b/src/main/java/kasuga/lib/core/addons/node/AssetReader.java index 9f24a42c..f23d2c97 100644 --- a/src/main/java/kasuga/lib/core/addons/node/AssetReader.java +++ b/src/main/java/kasuga/lib/core/addons/node/AssetReader.java @@ -17,14 +17,16 @@ public class AssetReader implements BiFunction { private final HashMap assets; private final JavascriptContext context; private final String dirname; + private final String assetRoot; ResourceProvider provider; - public AssetReader(String dirname, JavascriptContext context, ResourceProvider provider, HashMap assets) { + public AssetReader(String dirname, JavascriptContext context, ResourceProvider provider, HashMap assets, String assetRoot) { this.provider = provider; this.context = context; this.assets = assets; this.dirname = dirname; + this.assetRoot = assetRoot == null ? "/" : assetRoot; } @HostAccess.Export @@ -45,6 +47,16 @@ public String apply(String path, String resourceType){ ) ); } + path = PackageScanner.joinPath( + PackageScanner.resolve( + PackageScanner.splitPath( + assetRoot + ), + PackageScanner.splitPath( + path + ) + ) + ); UUID uuid; do{ uuid = UUID.randomUUID(); diff --git a/src/main/java/kasuga/lib/core/client/frontend/commands/FrontendCommands.java b/src/main/java/kasuga/lib/core/client/frontend/commands/FrontendCommands.java index 62d08e5d..88c132a2 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/commands/FrontendCommands.java +++ b/src/main/java/kasuga/lib/core/client/frontend/commands/FrontendCommands.java @@ -16,6 +16,7 @@ import net.minecraft.network.chat.TextColor; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -82,9 +83,7 @@ public void run() { return; } ResourceLocation id = getParameter("id", ResourceLocation.class); - RenderSystem.recordRenderCall(()->{ - Minecraft.getInstance().setScreen(KasugaLib.STACKS.GUI.get().create(id).createScreen()); - }); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, ()->()->GuiScreenHelper.createAndAttach(id)); } }).submit(REGISTRY); @@ -126,7 +125,7 @@ public void run() { .addLiteral("gui", false) .addLiteral("instances", false) .addLiteral("inspect", false) - .addResourceLocation("id", false) + .addString("id", false) .onlyIn(Dist.CLIENT) .setHandler(new CommandHandler(){ @Override @@ -134,10 +133,8 @@ public void run() { if(KasugaLib.STACKS.GUI.isEmpty()){ return; } - ResourceLocation id = getParameter("id", ResourceLocation.class); - RenderSystem.recordRenderCall(()->{ - Minecraft.getInstance().setScreen(KasugaLib.STACKS.GUI.get().create(id).createScreen()); - }); + UUID id = UUID.fromString(getParameter("id", String.class)); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, ()->()->GuiScreenHelper.attach(id)); } }).submit(REGISTRY); diff --git a/src/main/java/kasuga/lib/core/client/frontend/commands/GuiScreenHelper.java b/src/main/java/kasuga/lib/core/client/frontend/commands/GuiScreenHelper.java new file mode 100644 index 00000000..f01a8a21 --- /dev/null +++ b/src/main/java/kasuga/lib/core/client/frontend/commands/GuiScreenHelper.java @@ -0,0 +1,27 @@ +package kasuga.lib.core.client.frontend.commands; + +import com.mojang.blaze3d.systems.RenderSystem; +import kasuga.lib.KasugaLib; +import kasuga.lib.core.client.frontend.gui.GuiInstance; +import kasuga.lib.core.client.frontend.gui.GuiScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; + +import java.util.UUID; + +public class GuiScreenHelper { + public static void attach(UUID instanceId){ + GuiInstance instance = KasugaLib.STACKS.GUI.orElseThrow().getInstanceById(instanceId).get(); + if(instance == null) + return; + RenderSystem.recordRenderCall(()->{ + Minecraft.getInstance().setScreen(new GuiScreen(instance)); + }); + } + + public static void createAndAttach(ResourceLocation location){ + RenderSystem.recordRenderCall(()->{ + Minecraft.getInstance().setScreen(KasugaLib.STACKS.GUI.get().create(location).createScreen()); + }); + } +} diff --git a/src/main/java/kasuga/lib/core/client/frontend/commands/MetroModuleLoader.java b/src/main/java/kasuga/lib/core/client/frontend/commands/MetroModuleLoader.java index c70d04f3..8aacf364 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/commands/MetroModuleLoader.java +++ b/src/main/java/kasuga/lib/core/client/frontend/commands/MetroModuleLoader.java @@ -106,8 +106,8 @@ protected JavascriptEngineModule load( module.getDirectoryName(), javascriptContext, moduleInfo.getProvider(), - KasugaLib.STACKS.JAVASCRIPT.ASSETS.get() - )); + KasugaLib.STACKS.JAVASCRIPT.ASSETS.get(), + "/")); return module; }catch (IOException e){ diff --git a/src/main/java/kasuga/lib/core/client/frontend/gui/GuiContext.java b/src/main/java/kasuga/lib/core/client/frontend/gui/GuiContext.java index bc35e24e..e40ad361 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/gui/GuiContext.java +++ b/src/main/java/kasuga/lib/core/client/frontend/gui/GuiContext.java @@ -13,8 +13,10 @@ import kasuga.lib.core.javascript.Tickable; import net.minecraft.resources.ResourceLocation; +import java.util.ArrayDeque; import java.util.HashMap; import java.util.Optional; +import java.util.Queue; import java.util.concurrent.locks.ReentrantLock; @V8Convert() @@ -30,7 +32,7 @@ public class GuiContext extends DomContext implements Tic public GuiContext(GuiInstance guiInstance, DOMPriorityRegistry registry, ResourceLocation location) { super(registry, location); - layoutEngine = LayoutEngines.YOGA; + layoutEngine = LayoutEngines.YOGA.get(); this.guiInstance = guiInstance; } @@ -77,6 +79,11 @@ public void removeSourceInfo(Object source) { @Override public void tick() { + if(!isRendering){ + this.renderLock.lock(); + beforeRenderTick(); + this.renderLock.unlock(); + } super.tick(); this.getRootNode().getLayoutManager().tick(); } @@ -93,6 +100,19 @@ public void render(Object source, RenderContext context){ } + Queue afterRenderTickTasks = new ArrayDeque<>(32); + + public void beforeRenderTick(){ + Runnable task; + while((task = afterRenderTickTasks.poll()) != null){ + task.run(); + } + } + + public void enqueueAfterRenderTask(Runnable runnable) { + this.afterRenderTickTasks.add(runnable); + } + public void queueDuringRender(Runnable task) { Optional threadContext = this.getRenderer().getContext(); if(threadContext.isEmpty()){ @@ -102,17 +122,16 @@ public void queueDuringRender(Runnable task) { JavascriptContext context = threadContext.get(); if(!this.isRendering){ this.renderLock.lock(); - context.beforeRenderTick(); + beforeRenderTick(); RuntimeException _e = null; try{ task.run(); }catch (RuntimeException e){ - _e = e; + e.printStackTrace(); } this.renderLock.unlock(); - if(_e!=null) throw _e; }else{ - context.enqueueAfterRenderTask(task); + enqueueAfterRenderTask(task); } } @@ -124,11 +143,11 @@ public void queueDuringRenderUnsafe(Runnable task){ } JavascriptContext context = threadContext.get(); if(!this.isRendering){ - context.beforeRenderTick(); + beforeRenderTick(); task.run(); this.renderLock.unlock(); }else{ - context.enqueueAfterRenderTask(task); + enqueueAfterRenderTask(task); } } diff --git a/src/main/java/kasuga/lib/core/client/frontend/gui/layout/LayoutEngines.java b/src/main/java/kasuga/lib/core/client/frontend/gui/layout/LayoutEngines.java index 85739ba7..1f9df9bd 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/gui/layout/LayoutEngines.java +++ b/src/main/java/kasuga/lib/core/client/frontend/gui/layout/LayoutEngines.java @@ -1,7 +1,9 @@ package kasuga.lib.core.client.frontend.gui.layout; +import kasuga.lib.core.client.frontend.common.layouting.LayoutEngine; import kasuga.lib.core.client.frontend.gui.layout.yoga.YogaLayoutEngine; +import net.minecraftforge.common.util.Lazy; public class LayoutEngines { - public static YogaLayoutEngine YOGA = new YogaLayoutEngine(); + public static Lazy YOGA = Lazy.of(YogaLayoutEngine::new); } diff --git a/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java b/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java index 0aa6f130..af43a261 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java +++ b/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java @@ -115,7 +115,7 @@ public boolean removeChild(DomNode child) { @Override public boolean addChild(DomNode child) { this.domContext.queueDuringRender(()-> { - super.addChild(child); + addChildInstant(children.size(), child); }); return true; } diff --git a/src/main/java/kasuga/lib/core/client/render/texture/Vec2f.java b/src/main/java/kasuga/lib/core/client/render/texture/Vec2f.java index fb90e96e..97688395 100644 --- a/src/main/java/kasuga/lib/core/client/render/texture/Vec2f.java +++ b/src/main/java/kasuga/lib/core/client/render/texture/Vec2f.java @@ -164,6 +164,19 @@ public float distance(Vec2f vec2f) { return (float) Math.sqrt(distanceSqr(vec2f)); } + public float getRotation() { + float pi = (float) Math.PI; + float len = length(); + if (len == 0) return 0; + float asin = (float) Math.asin(y / len); + if (x > 0 && y >= 0) return - asin; + if (x < 0) { + return pi + asin; + } else { + return 2 * pi - asin; + } + } + @Util public static Vec2f average(Vec2f... vectors) { if (vectors.length < 1) return Vec2f.ZERO; diff --git a/src/main/java/kasuga/lib/core/events/client/PlayLogEvent.java b/src/main/java/kasuga/lib/core/events/client/PlayLogEvent.java index d2ce47f0..8cf1948b 100644 --- a/src/main/java/kasuga/lib/core/events/client/PlayLogEvent.java +++ b/src/main/java/kasuga/lib/core/events/client/PlayLogEvent.java @@ -1,6 +1,11 @@ package kasuga.lib.core.events.client; +import kasuga.lib.core.KasugaLibClient; import kasuga.lib.core.client.model.anim_instance.AnimateTickerManager; +import kasuga.lib.core.util.projectile.Panel; +import kasuga.lib.core.util.projectile.PanelRenderer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -9,10 +14,14 @@ public class PlayLogEvent { @SubscribeEvent public static void playerLogin(PlayerEvent.PlayerLoggedInEvent event) { AnimateTickerManager.INSTANCE.resetTicks(); + Player player = event.getEntity(); + Panel.test = new PanelRenderer(player.getForward(), Vec3.ZERO); + KasugaLibClient.PANEL_RENDERERS.add(Panel.test); } @SubscribeEvent public static void playerLogout(PlayerEvent.PlayerLoggedOutEvent event) { AnimateTickerManager.INSTANCE.resetTicks(); + KasugaLibClient.PANEL_RENDERERS.clear(); } } diff --git a/src/main/java/kasuga/lib/core/javascript/JavascriptContext.java b/src/main/java/kasuga/lib/core/javascript/JavascriptContext.java index 6fbb777c..1659f6bc 100644 --- a/src/main/java/kasuga/lib/core/javascript/JavascriptContext.java +++ b/src/main/java/kasuga/lib/core/javascript/JavascriptContext.java @@ -41,6 +41,7 @@ public void close(){ public void tick(){ tickables.forEach(Tickable::tick); + this.context.tick(); } public Callback registerTickable(Tickable tickable){ @@ -74,19 +75,6 @@ public Callback runTask(Callback task) { }); } - Queue afterRenderTickTasks = new ArrayDeque<>(32); - - public void beforeRenderTick(){ - Runnable task; - while((task = afterRenderTickTasks.poll()) != null){ - task.run(); - } - } - - public void enqueueAfterRenderTask(Runnable runnable) { - this.afterRenderTickTasks.add(runnable); - } - public JavascriptEngineContext getRuntimeContext() { return this.context; } diff --git a/src/main/java/kasuga/lib/core/javascript/engine/JavascriptEngineContext.java b/src/main/java/kasuga/lib/core/javascript/engine/JavascriptEngineContext.java index 5e10f056..23617c30 100644 --- a/src/main/java/kasuga/lib/core/javascript/engine/JavascriptEngineContext.java +++ b/src/main/java/kasuga/lib/core/javascript/engine/JavascriptEngineContext.java @@ -22,4 +22,6 @@ public interface JavascriptEngineContext { JavascriptEngineModule compileNativeModule(Object target, String moduleName); JavascriptContext getContext(); + + void tick(); } diff --git a/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetContext.java b/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetContext.java index fd406035..e37ccf8f 100644 --- a/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetContext.java +++ b/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetContext.java @@ -116,4 +116,12 @@ public JavetJavascriptModule compileNativeModule(Object target, String moduleNam public JavascriptContext getContext() { return context; } + + private int gcTicks = 0; + @Override + public void tick() { + if(gcTicks ++ > 20){ + runtime.lowMemoryNotification(); + } + } } diff --git a/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetJavascriptModule.java b/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetJavascriptModule.java index 3dc50fed..79102c60 100644 --- a/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetJavascriptModule.java +++ b/src/main/java/kasuga/lib/core/javascript/engine/javet/JavetJavascriptModule.java @@ -37,7 +37,8 @@ public JavetJavascriptModule( directoryName, context, nodePackage.reader, - KasugaLib.STACKS.JAVASCRIPT.ASSETS.get() + KasugaLib.STACKS.JAVASCRIPT.ASSETS.get(), + nodePackage.minecraft.assetsFolder() ): null, absolutePath, directoryName, context); } public JavetJavascriptModule( @@ -53,6 +54,7 @@ public JavetJavascriptModule( this.nodePackage = nodePackage; this.directoryName = directoryName; this.context = context; + this.assetReader = reader; } public JavetJavascriptModule( diff --git a/src/main/java/kasuga/lib/core/util/projectile/Grid.java b/src/main/java/kasuga/lib/core/util/projectile/Grid.java new file mode 100644 index 00000000..a9a0324f --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/projectile/Grid.java @@ -0,0 +1,121 @@ +package kasuga.lib.core.util.projectile; + +import com.mojang.math.Vector3f; +import kasuga.lib.core.client.animation.neo_neo.VectorUtil; +import kasuga.lib.core.client.render.texture.Vec2f; +import lombok.Getter; + +import javax.annotation.Nullable; +import java.util.function.Function; + +@Getter +public class Grid { + + private final Panel panel; + + private final Vector3f o, xAxis, yAxis; + + private final Vec2f xAxis2d, yAxis2d; + + public Grid(final Panel panel, Vector3f o, final Vec2f xAxis, final Vec2f yAxis) { + this.panel = panel; + this.o = o; + this.xAxis2d = xAxis; + this.yAxis2d = yAxis; + this.xAxis = panel.map(xAxis); + this.yAxis = panel.map(yAxis); + } + + private Grid(final Panel panel, Vector3f o, Vector3f xAxis, Vector3f yAxis, Vec2f xAxis2d, Vec2f yAxis2d) { + this.panel = panel; + this.o = o; + this.xAxis = xAxis; + this.yAxis = yAxis; + this.xAxis2d = xAxis2d; + this.yAxis2d = yAxis2d; + } + + public Grid copy() { + return new Grid(this.panel, this.o, this.xAxis, this.yAxis, xAxis2d, yAxis2d); + } + + public Vector3f get(Vec2f vec) { + return get(vec.x(), vec.y()); + } + + public Vector3f get(float x, float y) { + Vector3f result = o.copy(); + Vector3f x3d = xAxis.copy(); + x3d.mul(x); + result.add(x3d); + Vector3f y3d = yAxis.copy(); + y3d.mul(y); + result.add(y3d); + return result; + } + + public Vec2f get(Vector3f vec) { + float pi = (float) Math.PI; + Vector3f offset = vec.copy(); + offset.sub(o); + Vec2f offset2d = panel.map(offset); + Function mapper = + angle -> angle > pi ? 2 * pi - angle : angle; + + float angleX = mapper.apply(xAxis2d.getRotation()); + float angleY = mapper.apply(yAxis2d.getRotation()); + float angleO = mapper.apply(offset2d.getRotation()); + + // offset2d = u * xAxis2d + v * yAxis2d + // use law of sines. + float angleXY = pi - angleX - angleY; + float angleXO = angleO + angleX; + float angleYO = pi - angleXY - angleXO; + float k = offset2d.length() / (float) Math.sin(angleXY); + float u = k * (float) Math.sin(angleYO); + float v = k * (float) Math.sin(angleXO); + + return new Vec2f(u, v); + } + + public void flex(float xScale, float yScale) { + xAxis.mul(xScale); + yAxis.mul(yScale); + xAxis2d.set(xAxis2d.x() * xScale, xAxis2d.y() * xScale); + yAxis2d.set(yAxis2d.x() * yScale, yAxis2d.y() * yScale); + } + + public void flex(float scale) { + flex(scale, scale); + } + + public void rot(float rad) { + Vec2f xRot = xAxis2d.rotate(rad); + Vec2f yRot = yAxis2d.rotate(rad); + xAxis2d.set(xRot.x(), xRot.y()); + yAxis2d.set(yRot.x(), yRot.y()); + Vector3f neoXAxis = panel.map(xRot); + Vector3f neoYAxis = panel.map(yRot); + Vector3f offsetX = neoXAxis.copy(); + Vector3f offsetY = neoYAxis.copy(); + offsetX.sub(xAxis); + offsetY.sub(yAxis); + xAxis.add(offsetX); + yAxis.add(offsetY); + } + + public void rotDeg(float deg) { + rot(VectorUtil.translateDegAndRad(deg, false)); + } + + public Ray getNormalRay(float x, float y) { + Vector3f source = get(x, y); + return new Ray(new Vector3f(panel.normal), source); + } + + public @Nullable Vec2f rayToPoint(Ray ray) { + Vector3f hitPoint = ray.getHitPoint(this.panel); + if (!ray.pointOnRay(hitPoint)) return null; + return get(hitPoint); + } +} diff --git a/src/main/java/kasuga/lib/core/util/projectile/MatrixResolveUtil.java b/src/main/java/kasuga/lib/core/util/projectile/MatrixResolveUtil.java new file mode 100644 index 00000000..81edab53 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/projectile/MatrixResolveUtil.java @@ -0,0 +1,11 @@ +package kasuga.lib.core.util.projectile; + +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; + +public class MatrixResolveUtil { + + public static Vector3f getOffset(Matrix4f matrix4f) { + return new Vector3f(); + } +} diff --git a/src/main/java/kasuga/lib/core/util/projectile/Panel.java b/src/main/java/kasuga/lib/core/util/projectile/Panel.java new file mode 100644 index 00000000..8f2db5ae --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/projectile/Panel.java @@ -0,0 +1,258 @@ +package kasuga.lib.core.util.projectile; + +import com.mojang.math.*; +import kasuga.lib.core.client.animation.neo_neo.VectorIOUtil; +import kasuga.lib.core.client.animation.neo_neo.VectorUtil; +import kasuga.lib.core.client.render.texture.Vec2f; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nullable; + +@Getter +public class Panel { + + public static PanelRenderer test = null; + + // Ax + By + Cz = constant + // constant = Ax0+ By0 + Cy0 + @Setter + public Vec3 normal; + + public final double constant; + + public Panel(Panel panel) { + this.normal = panel.normal; + this.constant = panel.constant; + } + + private Panel(Vec3 normal, double constant) { + this.normal = normal; + this.constant = constant; + } + + public Panel(Vector3f pos1, Vector3f pos2, Vector3f pos3) { + this(new Vec3(pos3), new Vec3(pos1).cross(new Vec3(pos2))); + } + + public Panel(Vector3f point, Vector3f normal) { + this.normal = new Vec3(normal); + this.constant = point.dot(normal); + } + + public Panel(Vec3 point, Vec3 normal) { + this.normal = normal; + this.constant = point.dot(normal); + } + + public Panel(Vec3 pos1, Vec3 pos2, Vec3 pos3) { + this(pos3, pos1.cross(pos2)); + } + + public Panel copy() { + return new Panel(this); + } + + public Panel moveTo(Vec3 point) { + return new Panel(this.normal, point); + } + + public Panel offset(Vec3 offset) { + double offsetConst = offset.dot(normal); + return new Panel(this.normal.add(offset), this.constant + offsetConst); + } + + public Panel rotate(Quaternion quaternion, Vec3 referencePoint) { + assert isPointOnPanel(referencePoint); + Vector3f neoNormal = new Vector3f(normal); + neoNormal.transform(quaternion); + return new Panel(referencePoint, new Vec3(neoNormal)); + } + + public Panel rotateDeg(Vector3f rotationDeg, Vec3 referencePoint) { + return rotate(Quaternion.fromXYZDegrees(rotationDeg), referencePoint); + } + + public Panel rotate(Vector3f rotation, Vec3 referencePoint) { + return rotate(Quaternion.fromXYZ(rotation), referencePoint); + } + + public Panel transform(Matrix4f matrix) { + Vector4f vector4f = new Vector4f((float) this.normal.x(), + (float) this.normal.y(), + (float) this.normal.z(), + (float) this.constant); + vector4f.transform(matrix); + return new Panel(new Vec3(vector4f.x(), vector4f.y(), vector4f.z()), vector4f.w()); + } + + public Panel reverse() { + return new Panel(this.normal.reverse(), this.constant); + } + + public Vector3f getNormal() { + return new Vector3f(normal); + } + + public boolean isPointOnPanel(Vec3 point) { + return normal.dot(point) == constant; + } + + public boolean isPointOnPanel(Vector3f point) { + return isPointOnPanel(new Vec3(point)); + } + + public boolean isVecHitPanel(Vec3 vec) { + return vec.dot(normal) == 0; + } + + public boolean isVecHitPanel(Vector3f vec) { + return isVecHitPanel(new Vec3(vec)); + } + + public Vec3 getHitPoint(Vec3 pos, Vec3 forward) { + if (isPointOnPanel(pos)) return pos; + assert valid(); + assert isVecHitPanel(forward); + Vec3 referencePoint = defaultReferencePoint(); + double d = referencePoint.subtract(pos).dot(normal) + / forward.dot(normal); + return forward.scale(d).add(pos); + } + + public Vector3f getHitPoint(Vector3f pos, Vector3f forward) { + return new Vector3f(getHitPoint(new Vec3(pos), new Vec3(forward))); + } + + public Vector3f getHitPoint(Ray ray) { + return getHitPoint(ray.getSource(), ray.getForward()); + } + + public Vec3 defaultReferencePoint() { + assert valid(); + if (parallelWithXOZ()) { + return new Vec3(1, getY(1, 1), 1); + } else if (parallelWithYOZ()) { + return new Vec3(getX(1, 1), 1, 1); + } else { + return new Vec3(1 ,1, getZ(1, 1)); + } + } + + public boolean valid() { + return !normal.equals(Vec3.ZERO); + } + + public boolean parallelWith(Vec3 normal) { + return this.normal.cross(normal).equals(Vec3.ZERO); + } + + public boolean parallel(Vec3 vec3) { + return this.normal.dot(vec3) == 0; + } + + public boolean parallel(Vector3f vector3f) { + return this.normal.dot(new Vec3(vector3f)) == 0; + } + + public boolean parallelWithXOY() { + return parallelWith(new Vec3(0, 0, 1)); + } + + public boolean parallelWithXOZ() { + return parallelWith(new Vec3(0, 1, 0)); + } + + public boolean parallelWithYOZ() { + return parallelWith(new Vec3(1, 0, 0)); + } + + public Vec3 yAxisIntersection() { + return new Vec3(0, getY(0, 0), 0); + } + + public Vec3 xAxisIntersection() { + return new Vec3(getX(0, 0), 0, 0); + } + + public Vec3 zAxisIntersection() { + return new Vec3(0, 0, getZ(0, 0)); + } + + public double getX(double y, double z) { + return (constant - normal.y() * y - normal.z() * z) / normal.x(); + } + + public double getY(double x, double z) { + return (constant - normal.x() * x - normal.z() * z) / normal.y(); + } + + public double getZ(double x, double y) { + return (constant - normal.x() * x - normal.y() * y) / normal.z(); + } + + public Vector3f map(Vec2f vec) { + Vec2f pitchAndYaw = getPitchAndYaw(this.normal); + Quaternion quaternion = Quaternion.fromXYZ(0, pitchAndYaw.y(), pitchAndYaw.x()); + Vector3f vector3f = new Vector3f(vec.x(), 0, vec.y()); + vector3f.transform(quaternion); + return vector3f; + } + + public Vec2f map(Vector3f vec) { + assert parallel(vec); + Vec2f pitchAndYaw = getPitchAndYaw(this.normal).invert(); + Quaternion quaternion = Quaternion.fromXYZ(0, pitchAndYaw.y(), pitchAndYaw.x()); + Vector3f vec3f = vec.copy(); + vec3f.transform(quaternion); + return new Vec2f(vec3f.x(), vec3f.z()); + } + + public static Vec2f getPitchAndYaw(Vec3 vec) { + float pi = (float) Math.PI; + Vec2f horizontal = new Vec2f((float) vec.x(), (float) vec.z()); + if (horizontal.lengthSqr() == 0) { + return new Vec2f(vec.y() >= 0 ? 0 : pi, 0); + } + + float yaw = horizontal.getRotation(); + float vecLen = (float) vec.length(); + + float pitch = vecLen == 0 ? 0 : (float) Math.asin(horizontal.length() / vecLen); + if (vec.y() < 0) pitch = pi - pitch; + return new Vec2f(- pitch, yaw); + } + + public Quaternion getQuaternion() { + Vec2f pitchAndYaw = getPitchAndYaw(this.normal); + Quaternion result = Quaternion.ONE.copy(); + Quaternion yaw = Quaternion.fromXYZ(0, pitchAndYaw.y(), 0); + Quaternion pitch = Quaternion.fromXYZ(0, 0, pitchAndYaw.x()); + result.mul(yaw); + result.mul(pitch); + return result; + } + + public Vector3f getRotationVector() { + return getQuaternion().toXYZ(); + } + + public Vector3f getRotationDegVector() { + return getQuaternion().toXYZDegrees(); + } + + @Override + public String toString() { + return "Panel"; + } + + public static void main(String[] args) { + Vec3 norm = new Vec3(0, 1, 0); + Vec3 pos = Vec3.ZERO; + Panel panel = new Panel(pos, norm); + panel = panel.rotateDeg(new Vector3f(0, 0, 90), pos); + System.out.println(panel); + System.out.println(panel.getRotationDegVector()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/projectile/PanelRenderer.java b/src/main/java/kasuga/lib/core/util/projectile/PanelRenderer.java new file mode 100644 index 00000000..1e9eda67 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/projectile/PanelRenderer.java @@ -0,0 +1,71 @@ +package kasuga.lib.core.util.projectile; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import kasuga.lib.core.KasugaLibClient; +import kasuga.lib.core.client.animation.neo_neo.VectorUtil; +import kasuga.lib.core.client.model.anim_model.AnimModel; +import kasuga.lib.core.client.model.model_json.UnbakedBedrockModel; +import kasuga.lib.core.client.render.SimpleColor; +import kasuga.lib.core.client.render.texture.Vec2f; +import kasuga.lib.core.util.LazyRecomputable; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +import java.awt.*; + +@Getter +public class PanelRenderer { + + private final Panel panel; + private final Vec3 pos; + + private static final LazyRecomputable panelModel = LazyRecomputable.of(() -> { + UnbakedBedrockModel model = KasugaLibClient.panel.get(); + return new AnimModel(model.getGeometries().get(0), model.getMaterial(), RenderType.translucent()); + }); + + private static final LazyRecomputable arrowModel = LazyRecomputable.of(() -> { + UnbakedBedrockModel model = KasugaLibClient.arrow.get(); + return new AnimModel(model.getGeometries().get(0), model.getMaterial(), RenderType.translucent()); + }); + + public static Vector3f BASE_OFFSET = new Vector3f(11f / 16f, 0, 15f / 16f); + + public PanelRenderer(Vec3 normal, Vec3 pos) { + panel = new Panel(pos, normal); + this.pos = pos; + } + + public PanelRenderer(Panel panel, Vec3 pos) { + this.panel = panel; + this.pos = pos; + } + + public void render(PoseStack pose, MultiBufferSource buffer, int light, int overlay, float partial) { + Player player = Minecraft.getInstance().player; + if (player == null) return; + panel.setNormal(player.getForward()); + Vec3 playerPos = player.getEyePosition(partial); + panel.moveTo(playerPos); + Quaternion quaternion = panel.getQuaternion(); + Vector3f position = new Vector3f(playerPos); + pose.translate(position.x(), position.y(), position.z()); + pose.translate(-BASE_OFFSET.x(), 0, -BASE_OFFSET.z()); + pose.mulPose(quaternion); + // pose.translate(BASE_OFFSET.x(), 0, BASE_OFFSET.z()); + if (!panel.valid()) + panelModel.get().setColor(SimpleColor.fromRGBInt(Color.RED.getRGB())); + else + panelModel.get().setColor(SimpleColor.fromRGBInt(Color.WHITE.getRGB())); + panelModel.get().render(pose, buffer, light, overlay); + + if (!panel.valid()) return; + arrowModel.get().render(pose, buffer, light, overlay); + } +} diff --git a/src/main/java/kasuga/lib/core/util/projectile/Ray.java b/src/main/java/kasuga/lib/core/util/projectile/Ray.java new file mode 100644 index 00000000..2fd485da --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/projectile/Ray.java @@ -0,0 +1,78 @@ +package kasuga.lib.core.util.projectile; + +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import kasuga.lib.core.client.animation.neo_neo.VectorUtil; +import kasuga.lib.core.client.render.texture.Vec2f; +import lombok.Getter; +import net.minecraft.world.phys.Vec3; + +@Getter +public class Ray { + + private final Vector3f source, forward; + + public Ray(final Vector3f source, final Vector3f forward) { + this.source = source; + this.forward = forward; + forward.normalize(); + } + + public Ray(Vec3 source, Vec3 forward) { + this(new Vector3f(source), new Vector3f(forward)); + } + + public void changeDirection(Quaternion quaternion) { + forward.transform(quaternion); + } + + public void offset(final Vector3f offset) { + source.add(offset); + } + + public Vector3f get(float distance) { + Vector3f result = source.copy(); + Vector3f f = forward.copy(); + f.mul(distance); + result.add(f); + return result; + } + + public Ray reflect(final Vector3f normal, Vector3f neoSource) { + Vec3 mir = VectorUtil.mirror(new Vec3(normal), new Vec3(forward)); + return new Ray(neoSource, new Vector3f(mir)); + } + + public Ray reflect(Panel panel) { + if (panel.parallel(this.forward)) return this; + if (panel.isPointOnPanel(this.source)) + return reflect(new Vector3f(panel.normal), this.source); + Vector3f hitPoint = panel.getHitPoint(this); + Vector3f test = hitPoint.copy(); + test.sub(source); + if (test.dot(forward) < 0) return this; + return reflect(new Vector3f(panel.normal), hitPoint); + } + + public Vector3f getHitPoint(Panel panel) { + return panel.getHitPoint(this); + } + + public boolean canHit(Panel panel) { + if (panel.isPointOnPanel(this.source)) return true; + if (panel.parallel(this.forward)) return false; + Vector3f hitPoint = panel.getHitPoint(this); + Vector3f test = hitPoint.copy(); + test.sub(source); + return test.dot(forward) >= 0; + } + + public boolean pointOnRay(Vector3f vector) { + Vector3f offset = vector.copy(); + offset.sub(source); + Vector3f test = offset.copy(); + test.cross(forward); + if (!test.equals(Vector3f.ZERO)) return false; + return offset.dot(forward) >= 0; + } +} \ No newline at end of file diff --git a/src/main/java/kasuga/lib/mixins/mixin/client/MixinLevelRenderer.java b/src/main/java/kasuga/lib/mixins/mixin/client/MixinLevelRenderer.java new file mode 100644 index 00000000..9a331ff9 --- /dev/null +++ b/src/main/java/kasuga/lib/mixins/mixin/client/MixinLevelRenderer.java @@ -0,0 +1,45 @@ +package kasuga.lib.mixins.mixin.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import kasuga.lib.core.KasugaLibClient; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LevelRenderer.class) +public class MixinLevelRenderer { + + @Final + @Shadow + private RenderBuffers renderBuffers; + + @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endLastBatch()V")) + public void doRender(PoseStack pPoseStack, float pPartialTick, + long pFinishNanoTime, boolean pRenderBlockOutline, + Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, + Matrix4f pProjectionMatrix, CallbackInfo ci) { + MultiBufferSource.BufferSource bufferSource = renderBuffers.bufferSource(); + pPoseStack.pushPose(); + Player player = Minecraft.getInstance().player; + Vec3 pos = player.getPosition(pPartialTick); + pPoseStack.translate(-pos.x(), -pos.y(), -pos.z()); + + KasugaLibClient.PANEL_RENDERERS.forEach( + renderer -> { + pPoseStack.pushPose(); + renderer.render(pPoseStack, bufferSource, LightTexture.FULL_BLOCK, 0, pPartialTick); + pPoseStack.popPose(); + } + ); + pPoseStack.popPose(); + } +} diff --git a/src/main/java/kasuga/lib/registrations/common/ChannelReg.java b/src/main/java/kasuga/lib/registrations/common/ChannelReg.java index 32fcf94a..341e26b0 100644 --- a/src/main/java/kasuga/lib/registrations/common/ChannelReg.java +++ b/src/main/java/kasuga/lib/registrations/common/ChannelReg.java @@ -21,6 +21,7 @@ import javax.annotation.Nonnull; import java.util.HashSet; +import java.util.LinkedList; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -36,7 +37,7 @@ public class ChannelReg extends Reg { private SimpleChannel channel = null; private String brand = registrationKey; private int id = 0; - private final HashSet> packetBuilders; + private final LinkedList> packetBuilders; Predicate clientVersions = ((input) -> true), serverVersions = ((input) -> true); /** @@ -45,7 +46,7 @@ public class ChannelReg extends Reg { */ public ChannelReg(String registrationKey) { super(registrationKey); - this.packetBuilders = new HashSet<>(); + this.packetBuilders = new LinkedList<>(); } /**