diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ParticleRenderer.kt b/common/attic/ParticleRenderer.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/ParticleRenderer.kt rename to common/attic/ParticleRenderer.kt diff --git a/common/attic/README.md b/common/attic/README.md new file mode 100644 index 00000000..d10a3e21 --- /dev/null +++ b/common/attic/README.md @@ -0,0 +1,36 @@ +# attic + +Code parked here is **excluded from compilation**. + +- `particle/`, `ParticleRenderer.kt` — the GPU particle system, retired during the 26.2 + migration. It was built directly on OpenGL (VAO/VBO double buffering, transform feedback) + and has no equivalent in the 26.2 `GpuDevice` wrapper API. Call sites in + `ScreenEffectRenderer`, `FinderArrowEntityRenderer` and `ClientboundExplosionPayload` + are commented out and marked with `GPU particle system retired (see common/attic)`. + +- `client/shader/{Program,Shader,ResourceShader,ShaderCompiler,ShaderCompilerV1, + ShaderStageStore,ShaderSourceDescriptor,ShaderExecutable,ShaderStage,Uniform, + UniformLocation,UniformWriter,FloatUniform,Vector2fUniform,Vector3fUniform, + Vector4fUniform,IntUniform,Matrix4fUniform,MonolithicProgramUniformWriter, + SeparableProgramUniformWriter,UniformBufferProvider}.kt`, `client/shader/component/`, + `client/shader/cache/` — the pre-26.2 mesh-shader compilation/linking/uniform-writer + infrastructure (raw `glCreateProgram`/`glAttachShader`/`glUniform*`, per-pointer + `UniformProvider(name) { pointer -> ... }`). Superseded by + `heckerpowered.matrix.client.shader.BlitProgram` + the new std140-block + `UniformProvider`/`TextureProvider` (see `BlitProgram.kt`/`UniformProvider.kt`), which + compiles GLSL through the vanilla `ShaderManager` and has no concept of a globally bound + program. There is no wrapper-API equivalent for "bind this program globally, then let + unrelated immediate-mode/vertex-attribute mesh code draw against it" — callers that relied + on that (`DissolveShader.enableShader/disableShader`, `PositionColorProgram`, + `MagicList.kt`, `ManaBar.kt`, `MatrixHud.kt`) either dropped the mesh-shader path or are + pending rework by whoever owns those files. + +- `client/render/{OpenGLExtensions,FramebufferCapture,AdvancedFramebuffer, + GpuPerformanceCounter}.kt`, `client/render/state/` (whole dir, including + `state/capabilities/`) — raw-GL debugging/state-capture/state-isolation helpers + (`glGetError`, GL capability snapshot+restore, `StateIsolation.isolate { }` wrappers). + On the 26.2 wrapper API blend/depth state is baked into `RenderPipeline`s per draw call + and render passes are self-contained, so there is nothing left to snapshot/restore around + a draw; callers that wrapped draws in `StateIsolation.isolate(...)` had the wrapper + removed and the blend/depth args translated into `BlitProgram.drawTo`'s `blend` parameter + where applicable. diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/AdvancedFramebuffer.kt b/common/attic/client/render/AdvancedFramebuffer.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/AdvancedFramebuffer.kt rename to common/attic/client/render/AdvancedFramebuffer.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt b/common/attic/client/render/FramebufferCapture.kt similarity index 89% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt rename to common/attic/client/render/FramebufferCapture.kt index 609de58d..0d978ff9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/FramebufferCapture.kt +++ b/common/attic/client/render/FramebufferCapture.kt @@ -5,8 +5,8 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.opengl.GlConst +import com.mojang.blaze3d.opengl.GlStateManager object FramebufferCapture { private var previousFramebuffer: Int = 0 diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/GpuPerformanceCounter.kt b/common/attic/client/render/GpuPerformanceCounter.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/GpuPerformanceCounter.kt rename to common/attic/client/render/GpuPerformanceCounter.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt b/common/attic/client/render/OpenGLExtensions.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/OpenGLExtensions.kt rename to common/attic/client/render/OpenGLExtensions.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ArrayBufferState.kt b/common/attic/client/render/state/ArrayBufferState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/ArrayBufferState.kt rename to common/attic/client/render/state/ArrayBufferState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/BlendFuncSeparateState.kt b/common/attic/client/render/state/BlendFuncSeparateState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/BlendFuncSeparateState.kt rename to common/attic/client/render/state/BlendFuncSeparateState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/BlendFuncState.kt b/common/attic/client/render/state/BlendFuncState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/BlendFuncState.kt rename to common/attic/client/render/state/BlendFuncState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt b/common/attic/client/render/state/FramebufferState.kt similarity index 86% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt rename to common/attic/client/render/state/FramebufferState.kt index d52a993e..97a25fc9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/FramebufferState.kt +++ b/common/attic/client/render/state/FramebufferState.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.render.state -import net.minecraft.client.gl.Framebuffer +import com.mojang.blaze3d.pipeline.RenderTarget import org.lwjgl.opengl.GL11.glGetInteger import org.lwjgl.opengl.GL30.* @@ -18,7 +18,7 @@ class FramebufferState(val framebuffer: Int) : RenderPipelineState { } } - constructor(framebuffer: Framebuffer) : this(framebuffer.fbo) + constructor(framebuffer: RenderTarget) : this(framebuffer.fbo) override fun apply(): RenderPipelineSnapshot { val snapshot = captureSnapshot() diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt b/common/attic/client/render/state/LineWidthState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/LineWidthState.kt rename to common/attic/client/render/state/LineWidthState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ProgramState.kt b/common/attic/client/render/state/ProgramState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/ProgramState.kt rename to common/attic/client/render/state/ProgramState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/RenderPipelineSnapshot.kt b/common/attic/client/render/state/RenderPipelineSnapshot.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/RenderPipelineSnapshot.kt rename to common/attic/client/render/state/RenderPipelineSnapshot.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/RenderPipelineState.kt b/common/attic/client/render/state/RenderPipelineState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/RenderPipelineState.kt rename to common/attic/client/render/state/RenderPipelineState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt b/common/attic/client/render/state/ShaderProgramState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/ShaderProgramState.kt rename to common/attic/client/render/state/ShaderProgramState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/StateIsolation.kt b/common/attic/client/render/state/StateIsolation.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/StateIsolation.kt rename to common/attic/client/render/state/StateIsolation.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/TransformFeedbackBindingState.kt b/common/attic/client/render/state/TransformFeedbackBindingState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/TransformFeedbackBindingState.kt rename to common/attic/client/render/state/TransformFeedbackBindingState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/VertexArrayState.kt b/common/attic/client/render/state/VertexArrayState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/VertexArrayState.kt rename to common/attic/client/render/state/VertexArrayState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt b/common/attic/client/render/state/ViewportState.kt similarity index 86% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt rename to common/attic/client/render/state/ViewportState.kt index 4ec77909..eb075e4c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/ViewportState.kt +++ b/common/attic/client/render/state/ViewportState.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.render.state -import net.minecraft.client.gl.Framebuffer +import com.mojang.blaze3d.pipeline.RenderTarget import org.lwjgl.opengl.GL46 class ViewportState(val viewportX: Int, val viewportY: Int, val viewportWidth: Int, val viewportHeight: Int) : RenderPipelineState { @@ -24,7 +24,7 @@ class ViewportState(val viewportX: Int, val viewportY: Int, val viewportWidth: I } } - constructor(framebuffer: Framebuffer) : this(0, 0, framebuffer.viewportWidth, framebuffer.viewportHeight) + constructor(framebuffer: RenderTarget) : this(0, 0, framebuffer.viewportWidth, framebuffer.viewportHeight) override fun apply(): RenderPipelineSnapshot { val snapshot = captureSnapshot() diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/BlendState.kt b/common/attic/client/render/state/capabilities/BlendState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/BlendState.kt rename to common/attic/client/render/state/capabilities/BlendState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/CapabilityState.kt b/common/attic/client/render/state/capabilities/CapabilityState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/CapabilityState.kt rename to common/attic/client/render/state/capabilities/CapabilityState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ClipDistanceState.kt b/common/attic/client/render/state/capabilities/ClipDistanceState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ClipDistanceState.kt rename to common/attic/client/render/state/capabilities/ClipDistanceState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ColorLogicOpState.kt b/common/attic/client/render/state/capabilities/ColorLogicOpState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ColorLogicOpState.kt rename to common/attic/client/render/state/capabilities/ColorLogicOpState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/CullFaceState.kt b/common/attic/client/render/state/capabilities/CullFaceState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/CullFaceState.kt rename to common/attic/client/render/state/capabilities/CullFaceState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DebugOutputState.kt b/common/attic/client/render/state/capabilities/DebugOutputState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DebugOutputState.kt rename to common/attic/client/render/state/capabilities/DebugOutputState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DebugOutputSynchronousState.kt b/common/attic/client/render/state/capabilities/DebugOutputSynchronousState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DebugOutputSynchronousState.kt rename to common/attic/client/render/state/capabilities/DebugOutputSynchronousState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DepthTestState.kt b/common/attic/client/render/state/capabilities/DepthTestState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/DepthTestState.kt rename to common/attic/client/render/state/capabilities/DepthTestState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/PolygonOffsetFillState.kt b/common/attic/client/render/state/capabilities/PolygonOffsetFillState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/PolygonOffsetFillState.kt rename to common/attic/client/render/state/capabilities/PolygonOffsetFillState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/RasterizerDiscardState.kt b/common/attic/client/render/state/capabilities/RasterizerDiscardState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/RasterizerDiscardState.kt rename to common/attic/client/render/state/capabilities/RasterizerDiscardState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ScissorTestState.kt b/common/attic/client/render/state/capabilities/ScissorTestState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/state/capabilities/ScissorTestState.kt rename to common/attic/client/render/state/capabilities/ScissorTestState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/FloatUniform.kt b/common/attic/client/shader/FloatUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/FloatUniform.kt rename to common/attic/client/shader/FloatUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/IntUniform.kt b/common/attic/client/shader/IntUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/IntUniform.kt rename to common/attic/client/shader/IntUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Matrix4fUniform.kt b/common/attic/client/shader/Matrix4fUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Matrix4fUniform.kt rename to common/attic/client/shader/Matrix4fUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/MonolithicProgramUniformWriter.kt b/common/attic/client/shader/MonolithicProgramUniformWriter.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/MonolithicProgramUniformWriter.kt rename to common/attic/client/shader/MonolithicProgramUniformWriter.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt b/common/attic/client/shader/Program.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Program.kt rename to common/attic/client/shader/Program.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ResourceShader.kt b/common/attic/client/shader/ResourceShader.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ResourceShader.kt rename to common/attic/client/shader/ResourceShader.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/SeparableProgramUniformWriter.kt b/common/attic/client/shader/SeparableProgramUniformWriter.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/SeparableProgramUniformWriter.kt rename to common/attic/client/shader/SeparableProgramUniformWriter.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Shader.kt b/common/attic/client/shader/Shader.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Shader.kt rename to common/attic/client/shader/Shader.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt b/common/attic/client/shader/ShaderCompiler.kt similarity index 96% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt rename to common/attic/client/shader/ShaderCompiler.kt index 1c1ba815..70d7c04d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompiler.kt +++ b/common/attic/client/shader/ShaderCompiler.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst +import com.mojang.blaze3d.opengl.GlConst import heckerpowered.matrix.client.render.MatrixRenderSystem import heckerpowered.matrix.client.shader.cache.ShaderCompilationException import org.lwjgl.opengl.ARBShadingLanguageInclude diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt b/common/attic/client/shader/ShaderCompilerV1.kt similarity index 98% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt rename to common/attic/client/shader/ShaderCompilerV1.kt index 2591ed1e..b4dcfe31 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderCompilerV1.kt +++ b/common/attic/client/shader/ShaderCompilerV1.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst +import com.mojang.blaze3d.opengl.GlConst import heckerpowered.matrix.client.render.OpenGLExtensions import heckerpowered.matrix.client.shader.cache.ShaderCompilationException import kotlinx.coroutines.* diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderExecutable.kt b/common/attic/client/shader/ShaderExecutable.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderExecutable.kt rename to common/attic/client/shader/ShaderExecutable.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderSourceDescriptor.kt b/common/attic/client/shader/ShaderSourceDescriptor.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderSourceDescriptor.kt rename to common/attic/client/shader/ShaderSourceDescriptor.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderStage.kt b/common/attic/client/shader/ShaderStage.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderStage.kt rename to common/attic/client/shader/ShaderStage.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderStageStore.kt b/common/attic/client/shader/ShaderStageStore.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/ShaderStageStore.kt rename to common/attic/client/shader/ShaderStageStore.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Uniform.kt b/common/attic/client/shader/Uniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Uniform.kt rename to common/attic/client/shader/Uniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformBufferProvider.kt b/common/attic/client/shader/UniformBufferProvider.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformBufferProvider.kt rename to common/attic/client/shader/UniformBufferProvider.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformLocation.kt b/common/attic/client/shader/UniformLocation.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformLocation.kt rename to common/attic/client/shader/UniformLocation.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformWriter.kt b/common/attic/client/shader/UniformWriter.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformWriter.kt rename to common/attic/client/shader/UniformWriter.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector2fUniform.kt b/common/attic/client/shader/Vector2fUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector2fUniform.kt rename to common/attic/client/shader/Vector2fUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector3fUniform.kt b/common/attic/client/shader/Vector3fUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector3fUniform.kt rename to common/attic/client/shader/Vector3fUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector4fUniform.kt b/common/attic/client/shader/Vector4fUniform.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/Vector4fUniform.kt rename to common/attic/client/shader/Vector4fUniform.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/cache/ShaderCompilationException.kt b/common/attic/client/shader/cache/ShaderCompilationException.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/cache/ShaderCompilationException.kt rename to common/attic/client/shader/cache/ShaderCompilationException.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/component/ShaderComponent.kt b/common/attic/client/shader/component/ShaderComponent.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/component/ShaderComponent.kt rename to common/attic/client/shader/component/ShaderComponent.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/component/TransformFeedback.kt b/common/attic/client/shader/component/TransformFeedback.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/shader/component/TransformFeedback.kt rename to common/attic/client/shader/component/TransformFeedback.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/GpuParticleState.kt b/common/attic/particle/GpuParticleState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/GpuParticleState.kt rename to common/attic/particle/GpuParticleState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleState.kt b/common/attic/particle/ParticleState.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleState.kt rename to common/attic/particle/ParticleState.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleStateDump.kt b/common/attic/particle/ParticleStateDump.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleStateDump.kt rename to common/attic/particle/ParticleStateDump.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleSystem.kt b/common/attic/particle/ParticleSystem.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/ParticleSystem.kt rename to common/attic/particle/ParticleSystem.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/DefaultLayout.kt b/common/attic/particle/memory/DefaultLayout.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/DefaultLayout.kt rename to common/attic/particle/memory/DefaultLayout.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/MemoryLayout.kt b/common/attic/particle/memory/MemoryLayout.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/MemoryLayout.kt rename to common/attic/particle/memory/MemoryLayout.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/Std140Layout.kt b/common/attic/particle/memory/Std140Layout.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/memory/Std140Layout.kt rename to common/attic/particle/memory/Std140Layout.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/DummyParticleModule.kt b/common/attic/particle/module/DummyParticleModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/DummyParticleModule.kt rename to common/attic/particle/module/DummyParticleModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleModule.kt b/common/attic/particle/module/ParticleModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleModule.kt rename to common/attic/particle/module/ParticleModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleRenderModule.kt b/common/attic/particle/module/ParticleRenderModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleRenderModule.kt rename to common/attic/particle/module/ParticleRenderModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleStateElement.kt b/common/attic/particle/module/ParticleStateElement.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/ParticleStateElement.kt rename to common/attic/particle/module/ParticleStateElement.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_render/ParticleSpriteRendererModule.kt b/common/attic/particle/module/particle_render/ParticleSpriteRendererModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_render/ParticleSpriteRendererModule.kt rename to common/attic/particle/module/particle_render/ParticleSpriteRendererModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/DummyParticleSpawnModule.kt b/common/attic/particle/module/particle_spawn/DummyParticleSpawnModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/DummyParticleSpawnModule.kt rename to common/attic/particle/module/particle_spawn/DummyParticleSpawnModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/InitializeParticleModule.kt b/common/attic/particle/module/particle_spawn/InitializeParticleModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/InitializeParticleModule.kt rename to common/attic/particle/module/particle_spawn/InitializeParticleModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/ParticleSpawnModule.kt b/common/attic/particle/module/particle_spawn/ParticleSpawnModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/ParticleSpawnModule.kt rename to common/attic/particle/module/particle_spawn/ParticleSpawnModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/RandomLifetimeModule.kt b/common/attic/particle/module/particle_spawn/RandomLifetimeModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/RandomLifetimeModule.kt rename to common/attic/particle/module/particle_spawn/RandomLifetimeModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/RandomVelocityModule.kt b/common/attic/particle/module/particle_spawn/RandomVelocityModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_spawn/RandomVelocityModule.kt rename to common/attic/particle/module/particle_spawn/RandomVelocityModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/AddVelocityModule.kt b/common/attic/particle/module/particle_update/AddVelocityModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/AddVelocityModule.kt rename to common/attic/particle/module/particle_update/AddVelocityModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/DragModule.kt b/common/attic/particle/module/particle_update/DragModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/DragModule.kt rename to common/attic/particle/module/particle_update/DragModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/DummyParticleUpdateModule.kt b/common/attic/particle/module/particle_update/DummyParticleUpdateModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/DummyParticleUpdateModule.kt rename to common/attic/particle/module/particle_update/DummyParticleUpdateModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/KillParticleModule.kt b/common/attic/particle/module/particle_update/KillParticleModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/KillParticleModule.kt rename to common/attic/particle/module/particle_update/KillParticleModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ParticleStateModule.kt b/common/attic/particle/module/particle_update/ParticleStateModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ParticleStateModule.kt rename to common/attic/particle/module/particle_update/ParticleStateModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ParticleUpdateModule.kt b/common/attic/particle/module/particle_update/ParticleUpdateModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ParticleUpdateModule.kt rename to common/attic/particle/module/particle_update/ParticleUpdateModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ScaleSpriteSizeBySpeedModule.kt b/common/attic/particle/module/particle_update/ScaleSpriteSizeBySpeedModule.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/module/particle_update/ScaleSpriteSizeBySpeedModule.kt rename to common/attic/particle/module/particle_update/ScaleSpriteSizeBySpeedModule.kt diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt b/common/attic/particle/system/ExplosionParticle.kt similarity index 100% rename from common/src/main/kotlin/heckerpowered/matrix/client/render/particle/system/ExplosionParticle.kt rename to common/attic/particle/system/ExplosionParticle.kt diff --git a/common/src/main/resources/assets/matrix/shaders/blur/ui_blur.frag b/common/attic/shaders/blur/ui_blur.frag similarity index 90% rename from common/src/main/resources/assets/matrix/shaders/blur/ui_blur.frag rename to common/attic/shaders/blur/ui_blur.frag index 24e341a5..4325e18c 100644 --- a/common/src/main/resources/assets/matrix/shaders/blur/ui_blur.frag +++ b/common/attic/shaders/blur/ui_blur.frag @@ -4,7 +4,12 @@ in vec2 fragTexCoord; out vec4 fragColor; uniform sampler2D image; -uniform float radius; + +layout(std140) uniform MatrixPostUniforms { + vec4 blurParams0; +}; + +#define radius blurParams0.x const vec2 BlurDir = vec2(1.2, 0.8); diff --git a/common/src/main/resources/assets/matrix/shaders/particle/geometry_template.gsh b/common/attic/shaders/particle/geometry_template.gsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/geometry_template.gsh rename to common/attic/shaders/particle/geometry_template.gsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/geometry_template.vsh b/common/attic/shaders/particle/geometry_template.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/geometry_template.vsh rename to common/attic/shaders/particle/geometry_template.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_render/point_sprite_renderer.fsh b/common/attic/shaders/particle/particle_render/point_sprite_renderer.fsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_render/point_sprite_renderer.fsh rename to common/attic/shaders/particle/particle_render/point_sprite_renderer.fsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_render/point_sprite_renderer.vsh b/common/attic/shaders/particle/particle_render/point_sprite_renderer.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_render/point_sprite_renderer.vsh rename to common/attic/shaders/particle/particle_render/point_sprite_renderer.vsh diff --git a/common/attic/shaders/particle/particle_render/world_point_sprite.fsh b/common/attic/shaders/particle/particle_render/world_point_sprite.fsh new file mode 100644 index 00000000..99135617 --- /dev/null +++ b/common/attic/shaders/particle/particle_render/world_point_sprite.fsh @@ -0,0 +1,17 @@ +#version 330 + +#moj_import + +in vec4 vertexColor; + +out vec4 fragColor; + +void main() { + vec2 coord = gl_PointCoord * 2.0 - 1.0; + float squaredDistance = dot(coord, coord); + if (squaredDistance > 1.0) { + discard; + } + + fragColor = vertexColor * ColorModulator; +} diff --git a/common/attic/shaders/particle/particle_render/world_point_sprite.vsh b/common/attic/shaders/particle/particle_render/world_point_sprite.vsh new file mode 100644 index 00000000..c8c47f92 --- /dev/null +++ b/common/attic/shaders/particle/particle_render/world_point_sprite.vsh @@ -0,0 +1,20 @@ +#version 330 + +#moj_import +#moj_import + +in vec3 Position; +in vec2 UV0; +in vec4 Color; + +out vec4 vertexColor; + +void main() { + vec4 viewPosition = ModelViewMat * vec4(Position, 1.0); + gl_Position = ProjMat * viewPosition; + + float distance = max(length(viewPosition.xyz), 0.01); + gl_PointSize = UV0.x / distance; + + vertexColor = Color * UV0.y; +} diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/initialize_particle.vsh b/common/attic/shaders/particle/particle_spawn/initialize_particle.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/initialize_particle.vsh rename to common/attic/shaders/particle/particle_spawn/initialize_particle.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/random_lifetime.vsh b/common/attic/shaders/particle/particle_spawn/random_lifetime.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/random_lifetime.vsh rename to common/attic/shaders/particle/particle_spawn/random_lifetime.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/random_velocity.vsh b/common/attic/shaders/particle/particle_spawn/random_velocity.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_spawn/random_velocity.vsh rename to common/attic/shaders/particle/particle_spawn/random_velocity.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/add_velocity.vsh b/common/attic/shaders/particle/particle_update/add_velocity.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/add_velocity.vsh rename to common/attic/shaders/particle/particle_update/add_velocity.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/drag.vsh b/common/attic/shaders/particle/particle_update/drag.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/drag.vsh rename to common/attic/shaders/particle/particle_update/drag.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/kill_particle.gsh b/common/attic/shaders/particle/particle_update/kill_particle.gsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/kill_particle.gsh rename to common/attic/shaders/particle/particle_update/kill_particle.gsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/kill_particle.vsh b/common/attic/shaders/particle/particle_update/kill_particle.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/kill_particle.vsh rename to common/attic/shaders/particle/particle_update/kill_particle.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/particle_state.vsh b/common/attic/shaders/particle/particle_update/particle_state.vsh similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/particle_state.vsh rename to common/attic/shaders/particle/particle_update/particle_state.vsh diff --git a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh b/common/attic/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh similarity index 97% rename from common/src/main/resources/assets/matrix/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh rename to common/attic/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh index 035c9cc7..7552532f 100644 --- a/common/src/main/resources/assets/matrix/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh +++ b/common/attic/shaders/particle/particle_update/scale_sprite_size_by_speed.vsh @@ -11,7 +11,7 @@ layout (location = 7) in vec4 InColor; layout (location = 8) in vec4 InOrientation; layout (location = 9) in vec3 InAngularVelocity; -uniform float MinScaleFactor = .0; +uniform float MinScaleFactor = 0.0; uniform float MaxScaleFactor = 2.0; uniform float VelocityThreshold = 1.0; diff --git a/common/src/main/resources/assets/matrix/shaders/particle/template.glsl b/common/attic/shaders/particle/template.glsl similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/particle/template.glsl rename to common/attic/shaders/particle/template.glsl diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh b/common/attic/shaders/post/bloom/bloom_lower_sampling_pass.fsh similarity index 76% rename from common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh rename to common/attic/shaders/post/bloom/bloom_lower_sampling_pass.fsh index dc9bf4ef..b7fe1405 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_lower_sampling_pass.fsh +++ b/common/attic/shaders/post/bloom/bloom_lower_sampling_pass.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 direction; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define direction MatrixPostData0.xy out vec4 fragColor; @@ -21,4 +29,4 @@ void main() { } fragColor = vec4(result, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh b/common/attic/shaders/post/bloom/bloom_super_sampling_pass.fsh similarity index 71% rename from common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh rename to common/attic/shaders/post/bloom/bloom_super_sampling_pass.fsh index 09e890b1..84c49753 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_super_sampling_pass.fsh +++ b/common/attic/shaders/post/bloom/bloom_super_sampling_pass.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float filterRadius = 15; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define filterRadius MatrixPostData0.x out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { color /= 16.0; fragColor = color * 1.2; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/grain/background_grain.fsh b/common/attic/shaders/post/grain/background_grain.fsh similarity index 67% rename from common/src/main/resources/assets/matrix/shaders/post/grain/background_grain.fsh rename to common/attic/shaders/post/grain/background_grain.fsh index b421771f..8567ff90 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/grain/background_grain.fsh +++ b/common/attic/shaders/post/grain/background_grain.fsh @@ -4,14 +4,19 @@ in vec2 fragTexCoord; uniform sampler2D opacityMask; uniform sampler2D noiseTexture; -uniform float grainStrength = 0.05; + +layout(std140) uniform MatrixPostUniforms { + vec4 grainParams; +}; + +#define grainStrength grainParams.x out vec4 fragColor; void main() { vec4 opacity = texture(opacityMask, fragTexCoord); - if (opacity.a == .0) { + if (opacity.a == 0.0) { discard; } fragColor = texture(noiseTexture, fragTexCoord) * grainStrength; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh b/common/attic/shaders/post/lower_sampling/hybrid_lod.fsh similarity index 56% rename from common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh rename to common/attic/shaders/post/lower_sampling/hybrid_lod.fsh index 62267074..1083fa16 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/hybrid_lod.fsh +++ b/common/attic/shaders/post/lower_sampling/hybrid_lod.fsh @@ -3,9 +3,17 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float primaryLevelOfDetail; -uniform float secondaryLevelOfDetail; -uniform float alpha = 0.5; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define primaryLevelOfDetail MatrixPostData0.x +#define secondaryLevelOfDetail MatrixPostData0.y +#define alpha MatrixPostData0.z out vec4 fragColor; @@ -14,4 +22,4 @@ void main() { vec4 secondaryColor = textureLod(framebuffer, fragTexCoord, secondaryLevelOfDetail); vec4 mixColor = mix(primaryColor, secondaryColor, alpha); fragColor = mixColor; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/opacity_blend.fsh b/common/attic/shaders/post/opacity_blend.fsh similarity index 90% rename from common/src/main/resources/assets/matrix/shaders/post/opacity_blend.fsh rename to common/attic/shaders/post/opacity_blend.fsh index 33f29624..5e1cd47c 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/opacity_blend.fsh +++ b/common/attic/shaders/post/opacity_blend.fsh @@ -9,7 +9,7 @@ out vec4 fragColor; void main() { vec4 opacity = texture(opacityMask, fragTexCoord); - if (opacity.a == .0) { + if (opacity.a == 0.0) { discard; } fragColor = texture(colorAttachment, fragTexCoord); diff --git a/common/attic/shaders/post/refraction/refraction.fsh b/common/attic/shaders/post/refraction/refraction.fsh new file mode 100644 index 00000000..03342cd9 --- /dev/null +++ b/common/attic/shaders/post/refraction/refraction.fsh @@ -0,0 +1,11 @@ +#version 330 core + +in vec2 fragTexCoord; + +uniform sampler2D framebuffer; + +out vec4 fragColor; + +void main() { + fragColor = texture(framebuffer, fragTexCoord); +} diff --git a/common/src/main/resources/assets/matrix/shaders/sobel.vert b/common/attic/shaders/sobel.vert similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/sobel.vert rename to common/attic/shaders/sobel.vert diff --git a/common/src/main/resources/assets/matrix/shaders/volume_distortion.frag b/common/attic/shaders/volume_distortion.frag similarity index 100% rename from common/src/main/resources/assets/matrix/shaders/volume_distortion.frag rename to common/attic/shaders/volume_distortion.frag diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 14b23e36..8877acda 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -69,6 +69,10 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") implementation(project(":ledger")) + // Ledger is a plain Kotlin library, not an installed mod: without jar-in-jar bundling it + // only exists on the dev classpath and production dies with NoClassDefFoundError on the + // first mana tick. + include(project(":ledger")) } tasks.test { diff --git a/common/src/main/generated/.cache/c0bdba60724d77a266169f97613eb903b1537b2d b/common/src/main/generated/.cache/6e7b3c24ee41899356a896c9100025f9f4c1ac3a similarity index 53% rename from common/src/main/generated/.cache/c0bdba60724d77a266169f97613eb903b1537b2d rename to common/src/main/generated/.cache/6e7b3c24ee41899356a896c9100025f9f4c1ac3a index 60b359a4..0644092a 100644 --- a/common/src/main/generated/.cache/c0bdba60724d77a266169f97613eb903b1537b2d +++ b/common/src/main/generated/.cache/6e7b3c24ee41899356a896c9100025f9f4c1ac3a @@ -1,90 +1,90 @@ -// 1.21 2026-04-03T17:42:12.755525 matrix/Recipes -6f0fe7c9ed4d3124c51e7fb17bcb358b016b6811 data/matrix/advancement/recipes/combat/coal_boots.json -e78f3232c44998a9f5881204593c5387e89dc1e0 data/matrix/recipe/coal_hoe.json -254dc3471f2bd63f5424f87035e5af223a64ca47 data/matrix/advancement/recipes/combat/stone_boots.json -a0f44f7ce1003f9e4ceefeebda1a1c3002a72329 data/matrix/recipe/emerald_pickaxe.json -bec5566a12d905e694d8e191ac2cb34f420181c0 data/matrix/recipe/redstone_helmet.json -df342601e8988755e97fd285935b6d5d3033b95b data/matrix/advancement/recipes/combat/redstone_leggings.json -b6653c2e18ca705abfa550875256294b019ee29e data/matrix/recipe/lapis_lazuli_helmet.json +// 26.2 -999999999-01-01T00:00:00 matrix/MatrixRecipeProvider +3b447fab9b23e3c4ea31cb872d05de0ffb4a6d9d data/matrix/advancement/recipes/combat/coal_boots.json +980f9a5c502dcf99bb5b18fec2208b72d066f842 data/matrix/advancement/recipes/combat/coal_chestplate.json +a721fcc159b714e70ab0d83e636f68855dbbb3e9 data/matrix/advancement/recipes/combat/coal_helmet.json +c4c2413fa52a31081451630941bac0d5c23bf7e8 data/matrix/advancement/recipes/combat/coal_leggings.json +d88769d492bcc655922ab9a42d21e75153ef51ef data/matrix/advancement/recipes/combat/coal_sword.json +512a725fb0866d85b8a96e4f8ffb64743da02f44 data/matrix/advancement/recipes/combat/emerald_boots.json +ec5226e2cc1f19d8f0f8dba71c240bde824f8bfb data/matrix/advancement/recipes/combat/emerald_chestplate.json +caaec06c7c41d6e0cf99114cfcccbce0b6a773c6 data/matrix/advancement/recipes/combat/emerald_helmet.json b6a758d267bb7d8f4ca5d97efef6ddabe15f5aca data/matrix/advancement/recipes/combat/emerald_leggings.json -0009b52c206efc83f8268ae9775f3de17e0d1d63 data/matrix/advancement/recipes/tools/redstone_pickaxe.json -fae4909e0036c5f1fec4df3454c6c20c992a80d9 data/matrix/recipe/lapis_lazuli_sword.json -92e265a4c5749ac724b7ef9e3b9648218ccdc885 data/matrix/recipe/coal_shovel.json -c2ec309c632fadb62c4bfda9601cdc2a618959f9 data/matrix/recipe/wooden_boots.json -04f5f56c472d47925ca2be6852eb2665f53d5369 data/matrix/recipe/redstone_hoe.json -37f313eff654ba764564137b9f79d42a235fd446 data/matrix/advancement/recipes/combat/lapis_lazuli_leggings.json -999125da0209b957595b91f63e2ae18568e61bab data/matrix/recipe/emerald_leggings.json +ff67758118ded8985144fd8d5f3d68c820a994d1 data/matrix/advancement/recipes/combat/emerald_sword.json +3b9a3641d2e343d97387e721dbe1842dbbe04e26 data/matrix/advancement/recipes/combat/lapis_lazuli_boots.json +d6f26cd778f8fd186998514c9328a1511a5b2032 data/matrix/advancement/recipes/combat/lapis_lazuli_chestplate.json 5184325a508e0e3f2d783ca00a1d7af69d2f67f0 data/matrix/advancement/recipes/combat/lapis_lazuli_helmet.json -6d13e506559ad4b7525290a8a0450746f237a275 data/matrix/advancement/recipes/tools/lapis_lazuli_pickaxe.json -764ba3284ec8567f7213e7973e5708ce2ddc2d62 data/matrix/recipe/lapis_lazuli_axe.json -ccc365e0c709712e8f95e5f07a69148e4d480ece data/matrix/recipe/coal_chestplate.json -80de47daa26922f55cbeb9d0a527ac4a68005be4 data/matrix/advancement/recipes/tools/emerald_axe.json -37d1c27c4457487d6be95b198901dc127158a4be data/matrix/recipe/emerald_axe.json -1e0b5cec29cd522d3ddfa70116a3a414d33b2b90 data/matrix/recipe/wooden_helmet.json -1a8e0ce69543f072c9eb2a435625d1ce59125aba data/matrix/recipe/redstone_chestplate.json +37f313eff654ba764564137b9f79d42a235fd446 data/matrix/advancement/recipes/combat/lapis_lazuli_leggings.json bd8750f7fdce9e5dbbf2c5da38f01f2408de9d07 data/matrix/advancement/recipes/combat/lapis_lazuli_sword.json -3830d0571619b14e421cf9b68537acda24a627b0 data/matrix/advancement/recipes/combat/stone_leggings.json -1753515f51d6d35b04a45bde33c37a8503373fcd data/matrix/recipe/coal_leggings.json -caaec06c7c41d6e0cf99114cfcccbce0b6a773c6 data/matrix/advancement/recipes/combat/emerald_helmet.json -dbfd0752772552ebc8d90125ff1e59b05a9951c3 data/matrix/recipe/emerald_sword.json -b8811aec080e08196743003b31567cd0f883e412 data/matrix/advancement/recipes/tools/redstone_shovel.json -89a3424fccc33a626800e390f529cb34fc40962d data/matrix/advancement/recipes/tools/lapis_lazuli_hoe.json -4589fd83d7ec2bcade57dc76c3aa1ca8b2893cc9 data/matrix/recipe/lapis_lazuli_pickaxe.json -3987b52d46a4d2533a2d638703c2979b54674cab data/matrix/advancement/recipes/combat/redstone_helmet.json -d6f26cd778f8fd186998514c9328a1511a5b2032 data/matrix/advancement/recipes/combat/lapis_lazuli_chestplate.json -5089fd6ee537f2a9cb5cba297f8f1fc4a88e7664 data/matrix/advancement/recipes/tools/emerald_pickaxe.json -83fa7b8db1802cba3b0b03cc21d3701db107d11b data/matrix/advancement/recipes/combat/wooden_chestplate.json -8f9ac2391e46824d07a6e4740277d944138fe4c7 data/matrix/recipe/lapis_lazuli_hoe.json +f115a417f9dddd8d817ae887f6479a025175d222 data/matrix/advancement/recipes/combat/redstone_boots.json 89f112831785b0261606e89d287cb3038d1f6d05 data/matrix/advancement/recipes/combat/redstone_chestplate.json -ba90066c51b0fec30ff9c2fa7f4a985f7b17be4f data/matrix/recipe/stone_chestplate.json -9317ea6905d438910e8ce5b8bfe279faf7e3c948 data/matrix/recipe/stone_boots.json -a863ccec2da6df912f0491fc86545224c57c241a data/matrix/advancement/recipes/tools/emerald_shovel.json -e6e8bc7dd5d544d7ac08e02c783ddf245059f643 data/matrix/recipe/stone_helmet.json +3987b52d46a4d2533a2d638703c2979b54674cab data/matrix/advancement/recipes/combat/redstone_helmet.json +df342601e8988755e97fd285935b6d5d3033b95b data/matrix/advancement/recipes/combat/redstone_leggings.json f33f2d3ebd4c8878a2af5571024f9c1df04487e5 data/matrix/advancement/recipes/combat/redstone_sword.json -ec5226e2cc1f19d8f0f8dba71c240bde824f8bfb data/matrix/advancement/recipes/combat/emerald_chestplate.json -ea8315945e9083bafbf02dfe104e78e827bc332d data/matrix/recipe/emerald_chestplate.json -a1c0c645268c247718f47d736ce2b6be25ec6f96 data/matrix/recipe/coal_helmet.json -ff67758118ded8985144fd8d5f3d68c820a994d1 data/matrix/advancement/recipes/combat/emerald_sword.json -a17d27f1c3c3a583a5b5cfdb45900193f0417ed5 data/matrix/recipe/coal_axe.json -e1ec5b260d195b2b74581f1b7464cc6e3556d260 data/matrix/recipe/redstone_suit_charge.json -50e615756a89f9ee40773b9c4623ada5ab93c206 data/matrix/advancement/recipes/tools/coal_pickaxe.json -139a242bca3c29ce7c1f72077a4fa5425afdfadd data/matrix/recipe/lapis_lazuli_shovel.json -09d5f0b0a55b22266cd4594f128da762648471cc data/matrix/recipe/coal_boots.json -a4153baae7c7311e457487c2aea983551f7a23ed data/matrix/advancement/recipes/combat/coal_helmet.json -f733aa5b42694dbc8418672f674454271f63d9f6 data/matrix/recipe/redstone_axe.json -6163b3a69780190bb993611c5bfe5bcc25a42972 data/matrix/recipe/wooden_leggings.json -0e30cc9582ad16af70e18ca19a008adab079bc7f data/matrix/recipe/redstone_shovel.json -59146e66f5b35c11578df0ce65560f99a143c5d2 data/matrix/recipe/emerald_boots.json -d966df8e96ad6c30ed52c74320fedacb679aa1bb data/matrix/recipe/redstone_leggings.json -00a2e425bbce421fe324e3da30a9d4228dd9a28d data/matrix/recipe/lapis_lazuli_boots.json +96ac6222e443c13e8b01c2e7c90ba59dd3eb76f0 data/matrix/advancement/recipes/combat/stone_boots.json +bbf1fe58b4bf1f885c9f1db721aa6daef53b2983 data/matrix/advancement/recipes/combat/stone_chestplate.json +7efb9d45f55225b2f7e36d25586681006dd14edf data/matrix/advancement/recipes/combat/stone_helmet.json +9d2837bf83ff2f0483ecb6bb005ce46f32654e03 data/matrix/advancement/recipes/combat/stone_leggings.json 352ad76ec965173885bd626c4b5009e5527a9e41 data/matrix/advancement/recipes/combat/wooden_boots.json -439b072020651c31582ae0fc2c1766d7829d60d1 data/matrix/recipe/redstone_boots.json -9e2132d3e351131fb777cc52284c5cff40440cca data/matrix/advancement/recipes/combat/stone_chestplate.json -2b0d797cd2beb48f5bfc11ad0fa2818e1c523719 data/matrix/recipe/emerald_shovel.json -741fa4f65831efb94744e626f697284691b0103c data/matrix/advancement/recipes/combat/stone_helmet.json -d8cc6139915298946103a468a828d084138849de data/matrix/advancement/recipes/combat/coal_leggings.json -f115a417f9dddd8d817ae887f6479a025175d222 data/matrix/advancement/recipes/combat/redstone_boots.json -956fb2f48294bc3ecb664c13e7c959c02c47d6fa data/matrix/recipe/lapis_lazuli_leggings.json -3bdf0eeef90960f82a276a8b8104881ee6c20f85 data/matrix/recipe/emerald_helmet.json -512a725fb0866d85b8a96e4f8ffb64743da02f44 data/matrix/advancement/recipes/combat/emerald_boots.json -7dc7c00d1f40afcf9b445897a224f083eed96c17 data/matrix/recipe/lapis_lazuli_chestplate.json -3014083a54e84c0f2e220108a741a955bb079eb0 data/matrix/recipe/redstone_pickaxe.json -0ded056dc0f4faa32f8c61fea8d655018fe4b70b data/matrix/recipe/coal_pickaxe.json -d60cdbecfda26325d096b54a4ff89f2ad575dd40 data/matrix/recipe/redstone_sword.json -fe7e96fa036612620bce64c281787c83684f114f data/matrix/advancement/recipes/combat/coal_sword.json -d28d2ba61ce5efa96545fbb2655dccc7dda83ff1 data/matrix/advancement/recipes/tools/coal_axe.json -f1f6873a6895aa67b6aeac6980c92502c57f02b8 data/matrix/advancement/recipes/tools/coal_hoe.json -7b513de500311db168e6cae1e082a638ad6ed4b7 data/matrix/recipe/stone_leggings.json -af560e2fe0a55687de35e89bc8dd031000e74e03 data/matrix/recipe/wooden_chestplate.json -c04013d18b9a2dbbd772484481dd559575482238 data/matrix/advancement/recipes/tools/coal_shovel.json +83fa7b8db1802cba3b0b03cc21d3701db107d11b data/matrix/advancement/recipes/combat/wooden_chestplate.json +205c46d9917d6c88a6d457c21ed6c5f068763f2a data/matrix/advancement/recipes/combat/wooden_helmet.json 0109623388b9f8d27965da01081d715a7ea73edc data/matrix/advancement/recipes/combat/wooden_leggings.json +85a8704636b4ab93edc4120d75a4e1756ab695e1 data/matrix/advancement/recipes/tools/coal_axe.json +6ba90c4e27f950bcc48fe8ef42743e7023a8ea9b data/matrix/advancement/recipes/tools/coal_hoe.json +36999a8fbf2cf08fe1014a8080c8e815762fbb70 data/matrix/advancement/recipes/tools/coal_pickaxe.json +64d0dbecf691c4c762f2b0271687884162b0967b data/matrix/advancement/recipes/tools/coal_shovel.json +80de47daa26922f55cbeb9d0a527ac4a68005be4 data/matrix/advancement/recipes/tools/emerald_axe.json +fdc6130e13f4f7d58cf0a7bf68ee655abffcf59d data/matrix/advancement/recipes/tools/emerald_hoe.json +5089fd6ee537f2a9cb5cba297f8f1fc4a88e7664 data/matrix/advancement/recipes/tools/emerald_pickaxe.json +a863ccec2da6df912f0491fc86545224c57c241a data/matrix/advancement/recipes/tools/emerald_shovel.json 6de0ee33f69b18d27f9da9f12f3802f8b63f61af data/matrix/advancement/recipes/tools/lapis_lazuli_axe.json +89a3424fccc33a626800e390f529cb34fc40962d data/matrix/advancement/recipes/tools/lapis_lazuli_hoe.json +6d13e506559ad4b7525290a8a0450746f237a275 data/matrix/advancement/recipes/tools/lapis_lazuli_pickaxe.json +cb6e0b7854e075b97a224ac2c2448e6ebba32ce1 data/matrix/advancement/recipes/tools/lapis_lazuli_shovel.json 91fab2658348a9428986d95a0bdd8b1c714d43d6 data/matrix/advancement/recipes/tools/redstone_axe.json b40c039af98d40012d28f5c0c1d3fd04444073c3 data/matrix/advancement/recipes/tools/redstone_hoe.json -205c46d9917d6c88a6d457c21ed6c5f068763f2a data/matrix/advancement/recipes/combat/wooden_helmet.json -c6092559728954d23ae66e9af5d52f0cde7328b2 data/matrix/advancement/recipes/combat/coal_chestplate.json -cb6e0b7854e075b97a224ac2c2448e6ebba32ce1 data/matrix/advancement/recipes/tools/lapis_lazuli_shovel.json -f8029665dd82bda18985fde3814a7f5bd3b531be data/matrix/recipe/coal_sword.json -3b9a3641d2e343d97387e721dbe1842dbbe04e26 data/matrix/advancement/recipes/combat/lapis_lazuli_boots.json -fdc6130e13f4f7d58cf0a7bf68ee655abffcf59d data/matrix/advancement/recipes/tools/emerald_hoe.json -e1facacea9870d2bd4fe9015652dd5c5ad7f415d data/matrix/recipe/emerald_hoe.json +0009b52c206efc83f8268ae9775f3de17e0d1d63 data/matrix/advancement/recipes/tools/redstone_pickaxe.json +b8811aec080e08196743003b31567cd0f883e412 data/matrix/advancement/recipes/tools/redstone_shovel.json +ffbed3e00b7818041169144e0f16e20f0da40c41 data/matrix/recipe/coal_axe.json +357d538b6adabddb1f762ef0f4b343cf5a6ca0fd data/matrix/recipe/coal_boots.json +5d39e59f2f9669f5898b5333d346c9d1bb9a40ce data/matrix/recipe/coal_chestplate.json +4d64338dab37a5ad73c12ed28418d7345c57e50c data/matrix/recipe/coal_helmet.json +2b9d09aed060360fde83cce21c63661b6366f3ca data/matrix/recipe/coal_hoe.json +cf862f07f2937ae2066e3d24729980f75c1db591 data/matrix/recipe/coal_leggings.json +369e528bcfda5fcd79305ebf2f5f9112c39d142c data/matrix/recipe/coal_pickaxe.json +6f6826bcff23bb426c4ff9df9a1f4ce7e62384de data/matrix/recipe/coal_shovel.json +dfdedf6401a6d6de13672cc01a9d4238990afd54 data/matrix/recipe/coal_sword.json +5672678562cdf496f12dc2e3ca6096794cafa38f data/matrix/recipe/emerald_axe.json +9af25d0c4fca6c794ffff72654679c9b776c3ce6 data/matrix/recipe/emerald_boots.json +765f228f06b21bcc3a7a92ae41434beb375cbf1d data/matrix/recipe/emerald_chestplate.json +1b3d07667acfdc0a89c22be03e6d5e262675875c data/matrix/recipe/emerald_helmet.json +fa20fa473c85440b90c5bacab69c04c989621e51 data/matrix/recipe/emerald_hoe.json +74f0328abe931cdbf7f4a7fd92edbb4265f9d621 data/matrix/recipe/emerald_leggings.json +06cbc9c7117805b4dcf3b45656625facf7331711 data/matrix/recipe/emerald_pickaxe.json +3af38d6d3cbd3f3ab5f461409951eb4de9a525b9 data/matrix/recipe/emerald_shovel.json +5dd3589b68570081ec65e0f984432747a4f34049 data/matrix/recipe/emerald_sword.json +1133fef103ab9235598c9134859349570914763f data/matrix/recipe/lapis_lazuli_axe.json +bf7f8626ba424555db3f8716c1e874ce60419b16 data/matrix/recipe/lapis_lazuli_boots.json +a34f4ef872c4ba8ec54813d4a441ae7ad47e9cd7 data/matrix/recipe/lapis_lazuli_chestplate.json +7d83bbd7611995d21b50a9a49319e2a9d6d92a8c data/matrix/recipe/lapis_lazuli_helmet.json +85a58c1be296362452530446ba06de0e56fa1a99 data/matrix/recipe/lapis_lazuli_hoe.json +67e9354b96b3504360e1abc64421a684914d4d4e data/matrix/recipe/lapis_lazuli_leggings.json +434a6f98dba0bcda7d0d6274ac20ac192d137d96 data/matrix/recipe/lapis_lazuli_pickaxe.json +a1fd1e4c86a8d0f5588102013ed922183313311d data/matrix/recipe/lapis_lazuli_shovel.json +23af5b88b3a9ca85d79ecd1e443678ad845de8ba data/matrix/recipe/lapis_lazuli_sword.json +661231de2e808e45dfc2772916a2e5b79d1806c7 data/matrix/recipe/redstone_axe.json +5ff248a233cb5509729ac65ee3792dead966e5fb data/matrix/recipe/redstone_boots.json +159b88a6bae7188d63213de624575935a6740f45 data/matrix/recipe/redstone_chestplate.json +5cdbc3f13ea0f533725413cee01c74df677c4c3b data/matrix/recipe/redstone_helmet.json +6435f9ea14f403d02dba2b8640eb4bfdd6202c57 data/matrix/recipe/redstone_hoe.json +69682d61afe959f140c35724b766288361b1d42a data/matrix/recipe/redstone_leggings.json +18ac8ea00995c96d2db853fddc9b376fcfb70c76 data/matrix/recipe/redstone_pickaxe.json +b6cf02e6d55c1dc757b24a89f4f2ccb9c5e89f45 data/matrix/recipe/redstone_shovel.json +5ea41bb766533c928bca8995d46fc4413c51c785 data/matrix/recipe/redstone_suit_charge.json +ce9ba3ebc12c9712f9cb85ff5a551333add2a414 data/matrix/recipe/redstone_sword.json +6e7280c92e86ebcecdbb5c522e9d8a26fc59ce2b data/matrix/recipe/stone_boots.json +4b8f25bd601e06039ce744fee1d9f1a478d0bdf8 data/matrix/recipe/stone_chestplate.json +9e1aa1ef36dd4971327235588fdf323dee04fcf1 data/matrix/recipe/stone_helmet.json +380941f5f093a9b678ea3676f0e7f2855ef53a07 data/matrix/recipe/stone_leggings.json +326657f9e2edae10e2ae444b81f2092cc9dd52f7 data/matrix/recipe/wooden_boots.json +8b88cad3673ab99935e24f913f03eb69ab97c943 data/matrix/recipe/wooden_chestplate.json +a7df31b633c76eca3b2c0bffee7b4a4ec2914e63 data/matrix/recipe/wooden_helmet.json +ccd73f084264da6ae6fb8058ed4f1892b1266ec8 data/matrix/recipe/wooden_leggings.json diff --git a/common/src/main/generated/.cache/7ccdec8fc782326201a204ba0156cea52859195f b/common/src/main/generated/.cache/7ccdec8fc782326201a204ba0156cea52859195f index ee4c66a0..6e599b1e 100644 --- a/common/src/main/generated/.cache/7ccdec8fc782326201a204ba0156cea52859195f +++ b/common/src/main/generated/.cache/7ccdec8fc782326201a204ba0156cea52859195f @@ -1,2 +1,2 @@ -// 1.21 2026-04-03T17:42:12.75712 matrix/Language (en_us) -7928b02dc1a8825479437cdddcfa69f8f122769e assets/matrix/lang/en_us.json +// 26.2 -999999999-01-01T00:00:00 matrix/Language (en_us) +cc87bc523eafb2f75f78e5fdb889c5b09823a4ce assets/matrix/lang/en_us.json diff --git a/common/src/main/generated/.cache/8b19192b2d5f2ae4e35502a95ba4f0ffd4de538f b/common/src/main/generated/.cache/8b19192b2d5f2ae4e35502a95ba4f0ffd4de538f index 225d5ed1..f8599a1e 100644 --- a/common/src/main/generated/.cache/8b19192b2d5f2ae4e35502a95ba4f0ffd4de538f +++ b/common/src/main/generated/.cache/8b19192b2d5f2ae4e35502a95ba4f0ffd4de538f @@ -1,3 +1,3 @@ -// 1.21 2026-04-03T17:42:12.755384 matrix/Tags for minecraft:damage_type +// 26.2 -999999999-01-01T00:00:00 matrix/Tags for minecraft:damage_type 1375cccd6009e70d881bf68a7182a5547200f48d data/matrix/tags/damage_type/magic.json 1375cccd6009e70d881bf68a7182a5547200f48d data/minecraft/tags/damage_type/bypasses_shield.json diff --git a/common/src/main/generated/.cache/8eae0833f9594536d11f1dec5fa513b94cf29ec8 b/common/src/main/generated/.cache/8eae0833f9594536d11f1dec5fa513b94cf29ec8 index c660b710..93668b0a 100644 --- a/common/src/main/generated/.cache/8eae0833f9594536d11f1dec5fa513b94cf29ec8 +++ b/common/src/main/generated/.cache/8eae0833f9594536d11f1dec5fa513b94cf29ec8 @@ -1,29 +1,2 @@ -// 1.21 2026-04-03T17:42:12.754726 matrix/Tags for minecraft:item -35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/minecraft/tags/item/enchantable/trident.json -37bf4d34cf94607e0e61f471f70e9cf250644bbd data/minecraft/tags/item/arrows.json -3cbbc63689f50905108cb9253af715d5f14882a9 data/minecraft/tags/item/enchantable/vanishing.json -35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/minecraft/tags/item/enchantable/crossbow.json -3710937a7995e1f6b895c946326f84fe10512445 data/minecraft/tags/item/enchantable/mining.json -4d2a91a43addc79539b93bc838f7b1a5ca648b65 data/minecraft/tags/item/enchantable/sharp_weapon.json -9bd10420dd015b35b7c4bf3bca9b948e22f9c522 data/minecraft/tags/item/pickaxes.json -19c161622c13e1e8c324a5cdee52cfdcd0e24dcd data/matrix/tags/item/wizard_helmet.json -4d2a91a43addc79539b93bc838f7b1a5ca648b65 data/minecraft/tags/item/enchantable/fire_aspect.json -530a4d8c965d4cac95556b7d18a1f241fda78360 data/minecraft/tags/item/hoes.json -743f98bae151820b1375e7df6eb3ad7182c38e3a data/minecraft/tags/item/enchantable/chest_armor.json -1a579424259e2904ac8ac982b766d72aa9db1c70 data/minecraft/tags/item/enchantable/durability.json -4d2a91a43addc79539b93bc838f7b1a5ca648b65 data/minecraft/tags/item/enchantable/sword.json -3710937a7995e1f6b895c946326f84fe10512445 data/minecraft/tags/item/enchantable/mining_loot.json -874d561eee6e463fdda76ee9de5d1b2d2bc5dfe6 data/minecraft/tags/item/enchantable/bow.json -23f37552fbd6f24eb1f06dc21cb8272e140814d9 data/minecraft/tags/item/leg_armor.json -35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/minecraft/tags/item/enchantable/fishing.json -4d2a91a43addc79539b93bc838f7b1a5ca648b65 data/minecraft/tags/item/enchantable/weapon.json -87a9052cb8326380df28a0073e814abfb7ba18e0 data/minecraft/tags/item/foot_armor.json -743f98bae151820b1375e7df6eb3ad7182c38e3a data/minecraft/tags/item/chest_armor.json -e91c97fd560037a265b842b9f754a82c11f23759 data/minecraft/tags/item/shovels.json -008ac1415258f36d488bbc4fc4acbc68a48517ad data/minecraft/tags/item/enchantable/head_armor.json -4d2a91a43addc79539b93bc838f7b1a5ca648b65 data/minecraft/tags/item/swords.json -23f37552fbd6f24eb1f06dc21cb8272e140814d9 data/minecraft/tags/item/enchantable/leg_armor.json -fb732e24eb1bf3dfffd383696accbbd8782e0604 data/minecraft/tags/item/enchantable/armor.json -87a9052cb8326380df28a0073e814abfb7ba18e0 data/minecraft/tags/item/enchantable/foot_armor.json -008ac1415258f36d488bbc4fc4acbc68a48517ad data/minecraft/tags/item/head_armor.json -601216415c5932fef46338f674668335de84a695 data/minecraft/tags/item/axes.json +// 26.2 -999999999-01-01T00:00:00 matrix/Tags for minecraft:item +35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/matrix/tags/item/wizard_helmet.json diff --git a/common/src/main/generated/.cache/e95d32c8851612dfb03b4cac3542a0aa13c80bd0 b/common/src/main/generated/.cache/e95d32c8851612dfb03b4cac3542a0aa13c80bd0 index d3539960..2604abb2 100644 --- a/common/src/main/generated/.cache/e95d32c8851612dfb03b4cac3542a0aa13c80bd0 +++ b/common/src/main/generated/.cache/e95d32c8851612dfb03b4cac3542a0aa13c80bd0 @@ -1,2 +1,2 @@ -// 1.21 2026-04-03T17:42:12.756625 matrix/Language (zh_cn) -d934334a9a6b4bc193ce18882dbf978c0102507d assets/matrix/lang/zh_cn.json +// 26.2 -999999999-01-01T00:00:00 matrix/Language (zh_cn) +16f99ec0482657025646373afef036578fbf4b42 assets/matrix/lang/zh_cn.json diff --git a/common/src/main/generated/.cache/41e259ae7c95549d59af2971e6ab76136101a1da b/common/src/main/generated/.cache/ef8ebb11926084589e1ffc675cf5b20fdb7a136d similarity index 86% rename from common/src/main/generated/.cache/41e259ae7c95549d59af2971e6ab76136101a1da rename to common/src/main/generated/.cache/ef8ebb11926084589e1ffc675cf5b20fdb7a136d index bed1161f..2d9995e1 100644 --- a/common/src/main/generated/.cache/41e259ae7c95549d59af2971e6ab76136101a1da +++ b/common/src/main/generated/.cache/ef8ebb11926084589e1ffc675cf5b20fdb7a136d @@ -1,41 +1,41 @@ -// 1.21 2026-04-03T17:42:12.756331 matrix/MatrixEnchantmentGenerator -e40e2071a52a545f3abe89b77d5622152b262edc data/matrix/enchantment/magic_shield.json -2d0ff0606b21d90bee4b17d35fcc6f2fa6baba6c data/matrix/enchantment/magic_queue.json -15a805fa56bf5c146c9f55f0bdbc14002f21ed6d data/matrix/enchantment/memory_wipe.json -8691766d8f920a94d699833a2859697db9979ed1 data/matrix/enchantment/lightning_strike.json -93baa74af6a02c0006fcf846ef3852e6f9f58101 data/matrix/enchantment/wizard_force.json -a730b85d1736cd2afae64c6b53ca52592026103b data/matrix/enchantment/explosion.json -af30e68f516157bf92c2b7bc1ec750acdbddec8a data/matrix/enchantment/levitation.json -8487b88d3ba6f7f3a3be3b3130458342a71c70bf data/matrix/enchantment/mana_overflow.json -f23a5c89da8b5c6235dc3f14afd2280914826e93 data/matrix/enchantment/tuck_in.json -887054608708270d1c940f084ab53bf9ca2d2dbc data/matrix/enchantment/last_stand.json -6247d9dd916c70a2962828cfa493cf2adb13b50d data/matrix/enchantment/kinetic_throw.json -6029033bd740096b5e6ade91d3b1916ff686e015 data/matrix/enchantment/queue_acceleration.json -e06758c3af81b74e1c3ba144c640245d1d789627 data/matrix/enchantment/decisive_strike.json -16d841cb7c457e003cb22f6cd01741ef51be7ff5 data/matrix/enchantment/sculk_catalyst.json -2bcc4fd6b1efca1c955c8c63f02458fc76f325f6 data/matrix/enchantment/brutal_strength.json -baa37219c4a371596c554043fd3abe3039a97aac data/matrix/enchantment/ignite.json -43a9d2ad093a4939a977cd64489fe6f69c8eec86 data/matrix/enchantment/attract.json -5b135055da6f4915cd41e2d6401318dc443dfdd4 data/matrix/enchantment/target_positioning.json +// 26.2 -999999999-01-01T00:00:00 matrix/Enchantments a5a395dbbc5381b344fdae53478119610610603e data/matrix/enchantment/absolvrift.json -348c1890bed5bf8d202fc9d28a5c819b796bafb2 data/matrix/enchantment/teleport.json -cfb3c83fc2fd41db0dbef41039a7cbf7c6fd16a8 data/matrix/enchantment/mana_regeneration.json +7ac3668018f2c0dd4bd1a0d66bd9dd702a2acbc1 data/matrix/enchantment/armor_penetration.json +43a9d2ad093a4939a977cd64489fe6f69c8eec86 data/matrix/enchantment/attract.json +f8ad273eb43d383130875eac8c65fd26ffd0811f data/matrix/enchantment/blood_pact.json 8c03c8ee028eb050867383d507226a0f3edbf100 data/matrix/enchantment/breaking_bad.json -d10f05b5b39a2422c1a84cc6ed622e7a245576df data/matrix/enchantment/second_wind.json -0d7fd7437e0e1c9bc677052b16fd9e19180f9770 data/matrix/enchantment/spread.json -dcdb29f2663a2daf1f68081d234846a42546d91d data/matrix/enchantment/queue_mastery.json +2bcc4fd6b1efca1c955c8c63f02458fc76f325f6 data/matrix/enchantment/brutal_strength.json +5ff3f4c99ec7cfbfbf9f79095d68d263c49e573d data/matrix/enchantment/brute_force.json +8fe284d2ca29a25c379c3a4b660a3bd4c3d51e7b data/matrix/enchantment/cripple_movement.json +e06758c3af81b74e1c3ba144c640245d1d789627 data/matrix/enchantment/decisive_strike.json +a730b85d1736cd2afae64c6b53ca52592026103b data/matrix/enchantment/explosion.json +ce0ab16b6b1c12e7e1651232e9227467e273d5c3 data/matrix/enchantment/guaranteed.json +c7a05b2fd06dfc3d8e10a9d6743a3fed9bab0fea data/matrix/enchantment/health_steal.json +baa37219c4a371596c554043fd3abe3039a97aac data/matrix/enchantment/ignite.json +fe96603bb4c33ffb36e9a1e4ff64342be735a007 data/matrix/enchantment/kill.json +574a3ce07567d003150fda1f2982160f400b88cd data/matrix/enchantment/kinetic_throw.json +f8d3bf5e36f9eeccf1b07f355e519516768fee83 data/matrix/enchantment/last_stand.json +af30e68f516157bf92c2b7bc1ec750acdbddec8a data/matrix/enchantment/levitation.json 80a00a919a449758d7d5a9c05a9bf800acfe5ea7 data/matrix/enchantment/lightning_bolt.json +5e79b122aeaa13185ad2b2189ca8b1b6057977f2 data/matrix/enchantment/lightning_strike.json e72f90ab5fb79d175fcfe77227273ef5c33acc10 data/matrix/enchantment/magic_overload.json -feae4ad0d1a58cd40571dae617c2958a06f1af44 data/matrix/enchantment/sonic_boom.json -c7a05b2fd06dfc3d8e10a9d6743a3fed9bab0fea data/matrix/enchantment/health_steal.json +2d0ff0606b21d90bee4b17d35fcc6f2fa6baba6c data/matrix/enchantment/magic_queue.json +e40e2071a52a545f3abe89b77d5622152b262edc data/matrix/enchantment/magic_shield.json +8487b88d3ba6f7f3a3be3b3130458342a71c70bf data/matrix/enchantment/mana_overflow.json +cfb3c83fc2fd41db0dbef41039a7cbf7c6fd16a8 data/matrix/enchantment/mana_regeneration.json +15a805fa56bf5c146c9f55f0bdbc14002f21ed6d data/matrix/enchantment/memory_wipe.json b01a3b1c0651c64ae9cd05f1181747f24c827bbb data/matrix/enchantment/peak_overdrive.json +b64be14ac1653cd05d77663eeef4d4d91a95cd05 data/matrix/enchantment/proximate_propagation.json +6029033bd740096b5e6ade91d3b1916ff686e015 data/matrix/enchantment/queue_acceleration.json +dcdb29f2663a2daf1f68081d234846a42546d91d data/matrix/enchantment/queue_mastery.json fabfb2fa62911c61b5a5649c2f881af3fac281dd data/matrix/enchantment/revival.json -33162044849a848ba38f41354bff1b20b4bbc09a data/matrix/enchantment/wither_armor.json +16d841cb7c457e003cb22f6cd01741ef51be7ff5 data/matrix/enchantment/sculk_catalyst.json +3e9716c1d9adbbe3cdef75e1aad0ab18a7e79fc8 data/matrix/enchantment/second_wind.json +feae4ad0d1a58cd40571dae617c2958a06f1af44 data/matrix/enchantment/sonic_boom.json +0d7fd7437e0e1c9bc677052b16fd9e19180f9770 data/matrix/enchantment/spread.json d1f14b851a8c99dcee0bbfc6a5c83a5774e54836 data/matrix/enchantment/system_crash.json -7ac3668018f2c0dd4bd1a0d66bd9dd702a2acbc1 data/matrix/enchantment/armor_penetration.json -8fe284d2ca29a25c379c3a4b660a3bd4c3d51e7b data/matrix/enchantment/cripple_movement.json -fe96603bb4c33ffb36e9a1e4ff64342be735a007 data/matrix/enchantment/kill.json -5ff3f4c99ec7cfbfbf9f79095d68d263c49e573d data/matrix/enchantment/brute_force.json -b64be14ac1653cd05d77663eeef4d4d91a95cd05 data/matrix/enchantment/proximate_propagation.json -d6313b8cfc50003e4f5cc0173022b55c4f9e9c47 data/matrix/enchantment/guaranteed.json -f8ad273eb43d383130875eac8c65fd26ffd0811f data/matrix/enchantment/blood_pact.json +5b135055da6f4915cd41e2d6401318dc443dfdd4 data/matrix/enchantment/target_positioning.json +348c1890bed5bf8d202fc9d28a5c819b796bafb2 data/matrix/enchantment/teleport.json +f23a5c89da8b5c6235dc3f14afd2280914826e93 data/matrix/enchantment/tuck_in.json +4125a09802a225781518aee1be47f93aae4e895d data/matrix/enchantment/wither_armor.json +93baa74af6a02c0006fcf846ef3852e6f9f58101 data/matrix/enchantment/wizard_force.json diff --git a/common/src/main/generated/assets/matrix/lang/en_us.json b/common/src/main/generated/assets/matrix/lang/en_us.json index 75bb6fa0..62d5bbd3 100644 --- a/common/src/main/generated/assets/matrix/lang/en_us.json +++ b/common/src/main/generated/assets/matrix/lang/en_us.json @@ -1,8 +1,9 @@ { + "creativeTab.matrix": "Matrix", "effect.matrix.angered": "Angered", "effect.matrix.armor_penetration": "Armor Penetration", "effect.matrix.blood_pact": "Blood Pact", - "effect.matrix.borrowed_time": "Borrowed Time", + "effect.matrix.borrowed_time_effect": "Borrowed Time", "effect.matrix.cripple_movement": "Cripple Movement", "effect.matrix.mana_overload": "Mana Overload", "effect.matrix.wither_armor": "Wither Armor", @@ -82,7 +83,6 @@ "item.minecraft.lingering_potion.effect.angered": "Lingering Potion of Angered", "item.minecraft.potion.effect.angered": "Potion of Angered", "item.minecraft.splash_potion.effect.angered": "Slash Potion of Angered", - "itemGroup.matrix": "Matrix", "key.categories.matrix": "Matrix", "key.matrix.next_magic": "Next magic", "key.matrix.previous_magic": "Previous magic", @@ -155,6 +155,6 @@ "matrix.system_is_crashing": "System Crash Imminent", "matrix.warden_chestplate.description": "§7When Angered:§r\nImmune to §9damage§r, §9knockback§r, §9fire§r, and §9movement penalties§r.\nClears and blocks all negative effects.\nDamage is increased by §9100%§r.\n-§9100%§r melee weapon charge time.\nMovement speed is increased.", "matrix.wizard_helmet.accumulated_mana_delta": "Spent/Recovered Mana: ", - "matrix.wizard_helmet.blood_pact_conversion_efficiency": "Blood Pact Conversion Efficiency: ", + "matrix.wizard_helmet.blood_pact_exchange_rate": "Blood Pact Conversion Efficiency: ", "matrix.wizard_helmet.load.description": "Current load: " } \ No newline at end of file diff --git a/common/src/main/generated/assets/matrix/lang/zh_cn.json b/common/src/main/generated/assets/matrix/lang/zh_cn.json index 776b6ce1..bac46fb5 100644 --- a/common/src/main/generated/assets/matrix/lang/zh_cn.json +++ b/common/src/main/generated/assets/matrix/lang/zh_cn.json @@ -1,8 +1,9 @@ { + "creativeTab.matrix": "Matrix", "effect.matrix.angered": "狂暴", "effect.matrix.armor_penetration": "护甲穿透", "effect.matrix.blood_pact": "血之契约", - "effect.matrix.borrowed_time": "时不我待", + "effect.matrix.borrowed_time_effect": "时不我待", "effect.matrix.cripple_movement": "阻碍移动", "effect.matrix.mana_overload": "法力过载", "effect.matrix.wither_armor": "凋灵护甲", @@ -85,7 +86,6 @@ "item.minecraft.lingering_potion.effect.angered": "滞留型狂暴药水", "item.minecraft.potion.effect.angered": "狂暴药水", "item.minecraft.slash_potion.effect.angered": "喷溅型狂暴药水", - "itemGroup.matrix": "Matrix", "key.categories.matrix": "Matrix", "key.matrix.next_magic": "下一个魔法", "key.matrix.previous_magic": "上一个魔法", @@ -158,6 +158,6 @@ "matrix.system_is_crashing": "即将发生系统崩溃", "matrix.warden_chestplate.description": "§7狂暴时:§r\n对§9伤害§r、§9击退§r、§9火焰§r、§9移速惩罚§r免疫。\n立即清除负面效果并在持续时间内免疫任何负面效果。\n造成的伤害提升§9100%§r。\n-§9100%§r近战武器攻击蓄力时间。\n移动速度获得提升。", "matrix.wizard_helmet.accumulated_mana_delta": "已使用/回复的法力: ", - "matrix.wizard_helmet.blood_pact_conversion_efficiency": "血之契约兑换效率: ", + "matrix.wizard_helmet.blood_pact_exchange_rate": "血之契约兑换效率: ", "matrix.wizard_helmet.load.description": "当前负载: " } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json index 2f8f1889..1683a430 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_boots.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json index 49e88831..948c84b4 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_chestplate.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json index 33568b28..7253c35f 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_helmet.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json index ef58be90..14d8cf76 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_leggings.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json index 34f79f22..06494b53 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/coal_sword.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json index 0f489250..17f1612b 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_boots.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json index 8790a21d..b7bc192a 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_chestplate.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json index 95e93942..8535e263 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_helmet.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json index 4ea6041f..0e0c8d17 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/combat/stone_leggings.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "#minecraft:stone_tool_materials" + "items": "minecraft:cobblestone" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json index a6f4aaee..90842c7f 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_axe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json index e40d3bd2..e54afb3a 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_hoe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json index bc337542..244d2af9 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_pickaxe.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json index a87a53ba..f9e23679 100644 --- a/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json +++ b/common/src/main/generated/data/matrix/advancement/recipes/tools/coal_shovel.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "items": "minecraft:emerald" + "items": "minecraft:coal_block" } ] }, diff --git a/common/src/main/generated/data/matrix/enchantment/guaranteed.json b/common/src/main/generated/data/matrix/enchantment/guaranteed.json index 48d6c98e..176e3bf9 100644 --- a/common/src/main/generated/data/matrix/enchantment/guaranteed.json +++ b/common/src/main/generated/data/matrix/enchantment/guaranteed.json @@ -15,6 +15,6 @@ "slots": [ "hand" ], - "supported_items": "#minecraft:enchantable/sword", + "supported_items": "#minecraft:enchantable/weapon", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/enchantment/kinetic_throw.json b/common/src/main/generated/data/matrix/enchantment/kinetic_throw.json index af981778..e9856505 100644 --- a/common/src/main/generated/data/matrix/enchantment/kinetic_throw.json +++ b/common/src/main/generated/data/matrix/enchantment/kinetic_throw.json @@ -15,6 +15,6 @@ "slots": [ "hand" ], - "supported_items": "#minecraft:enchantable/sword", + "supported_items": "#minecraft:enchantable/weapon", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/enchantment/last_stand.json b/common/src/main/generated/data/matrix/enchantment/last_stand.json index d1fe4ebb..ad678498 100644 --- a/common/src/main/generated/data/matrix/enchantment/last_stand.json +++ b/common/src/main/generated/data/matrix/enchantment/last_stand.json @@ -15,6 +15,6 @@ "slots": [ "hand" ], - "supported_items": "#minecraft:enchantable/sword", + "supported_items": "#minecraft:enchantable/weapon", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/enchantment/lightning_strike.json b/common/src/main/generated/data/matrix/enchantment/lightning_strike.json index 36d3bd19..6b3f858d 100644 --- a/common/src/main/generated/data/matrix/enchantment/lightning_strike.json +++ b/common/src/main/generated/data/matrix/enchantment/lightning_strike.json @@ -15,6 +15,6 @@ "slots": [ "hand" ], - "supported_items": "#minecraft:enchantable/sword", + "supported_items": "#minecraft:enchantable/weapon", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/enchantment/second_wind.json b/common/src/main/generated/data/matrix/enchantment/second_wind.json index 1dd53ba6..336bb92e 100644 --- a/common/src/main/generated/data/matrix/enchantment/second_wind.json +++ b/common/src/main/generated/data/matrix/enchantment/second_wind.json @@ -15,6 +15,6 @@ "slots": [ "armor" ], - "supported_items": "#minecraft:enchantable/armor", + "supported_items": "#minecraft:enchantable/weapon", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/enchantment/wither_armor.json b/common/src/main/generated/data/matrix/enchantment/wither_armor.json index aaf8f5e9..6609182f 100644 --- a/common/src/main/generated/data/matrix/enchantment/wither_armor.json +++ b/common/src/main/generated/data/matrix/enchantment/wither_armor.json @@ -13,8 +13,8 @@ "per_level_above_first": 10 }, "slots": [ - "body" + "chest" ], - "supported_items": "#minecraft:enchantable/armor", + "supported_items": "#minecraft:enchantable/chest_armor", "weight": 10 } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_axe.json b/common/src/main/generated/data/matrix/recipe/coal_axe.json index d0c1372e..29571ec8 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_axe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_boots.json b/common/src/main/generated/data/matrix/recipe/coal_boots.json index dbbafc7c..5752c9ab 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_boots.json +++ b/common/src/main/generated/data/matrix/recipe/coal_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:coal_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_chestplate.json b/common/src/main/generated/data/matrix/recipe/coal_chestplate.json index e37a1c19..b759177b 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/coal_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:coal_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_helmet.json b/common/src/main/generated/data/matrix/recipe/coal_helmet.json index 8602e333..74791ffe 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/coal_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:coal_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_hoe.json b/common/src/main/generated/data/matrix/recipe/coal_hoe.json index 06518122..5f04a78e 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_leggings.json b/common/src/main/generated/data/matrix/recipe/coal_leggings.json index 6071780d..687e3785 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/coal_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - } + "#": "minecraft:coal_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:coal_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json b/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json index d6492527..ec10aece 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/coal_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_shovel.json b/common/src/main/generated/data/matrix/recipe/coal_shovel.json index f8286253..caed626a 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/coal_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/coal_sword.json b/common/src/main/generated/data/matrix/recipe/coal_sword.json index c462f3cb..b75b188e 100644 --- a/common/src/main/generated/data/matrix/recipe/coal_sword.json +++ b/common/src/main/generated/data/matrix/recipe/coal_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_coal_suit", "key": { - "#": { - "item": "minecraft:coal_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:coal_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:coal_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_axe.json b/common/src/main/generated/data/matrix/recipe/emerald_axe.json index e8f3588c..48a87628 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_axe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_boots.json b/common/src/main/generated/data/matrix/recipe/emerald_boots.json index 6dfaa36a..0b5ed9a2 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_boots.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:emerald_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json b/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json index 26ff3e3f..04995c4d 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:emerald_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_helmet.json b/common/src/main/generated/data/matrix/recipe/emerald_helmet.json index bfda6e97..28a3c461 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:emerald_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_hoe.json b/common/src/main/generated/data/matrix/recipe/emerald_hoe.json index 6a734683..04f13a22 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_leggings.json b/common/src/main/generated/data/matrix/recipe/emerald_leggings.json index 8020505a..29546863 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - } + "#": "minecraft:emerald" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:emerald_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json b/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json index 3f15f04b..6c232dc9 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_shovel.json b/common/src/main/generated/data/matrix/recipe/emerald_shovel.json index 6746e0af..737b0160 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/emerald_sword.json b/common/src/main/generated/data/matrix/recipe/emerald_sword.json index 0050518e..925ddcaa 100644 --- a/common/src/main/generated/data/matrix/recipe/emerald_sword.json +++ b/common/src/main/generated/data/matrix/recipe/emerald_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_emerald_suit", "key": { - "#": { - "item": "minecraft:emerald" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:emerald", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:emerald_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json index 4e45780a..5fcbc3a8 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json index a9a607be..8a9081e5 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json index 35529825..4acd798d 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json index 41c6fde3..67ecd4fb 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json index 1e63da9d..2a90bc22 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json index 3fb837f3..ecf17194 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - } + "#": "minecraft:lapis_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json index 3b05b2a3..79a38505 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json index 033c78e4..28ef0499 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json index 737a48e9..31e08985 100644 --- a/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json +++ b/common/src/main/generated/data/matrix/recipe/lapis_lazuli_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_lapis_lazuli_suit", "key": { - "#": { - "item": "minecraft:lapis_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:lapis_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:lapis_lazuli_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_axe.json b/common/src/main/generated/data/matrix/recipe/redstone_axe.json index 90b6b9e7..118a6262 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_axe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_axe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_axe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_boots.json b/common/src/main/generated/data/matrix/recipe/redstone_boots.json index 6ada5096..df0290df 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_boots.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:redstone_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json b/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json index 9732c6b0..412cb605 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:redstone_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_helmet.json b/common/src/main/generated/data/matrix/recipe/redstone_helmet.json index 8192bedf..38312698 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:redstone_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_hoe.json b/common/src/main/generated/data/matrix/recipe/redstone_hoe.json index 0e2f4757..5d77e9ea 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_hoe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_hoe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "## ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_hoe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_leggings.json b/common/src/main/generated/data/matrix/recipe/redstone_leggings.json index 7705b1d0..f8e05fd1 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - } + "#": "minecraft:redstone_block" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:redstone_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json b/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json index 1aab87fc..6b95f43f 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_pickaxe.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ "###", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_pickaxe" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_shovel.json b/common/src/main/generated/data/matrix/recipe/redstone_shovel.json index 7e957933..0dc26cf2 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_shovel.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_shovel.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_shovel" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json b/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json index afe099a6..b76d231a 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_suit_charge.json @@ -1,4 +1,3 @@ { - "type": "minecraft:redstone_suit_charger", - "category": "misc" + "type": "minecraft:redstone_suit_charger" } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/redstone_sword.json b/common/src/main/generated/data/matrix/recipe/redstone_sword.json index b2b240bc..91fa0d6e 100644 --- a/common/src/main/generated/data/matrix/recipe/redstone_sword.json +++ b/common/src/main/generated/data/matrix/recipe/redstone_sword.json @@ -3,12 +3,8 @@ "category": "equipment", "group": "matrix_redstone_suit", "key": { - "#": { - "item": "minecraft:redstone_block" - }, - "|": { - "item": "minecraft:stick" - } + "#": "minecraft:redstone_block", + "|": "minecraft:stick" }, "pattern": [ " # ", @@ -16,7 +12,6 @@ " | " ], "result": { - "count": 1, "id": "matrix:redstone_sword" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_boots.json b/common/src/main/generated/data/matrix/recipe/stone_boots.json index 0fc952fe..1687cbb9 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_boots.json +++ b/common/src/main/generated/data/matrix/recipe/stone_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:stone_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_chestplate.json b/common/src/main/generated/data/matrix/recipe/stone_chestplate.json index a05c0c87..f41dbde8 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/stone_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:stone_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_helmet.json b/common/src/main/generated/data/matrix/recipe/stone_helmet.json index 9ba3a44a..933c005d 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/stone_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:stone_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/stone_leggings.json b/common/src/main/generated/data/matrix/recipe/stone_leggings.json index 65c27128..cbda85cb 100644 --- a/common/src/main/generated/data/matrix/recipe/stone_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/stone_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_stone_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "minecraft:cobblestone" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:stone_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_boots.json b/common/src/main/generated/data/matrix/recipe/wooden_boots.json index 215e5f5a..2af07f41 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_boots.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_boots.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "item": "minecraft:cobblestone" - } + "#": "#minecraft:planks" }, "pattern": [ "# #", "# #" ], "result": { - "count": 1, "id": "matrix:wooden_boots" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json b/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json index eeb6d2e4..f8b45d4b 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_chestplate.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "# #", @@ -13,7 +11,6 @@ "###" ], "result": { - "count": 1, "id": "matrix:wooden_chestplate" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_helmet.json b/common/src/main/generated/data/matrix/recipe/wooden_helmet.json index ebbc3f28..ebba0cd2 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_helmet.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_helmet.json @@ -3,16 +3,13 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "###", "# #" ], "result": { - "count": 1, "id": "matrix:wooden_helmet" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/recipe/wooden_leggings.json b/common/src/main/generated/data/matrix/recipe/wooden_leggings.json index 6629fd93..28ff886f 100644 --- a/common/src/main/generated/data/matrix/recipe/wooden_leggings.json +++ b/common/src/main/generated/data/matrix/recipe/wooden_leggings.json @@ -3,9 +3,7 @@ "category": "equipment", "group": "matrix_wooden_suit", "key": { - "#": { - "tag": "minecraft:planks" - } + "#": "#minecraft:planks" }, "pattern": [ "###", @@ -13,7 +11,6 @@ "# #" ], "result": { - "count": 1, "id": "matrix:wooden_leggings" } } \ No newline at end of file diff --git a/common/src/main/generated/data/matrix/tags/item/wizard_helmet.json b/common/src/main/generated/data/matrix/tags/item/wizard_helmet.json index 5633159c..f72d209d 100644 --- a/common/src/main/generated/data/matrix/tags/item/wizard_helmet.json +++ b/common/src/main/generated/data/matrix/tags/item/wizard_helmet.json @@ -1,12 +1,3 @@ { - "values": [ - "matrix:wizard_helmet_hacker", - "matrix:wizard_helmet_1", - "matrix:wizard_helmet_2", - "matrix:wizard_helmet_3", - "matrix:wizard_helmet_4", - "matrix:wizard_helmet_5", - "matrix:wizard_helmet_10", - "matrix:wizard_helmet_13" - ] + "values": [] } \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/arrows.json b/common/src/main/generated/data/minecraft/tags/item/arrows.json deleted file mode 100644 index 3a5ab488..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/arrows.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "values": [ - "matrix:finder_arrow" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/axes.json b/common/src/main/generated/data/minecraft/tags/item/axes.json deleted file mode 100644 index 70e10aae..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/axes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_axe", - "matrix:lapis_lazuli_axe", - "matrix:emerald_axe", - "matrix:coal_axe" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/chest_armor.json b/common/src/main/generated/data/minecraft/tags/item/chest_armor.json deleted file mode 100644 index 4b848c3d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/chest_armor.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "values": [ - "matrix:warden_chestplate", - "matrix:redstone_chestplate", - "matrix:lapis_lazuli_chestplate", - "matrix:emerald_chestplate", - "matrix:coal_chestplate", - "matrix:stone_chestplate", - "matrix:wooden_chestplate", - "matrix:lightning_chestplate_borrowed_time" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/armor.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/armor.json deleted file mode 100644 index 2e2d91f6..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/armor.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "values": [ - "matrix:warden_chestplate", - "matrix:redstone_helmet", - "matrix:redstone_chestplate", - "matrix:redstone_leggings", - "matrix:redstone_boots", - "matrix:lapis_lazuli_helmet", - "matrix:lapis_lazuli_chestplate", - "matrix:lapis_lazuli_leggings", - "matrix:lapis_lazuli_boots", - "matrix:emerald_helmet", - "matrix:emerald_chestplate", - "matrix:emerald_leggings", - "matrix:emerald_boots", - "matrix:coal_helmet", - "matrix:coal_chestplate", - "matrix:coal_leggings", - "matrix:coal_boots", - "matrix:stone_helmet", - "matrix:stone_chestplate", - "matrix:stone_leggings", - "matrix:stone_boots", - "matrix:wooden_helmet", - "matrix:wooden_chestplate", - "matrix:wooden_leggings", - "matrix:wooden_boots", - "matrix:wizard_helmet_hacker", - "matrix:wizard_helmet_1", - "matrix:wizard_helmet_2", - "matrix:wizard_helmet_3", - "matrix:wizard_helmet_4", - "matrix:wizard_helmet_5", - "matrix:wizard_helmet_10", - "matrix:wizard_helmet_13", - "matrix:lightning_chestplate_borrowed_time" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/bow.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/bow.json deleted file mode 100644 index ce197f8f..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/bow.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "values": [ - "matrix:meta_bow" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/chest_armor.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/chest_armor.json deleted file mode 100644 index 4b848c3d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/chest_armor.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "values": [ - "matrix:warden_chestplate", - "matrix:redstone_chestplate", - "matrix:lapis_lazuli_chestplate", - "matrix:emerald_chestplate", - "matrix:coal_chestplate", - "matrix:stone_chestplate", - "matrix:wooden_chestplate", - "matrix:lightning_chestplate_borrowed_time" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/crossbow.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/crossbow.json deleted file mode 100644 index f72d209d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/crossbow.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "values": [] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/durability.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/durability.json deleted file mode 100644 index ff6df811..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/durability.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "values": [ - "matrix:warden_chestplate", - "matrix:redstone_helmet", - "matrix:redstone_chestplate", - "matrix:redstone_leggings", - "matrix:redstone_boots", - "matrix:redstone_sword", - "matrix:redstone_pickaxe", - "matrix:redstone_axe", - "matrix:redstone_shovel", - "matrix:redstone_hoe", - "matrix:lapis_lazuli_helmet", - "matrix:lapis_lazuli_chestplate", - "matrix:lapis_lazuli_leggings", - "matrix:lapis_lazuli_boots", - "matrix:lapis_lazuli_sword", - "matrix:lapis_lazuli_pickaxe", - "matrix:lapis_lazuli_axe", - "matrix:lapis_lazuli_shovel", - "matrix:lapis_lazuli_hoe", - "matrix:emerald_helmet", - "matrix:emerald_chestplate", - "matrix:emerald_leggings", - "matrix:emerald_boots", - "matrix:emerald_sword", - "matrix:emerald_pickaxe", - "matrix:emerald_axe", - "matrix:emerald_shovel", - "matrix:emerald_hoe", - "matrix:coal_helmet", - "matrix:coal_chestplate", - "matrix:coal_leggings", - "matrix:coal_boots", - "matrix:coal_sword", - "matrix:coal_pickaxe", - "matrix:coal_axe", - "matrix:coal_shovel", - "matrix:coal_hoe", - "matrix:stone_helmet", - "matrix:stone_chestplate", - "matrix:stone_leggings", - "matrix:stone_boots", - "matrix:wooden_helmet", - "matrix:wooden_chestplate", - "matrix:wooden_leggings", - "matrix:wooden_boots", - "matrix:lightning_chestplate_borrowed_time", - "matrix:meta_bow" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/fire_aspect.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/fire_aspect.json deleted file mode 100644 index 77b4ec19..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/fire_aspect.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_sword", - "matrix:lapis_lazuli_sword", - "matrix:emerald_sword", - "matrix:coal_sword" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/fishing.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/fishing.json deleted file mode 100644 index f72d209d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/fishing.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "values": [] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/foot_armor.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/foot_armor.json deleted file mode 100644 index 8713d659..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/foot_armor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "values": [ - "matrix:redstone_boots", - "matrix:lapis_lazuli_boots", - "matrix:emerald_boots", - "matrix:coal_boots", - "matrix:stone_boots", - "matrix:wooden_boots" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/head_armor.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/head_armor.json deleted file mode 100644 index c116f6c1..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/head_armor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "values": [ - "matrix:redstone_helmet", - "matrix:lapis_lazuli_helmet", - "matrix:emerald_helmet", - "matrix:coal_helmet", - "matrix:stone_helmet", - "matrix:wooden_helmet", - "matrix:wizard_helmet_hacker", - "matrix:wizard_helmet_1", - "matrix:wizard_helmet_2", - "matrix:wizard_helmet_3", - "matrix:wizard_helmet_4", - "matrix:wizard_helmet_5", - "matrix:wizard_helmet_10", - "matrix:wizard_helmet_13" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/leg_armor.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/leg_armor.json deleted file mode 100644 index 58dd7f74..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/leg_armor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "values": [ - "matrix:redstone_leggings", - "matrix:lapis_lazuli_leggings", - "matrix:emerald_leggings", - "matrix:coal_leggings", - "matrix:stone_leggings", - "matrix:wooden_leggings" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/mining.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/mining.json deleted file mode 100644 index 7df01459..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/mining.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "values": [ - "matrix:redstone_pickaxe", - "matrix:redstone_axe", - "matrix:redstone_shovel", - "matrix:redstone_hoe", - "matrix:lapis_lazuli_pickaxe", - "matrix:lapis_lazuli_axe", - "matrix:lapis_lazuli_shovel", - "matrix:lapis_lazuli_hoe", - "matrix:emerald_pickaxe", - "matrix:emerald_axe", - "matrix:emerald_shovel", - "matrix:emerald_hoe", - "matrix:coal_pickaxe", - "matrix:coal_axe", - "matrix:coal_shovel", - "matrix:coal_hoe" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/mining_loot.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/mining_loot.json deleted file mode 100644 index 7df01459..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/mining_loot.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "values": [ - "matrix:redstone_pickaxe", - "matrix:redstone_axe", - "matrix:redstone_shovel", - "matrix:redstone_hoe", - "matrix:lapis_lazuli_pickaxe", - "matrix:lapis_lazuli_axe", - "matrix:lapis_lazuli_shovel", - "matrix:lapis_lazuli_hoe", - "matrix:emerald_pickaxe", - "matrix:emerald_axe", - "matrix:emerald_shovel", - "matrix:emerald_hoe", - "matrix:coal_pickaxe", - "matrix:coal_axe", - "matrix:coal_shovel", - "matrix:coal_hoe" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/sharp_weapon.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/sharp_weapon.json deleted file mode 100644 index 77b4ec19..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/sharp_weapon.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_sword", - "matrix:lapis_lazuli_sword", - "matrix:emerald_sword", - "matrix:coal_sword" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/sword.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/sword.json deleted file mode 100644 index 77b4ec19..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/sword.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_sword", - "matrix:lapis_lazuli_sword", - "matrix:emerald_sword", - "matrix:coal_sword" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/trident.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/trident.json deleted file mode 100644 index f72d209d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/trident.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "values": [] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/vanishing.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/vanishing.json deleted file mode 100644 index 8884db6f..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/vanishing.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "values": [ - "matrix:warden_chestplate", - "matrix:redstone_helmet", - "matrix:redstone_chestplate", - "matrix:redstone_leggings", - "matrix:redstone_boots", - "matrix:redstone_sword", - "matrix:redstone_pickaxe", - "matrix:redstone_axe", - "matrix:redstone_shovel", - "matrix:redstone_hoe", - "matrix:lapis_lazuli_helmet", - "matrix:lapis_lazuli_chestplate", - "matrix:lapis_lazuli_leggings", - "matrix:lapis_lazuli_boots", - "matrix:lapis_lazuli_sword", - "matrix:lapis_lazuli_pickaxe", - "matrix:lapis_lazuli_axe", - "matrix:lapis_lazuli_shovel", - "matrix:lapis_lazuli_hoe", - "matrix:emerald_helmet", - "matrix:emerald_chestplate", - "matrix:emerald_leggings", - "matrix:emerald_boots", - "matrix:emerald_sword", - "matrix:emerald_pickaxe", - "matrix:emerald_axe", - "matrix:emerald_shovel", - "matrix:emerald_hoe", - "matrix:coal_helmet", - "matrix:coal_chestplate", - "matrix:coal_leggings", - "matrix:coal_boots", - "matrix:coal_sword", - "matrix:coal_pickaxe", - "matrix:coal_axe", - "matrix:coal_shovel", - "matrix:coal_hoe", - "matrix:stone_helmet", - "matrix:stone_chestplate", - "matrix:stone_leggings", - "matrix:stone_boots", - "matrix:wooden_helmet", - "matrix:wooden_chestplate", - "matrix:wooden_leggings", - "matrix:wooden_boots", - "matrix:wizard_helmet_hacker", - "matrix:wizard_helmet_1", - "matrix:wizard_helmet_2", - "matrix:wizard_helmet_3", - "matrix:wizard_helmet_4", - "matrix:wizard_helmet_5", - "matrix:wizard_helmet_10", - "matrix:wizard_helmet_13", - "matrix:lightning_chestplate_borrowed_time", - "matrix:meta_bow" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/enchantable/weapon.json b/common/src/main/generated/data/minecraft/tags/item/enchantable/weapon.json deleted file mode 100644 index 77b4ec19..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/enchantable/weapon.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_sword", - "matrix:lapis_lazuli_sword", - "matrix:emerald_sword", - "matrix:coal_sword" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/foot_armor.json b/common/src/main/generated/data/minecraft/tags/item/foot_armor.json deleted file mode 100644 index 8713d659..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/foot_armor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "values": [ - "matrix:redstone_boots", - "matrix:lapis_lazuli_boots", - "matrix:emerald_boots", - "matrix:coal_boots", - "matrix:stone_boots", - "matrix:wooden_boots" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/head_armor.json b/common/src/main/generated/data/minecraft/tags/item/head_armor.json deleted file mode 100644 index c116f6c1..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/head_armor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "values": [ - "matrix:redstone_helmet", - "matrix:lapis_lazuli_helmet", - "matrix:emerald_helmet", - "matrix:coal_helmet", - "matrix:stone_helmet", - "matrix:wooden_helmet", - "matrix:wizard_helmet_hacker", - "matrix:wizard_helmet_1", - "matrix:wizard_helmet_2", - "matrix:wizard_helmet_3", - "matrix:wizard_helmet_4", - "matrix:wizard_helmet_5", - "matrix:wizard_helmet_10", - "matrix:wizard_helmet_13" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/hoes.json b/common/src/main/generated/data/minecraft/tags/item/hoes.json deleted file mode 100644 index 952ccf1d..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/hoes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_hoe", - "matrix:lapis_lazuli_hoe", - "matrix:emerald_hoe", - "matrix:coal_hoe" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/leg_armor.json b/common/src/main/generated/data/minecraft/tags/item/leg_armor.json deleted file mode 100644 index 58dd7f74..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/leg_armor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "values": [ - "matrix:redstone_leggings", - "matrix:lapis_lazuli_leggings", - "matrix:emerald_leggings", - "matrix:coal_leggings", - "matrix:stone_leggings", - "matrix:wooden_leggings" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/pickaxes.json b/common/src/main/generated/data/minecraft/tags/item/pickaxes.json deleted file mode 100644 index 9da9248e..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/pickaxes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_pickaxe", - "matrix:lapis_lazuli_pickaxe", - "matrix:emerald_pickaxe", - "matrix:coal_pickaxe" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/shovels.json b/common/src/main/generated/data/minecraft/tags/item/shovels.json deleted file mode 100644 index 90202b17..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/shovels.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_shovel", - "matrix:lapis_lazuli_shovel", - "matrix:emerald_shovel", - "matrix:coal_shovel" - ] -} \ No newline at end of file diff --git a/common/src/main/generated/data/minecraft/tags/item/swords.json b/common/src/main/generated/data/minecraft/tags/item/swords.json deleted file mode 100644 index 77b4ec19..00000000 --- a/common/src/main/generated/data/minecraft/tags/item/swords.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "values": [ - "matrix:redstone_sword", - "matrix:lapis_lazuli_sword", - "matrix:emerald_sword", - "matrix:coal_sword" - ] -} \ No newline at end of file diff --git a/common/src/main/java/heckerpowered/matrix/mixin/BrainAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/BrainAccessor.java new file mode 100644 index 00000000..6661fb25 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/BrainAccessor.java @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.entity.ai.Brain; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.ai.memory.MemorySlot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +/** See {@link TickRateManagerAccessor} for why this is an accessor, not a tweaker widening. */ +@Mixin(Brain.class) +public interface BrainAccessor { + @Accessor("memories") + Map, MemorySlot> matrix$getMemories(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java new file mode 100644 index 00000000..2a19355f --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/CameraMixin.java @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.client.MatrixHud; +import heckerpowered.matrix.client.TimeController; +import heckerpowered.matrix.client.render.MatrixRenderSystem; +import heckerpowered.matrix.client.render.post.CameraShake; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.renderer.state.level.CameraRenderState; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * 26.2: fov calculation and the projection matrix moved from GameRenderer into Camera, so + * the pre-migration GameRenderer.getFov / loadProjectionMatrix / camera-shake hooks live + * here now: + *
    + *
  • calculateFov/calculateHudFov × MatrixHud.fovAnimation — the former getFov TAIL hook.
  • + *
  • getCameraEntityPartialTicks — the former standalone-render-tick delta override.
  • + *
  • extractRenderState TAIL — captures view/projection for MatrixRenderSystem (former + * loadProjectionMatrix redirect) and applies CameraShake to the extracted view rotation + * (former renderWorld view-matrix perturbation before frustum setup).
  • + *
+ */ +@Mixin(Camera.class) +class CameraMixin { + private CameraMixin() { + } + + @Inject(method = "getCameraEntityPartialTicks", at = @At("RETURN"), cancellable = true) + private void getCameraEntityPartialTicks(DeltaTracker deltaTracker, CallbackInfoReturnable cir) { + if (TimeController.getPlayerStandaloneRenderTick()) { + cir.setReturnValue(TimeController.standaloneRenderTickCounter.getGameTimeDeltaPartialTick(true)); + } + } + + @Inject(method = "calculateFov", at = @At("RETURN"), cancellable = true) + private void calculateFov(float partialTick, CallbackInfoReturnable cir) { + cir.setReturnValue(cir.getReturnValueF() * (float) MatrixHud.fovAnimation.getAnimatedValue()); + } + + @Inject(method = "calculateHudFov", at = @At("RETURN"), cancellable = true) + private void calculateHudFov(float partialTick, CallbackInfoReturnable cir) { + cir.setReturnValue(cir.getReturnValueF() * (float) MatrixHud.fovAnimation.getAnimatedValue()); + } + + @Inject(method = "extractRenderState", at = @At("TAIL")) + private void extractRenderState(CameraRenderState renderState, float partialTick, CallbackInfo ci) { + CameraShake.applyCameraShake(renderState.viewRotationMatrix); + MatrixRenderSystem.setupMatrix((Camera) (Object) this, renderState.projectionMatrix); + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/CastSpellGoalMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/CastSpellGoalMixin.java index e46180ca..8829b96c 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/CastSpellGoalMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/CastSpellGoalMixin.java @@ -6,7 +6,7 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.effect.ManaOverloadEffect; -import net.minecraft.entity.mob.SpellcastingIllagerEntity; +import net.minecraft.world.entity.monster.illager.SpellcasterIllager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -16,23 +16,31 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(SpellcastingIllagerEntity.CastSpellGoal.class) +/** + * 26.2: {@code SpellcasterIllager.CastSpellGoal} (Yarn) is now the abstract base + * {@link SpellcasterIllager.SpellcasterUseSpellGoal}, with {@code canStart}/{@code shouldContinue}/ + * {@code castSpell} renamed to {@code canUse}/{@code canContinueToUse}/{@code performSpellCasting} + * (the latter now {@code protected abstract}, implemented per-illager in subclasses such as + * {@code EvokerAttackSpellGoal}/{@code IllusionerBlindnessSpellGoal}). The outer-instance + * synthetic field is named {@code this$0} instead of the Yarn intermediary {@code field_7386}. + */ +@Mixin(SpellcasterIllager.SpellcasterUseSpellGoal.class) class CastSpellGoalMixin { @Shadow @Final - SpellcastingIllagerEntity field_7386; // this + SpellcasterIllager this$0; - @Inject(method = "canStart", at = @At("HEAD"), cancellable = true) - private void canStart(CallbackInfoReturnable cir) { - final var self = field_7386; + @Inject(method = "canUse", at = @At("HEAD"), cancellable = true) + private void canUse(CallbackInfoReturnable cir) { + final var self = this$0; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { cir.setReturnValue(false); } } - @Inject(method = "shouldContinue", at = @At("HEAD"), cancellable = true) - private void shouldContinue(CallbackInfoReturnable cir) { - final var self = field_7386; + @Inject(method = "canContinueToUse", at = @At("HEAD"), cancellable = true) + private void canContinueToUse(CallbackInfoReturnable cir) { + final var self = this$0; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { cir.setReturnValue(false); } @@ -40,19 +48,19 @@ private void shouldContinue(CallbackInfoReturnable cir) { @Inject(method = "start", at = @At("HEAD"), cancellable = true) private void start(CallbackInfo ci) { - final var self = field_7386; + final var self = this$0; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { ci.cancel(); } } - @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/SpellcastingIllagerEntity$CastSpellGoal;castSpell()V")) - private void tick(SpellcastingIllagerEntity.CastSpellGoal instance) { - final var self = field_7386; + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/illager/SpellcasterIllager$SpellcasterUseSpellGoal;performSpellCasting()V")) + private void tick(SpellcasterIllager.SpellcasterUseSpellGoal instance) { + final var self = this$0; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { return; } - instance.castSpell(); + instance.performSpellCasting(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java index 4da7edf9..b76666c3 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/DamageSourceMixin.java @@ -7,22 +7,21 @@ import heckerpowered.matrix.extension.MatrixDamageSource; import net.minecraft.world.damagesource.DamageSource; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @Mixin(DamageSource.class) -@Implements(@Interface(iface = MatrixDamageSource.class, prefix = "matrix$")) class DamageSourceMixin implements MatrixDamageSource { @Unique private boolean isAdditionalDamage = false; - public boolean matrix$isAdditionalDamage() { + @Override + public boolean isAdditionalDamage() { return isAdditionalDamage; } - public void matrix$setAdditionalDamage(boolean b) { + @Override + public void setAdditionalDamage(boolean b) { isAdditionalDamage = b; } } \ No newline at end of file diff --git a/common/src/main/java/heckerpowered/matrix/mixin/ElderGuardianEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/ElderGuardianEntityMixin.java index 7e11940c..6c1d6f98 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/ElderGuardianEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/ElderGuardianEntityMixin.java @@ -6,13 +6,13 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.effect.ManaOverloadEffect; -import net.minecraft.entity.Entity; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffectUtil; -import net.minecraft.entity.mob.ElderGuardianEntity; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.Vec3d; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffectUtil; +import net.minecraft.world.entity.monster.ElderGuardian; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -21,15 +21,20 @@ import java.util.Collections; import java.util.List; -@Mixin(ElderGuardianEntity.class) +/** + * 26.2: {@code ElderGuardianEntity#mobTick} (Yarn) is now {@code customServerAiStep}, and + * {@code MobEffectUtil#addEffectToPlayersWithinDistance} was renamed to + * {@code addEffectToPlayersAround} (same signature/semantics). + */ +@Mixin(ElderGuardian.class) class ElderGuardianEntityMixin { - @Redirect(method = "mobTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/effect/StatusEffectUtil;addEffectToPlayersWithinDistance(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Vec3d;DLnet/minecraft/entity/effect/StatusEffectInstance;I)Ljava/util/List;")) - private List addEffectToPlayersWithinDistance(ServerWorld world, @Nullable Entity entity, Vec3d origin, double range, StatusEffectInstance statusEffectInstance, int duration) { - final var self = (ElderGuardianEntity) (Object) this; + @Redirect(method = "customServerAiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/effect/MobEffectUtil;addEffectToPlayersAround(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;DLnet/minecraft/world/effect/MobEffectInstance;I)Ljava/util/List;")) + private List addEffectToPlayersAround(ServerLevel world, @Nullable Entity entity, Vec3 origin, double range, MobEffectInstance statusEffectInstance, int duration) { + final var self = (ElderGuardian) (Object) this; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { return Collections.emptyList(); } - return StatusEffectUtil.addEffectToPlayersWithinDistance(world, entity, origin, range, statusEffectInstance, duration); + return MobEffectUtil.addEffectToPlayersAround(world, entity, origin, range, statusEffectInstance, duration); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/EndermanEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/EndermanEntityMixin.java index 2fd2903b..cdf9da3f 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/EndermanEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/EndermanEntityMixin.java @@ -7,45 +7,61 @@ import heckerpowered.matrix.common.effect.ManaOverloadEffect; import heckerpowered.matrix.common.effect.ModMobEffects; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.mob.EndermanEntity; -import net.minecraft.world.World; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(EndermanEntity.class) +/** + * 26.2: {@code EndermanEntity#damage(DamageSource, float)Z} (Yarn) is now split into the + * server-authoritative {@code EnderMan#hurtServer(ServerLevel, DamageSource, float)Z}, which + * is EnderMan's own override of {@code LivingEntity#hurtServer}. The mixin still extends + * {@link LivingEntity} purely so {@code super.hurtServer(...)} resolves past EnderMan's (and + * Monster's, which does not override it) dodge behaviour straight to the vanilla + * {@link LivingEntity#hurtServer} implementation, exactly like the old {@code super.damage(...)} + * call bypassed {@code EndermanEntity}'s override. + *

+ * {@code EndermanEntity#teleportTo(DDD)Z} no longer exists: {@code Entity#teleportTo(DDD)} is + * now {@code void}, and the boolean-returning teleport-execution logic Enderman used to + * override lives in its own private {@code teleport(double, double, double)} method. + *

+ * {@code LivingEntity#getStatusEffect} was renamed to {@code getEffect}. + */ +@Mixin(EnderMan.class) abstract class EndermanEntityMixin extends LivingEntity { - private EndermanEntityMixin(EntityType entityType, World world) { + private EndermanEntityMixin(EntityType entityType, Level world) { super(entityType, world); } @SuppressWarnings("all") @Unique - private EndermanEntity self() { - return (EndermanEntity) (Object) this; + private EnderMan self() { + return (EnderMan) (Object) this; } - @Inject(method = "damage", at = @At("HEAD"), cancellable = true) - private void damage(DamageSource source, float amount, CallbackInfoReturnable cir) { - final var self = (EndermanEntity) (Object) this; - final var crippleMovement = ModMobEffects.getCrippleMovementEffect(); - final var effect = self().getStatusEffect(crippleMovement); + @Inject(method = "hurtServer", at = @At("HEAD"), cancellable = true) + private void hurtServer(ServerLevel level, DamageSource source, float amount, CallbackInfoReturnable cir) { + final var self = (EnderMan) (Object) this; + final var crippleMovement = ModMobEffects.INSTANCE.getCrippleMovement(); + final var effect = self().getEffect(crippleMovement); if (effect == null && !ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { return; } - final var result = super.damage(source, amount); + final var result = super.hurtServer(level, source, amount); cir.setReturnValue(result); } - @Inject(method = "teleportTo(DDD)Z", at = @At("HEAD"), cancellable = true) - private void teleportTo(double x, double y, double z, CallbackInfoReturnable cir) { - final var self = (EndermanEntity) (Object) this; + @Inject(method = "teleport(DDD)Z", at = @At("HEAD"), cancellable = true) + private void teleport(double x, double y, double z, CallbackInfoReturnable cir) { + final var self = (EnderMan) (Object) this; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { cir.setReturnValue(false); } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/EntityInvoker.java b/common/src/main/java/heckerpowered/matrix/mixin/EntityInvoker.java new file mode 100644 index 00000000..d63a920d --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/EntityInvoker.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +/** See {@link TickRateManagerAccessor} for why this is an invoker, not a tweaker widening. */ +@Mixin(Entity.class) +public interface EntityInvoker { + @Invoker("isInvulnerableToBase") + boolean matrix$isInvulnerableToBase(DamageSource damageSource); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionAccessor.java new file mode 100644 index 00000000..1a9fd3af --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionAccessor.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.util.ClassInstanceMultiMap; +import net.minecraft.world.level.entity.EntitySection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** See {@link TickRateManagerAccessor} for why this is an accessor, not a tweaker widening. */ +@Mixin(EntitySection.class) +public interface EntitySectionAccessor { + @Accessor("storage") + ClassInstanceMultiMap matrix$getStorage(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionStorageAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionStorageAccessor.java new file mode 100644 index 00000000..25b131c1 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/EntitySectionStorageAccessor.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import it.unimi.dsi.fastutil.longs.LongSortedSet; +import net.minecraft.world.level.entity.EntitySectionStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** See {@link TickRateManagerAccessor} for why this is an accessor, not a tweaker widening. */ +@Mixin(EntitySectionStorage.class) +public interface EntitySectionStorageAccessor { + @Accessor("sectionIds") + LongSortedSet matrix$getSectionIds(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/EntityTrackerEntryMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/EntityTrackerEntryMixin.java index afc7b542..2ca485ef 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/EntityTrackerEntryMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/EntityTrackerEntryMixin.java @@ -6,11 +6,11 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.magic.system.MagicSystem; -import net.minecraft.entity.Entity; -import net.minecraft.network.listener.ClientPlayPacketListener; -import net.minecraft.network.packet.Packet; -import net.minecraft.server.network.EntityTrackerEntry; -import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.world.entity.Entity; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerPlayer; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,14 +20,18 @@ import java.util.function.Consumer; -@Mixin(EntityTrackerEntry.class) +/** + * 26.2: {@code EntityTrackerEntry#sendPackets} (Yarn) — invoked once when a player starts + * tracking (pairs with) an entity — is now {@code ServerEntity#sendPairingData}. + */ +@Mixin(ServerEntity.class) class EntityTrackerEntryMixin { @Shadow @Final private Entity entity; - @Inject(method = "sendPackets", at = @At("TAIL")) - private void sendPackets(ServerPlayerEntity player, Consumer> sender, CallbackInfo ci) { + @Inject(method = "sendPairingData", at = @At("TAIL")) + private void sendPairingData(ServerPlayer player, Consumer> sender, CallbackInfo ci) { MagicSystem.onEntityTracked(player, entity); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/FireBeamGoalMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/FireBeamGoalMixin.java index 4ef787bc..ce63f94f 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/FireBeamGoalMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/FireBeamGoalMixin.java @@ -6,7 +6,7 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.effect.ManaOverloadEffect; -import net.minecraft.entity.mob.GuardianEntity; +import net.minecraft.world.entity.monster.Guardian; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,21 +15,29 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(GuardianEntity.FireBeamGoal.class) +/** + * 26.2: {@code GuardianEntity.FireBeamGoal} (Yarn) no longer exists as a separate goal — + * vanilla merged the laser-beam attack into {@link Guardian.GuardianAttackGoal}, which now + * owns targeting/movement AND the beam charge-up/damage that {@code FireBeamGoal} used to + * handle alone. The {@code guardian} field and {@code canStart}/{@code shouldContinue}/ + * {@code start}/{@code tick} lifecycle are preserved 1:1 under their new + * {@code canUse}/{@code canContinueToUse}/{@code start}/{@code tick} names. + */ +@Mixin(Guardian.GuardianAttackGoal.class) class FireBeamGoalMixin { @Shadow @Final - private GuardianEntity guardian; + private Guardian guardian; - @Inject(method = "canStart", at = @At("HEAD"), cancellable = true) - private void canStart(CallbackInfoReturnable cir) { + @Inject(method = "canUse", at = @At("HEAD"), cancellable = true) + private void canUse(CallbackInfoReturnable cir) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(guardian)) { cir.setReturnValue(false); } } - @Inject(method = "shouldContinue", at = @At("HEAD"), cancellable = true) - private void shouldContinue(CallbackInfoReturnable cir) { + @Inject(method = "canContinueToUse", at = @At("HEAD"), cancellable = true) + private void canContinueToUse(CallbackInfoReturnable cir) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(guardian)) { cir.setReturnValue(false); } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/FramebufferMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/FramebufferMixin.java index 28f15159..2efa69ff 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/FramebufferMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/FramebufferMixin.java @@ -5,56 +5,40 @@ package heckerpowered.matrix.mixin; +import com.mojang.blaze3d.GpuFormat; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.textures.GpuTexture; import heckerpowered.matrix.client.event.InitAttachmentCallback; -import heckerpowered.matrix.client.render.OpenGLExtensions; import heckerpowered.matrix.client.render.RenderExtensionsKt; import heckerpowered.matrix.core.FramebufferExtension; -import kotlin.Unit; -import net.minecraft.client.gl.Framebuffer; -import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryUtil; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.Redirect; -import java.nio.IntBuffer; - -import static com.mojang.blaze3d.platform.GlStateManager._texImage2D; -import static heckerpowered.matrix.Matrix.LOGGER; -import static org.lwjgl.opengl.GL46.*; +import java.util.function.Supplier; /** - * Mixin for the {@link Framebuffer} class to extend its functionality. + * Mixin for the {@link RenderTarget} class to extend its functionality. + *

+ * Adds optional full-mipmap-chain allocation for the color attachment (used by the bloom + * pipeline), applied through the backend-agnostic {@link GpuDevice#createTexture} wrapper + * inside {@code createBuffers}, so it works on both the Vulkan and OpenGL backends. *

- * This mixin adds support for: - *

    - *
  • Using alternative color formats for the framebuffer texture, such as RGBA16, enabling HDR rendering.
  • - *
  • Allocating and generating mipmaps for framebuffer's color attachment texture during initialization, if enabled.
  • - *
- *

+ * 26.2 release note: the pre-migration global HDR color-format override is gone. Release + * pipelines declare their color target format and render passes validate the attachment + * against it, so vanilla-rendered targets (the main framebuffer, entity/GUI capture targets) + * must keep the format vanilla created them with; HDR formats are now passed explicitly to + * the mod's own render targets instead (see FramebufferExtension.framebufferColorFormat). * * @author heckerpowered */ -@Mixin(Framebuffer.class) +@Mixin(RenderTarget.class) class FramebufferMixin implements FramebufferExtension { - @Unique - private static final Marker MARKER = MarkerFactory.getMarker("FRAMEBUFFER_MIXIN"); - @Shadow - protected int colorAttachment; @Unique private boolean useMipmaps = false; - @ModifyConstant(method = "initFbo", constant = @Constant(intValue = GL_RGBA8)) - private int modify$imageFormat(int constant) { - return FramebufferExtension.getFramebufferColorFormat(); - } - @SuppressWarnings("all") @Override public boolean getUseMipmaps() { @@ -67,49 +51,23 @@ public void setUseMipmaps(boolean b) { useMipmaps = b; } + /** + * The second createTexture invocation inside createBuffers allocates the color + * attachment (the first one is the depth attachment); allocate a full mipmap chain + * when enabled. + */ @Redirect( - method = "initFbo", + method = "createBuffers", at = @At( value = "INVOKE", - target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texImage2D(IIIIIIIILjava/nio/IntBuffer;)V" + target = "Lcom/mojang/blaze3d/systems/GpuDevice;createTexture(Ljava/util/function/Supplier;ILcom/mojang/blaze3d/GpuFormat;IIII)Lcom/mojang/blaze3d/textures/GpuTexture;", + ordinal = 1 ) ) - private void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, @Nullable IntBuffer pixels) { - InitAttachmentCallback.EVENT.invoker().onInitAttachment((Framebuffer) (Object) this); - final var isDepthAttachment = format == GL_DEPTH_COMPONENT; - if (!useMipmaps || isDepthAttachment) { - _texImage2D(target, level, internalFormat, width, height, border, format, type, pixels); - return; - } - - OpenGLExtensions.clearGLError(); - - @SuppressWarnings("DataFlowIssue") final var self = (Framebuffer) (Object) this; - final var recommendMipLevels = RenderExtensionsKt.recommendMipLevel(self); - glTexStorage2D(target, recommendMipLevels, internalFormat, width, height); - OpenGLExtensions.checkGLError(error -> { - final var name = OpenGLExtensions.getErrorName(error); - final var message = OpenGLExtensions.getErrorDescription(error); - LOGGER.error(MARKER, "Error occurs during call `glTexStorage2D`: {}", name); - LOGGER.error(MARKER, message); - LOGGER.error(MARKER, "Target: {}, Level: {}, InternalFormat: {}, Width: {}, Height: {}", target, level, internalFormat, width, height); - return Unit.INSTANCE; - }); - - final var packedPixelDataType = OpenGLExtensions.getPackedPixelDataTypeForFormat(internalFormat); - final var bytesPerPixel = OpenGLExtensions.getBytesPerPixel(format, type); - final var bufferSize = width * height * bytesPerPixel; - final var buffer = MemoryUtil.memAlloc(bufferSize); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, buffer); - MemoryUtil.memFree(buffer); - - OpenGLExtensions.checkGLError(error -> { - final var name = OpenGLExtensions.getErrorName(error); - final var message = OpenGLExtensions.getErrorDescription(error); - LOGGER.error(MARKER, "Error occurs during call `glTexSubImage2D`: {}", name); - LOGGER.error(MARKER, message); - LOGGER.error(MARKER, "Width: {}, Height: {}, Format: {} Type: {}:", width, height, format, packedPixelDataType); - return Unit.INSTANCE; - }); + private GpuTexture matrix$createColorTexture(GpuDevice device, Supplier label, int usage, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels) { + final var levels = useMipmaps ? Math.max(RenderExtensionsKt.recommendMipLevel(width, height), 1) : mipLevels; + final var texture = device.createTexture(label, usage, format, width, height, depthOrLayers, levels); + InitAttachmentCallback.EVENT.invoker().onInitAttachment((RenderTarget) (Object) this); + return texture; } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/GameRendererMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/GameRendererMixin.java index 34148c08..b077d24a 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/GameRendererMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/GameRendererMixin.java @@ -5,105 +5,101 @@ package heckerpowered.matrix.mixin; -import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef; -import heckerpowered.matrix.client.MatrixHud; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.vertex.PoseStack; import heckerpowered.matrix.client.TimeController; -import heckerpowered.matrix.client.render.MatrixRenderSystem; +import heckerpowered.matrix.client.core.FramebufferSpoof; +import heckerpowered.matrix.client.render.GuideLineRenderer; import heckerpowered.matrix.client.render.PostProcessRenderer; -import heckerpowered.matrix.client.render.post.CameraShake; import heckerpowered.matrix.client.shader.BlurRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.world.BlockView; -import org.joml.Matrix4f; -import org.spongepowered.asm.mixin.Final; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.state.level.CameraRenderState; 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; +/** + * 26.2 re-anchoring of the pre-migration GameRenderer hooks: + * onResized→resize, render-before-InGameHud→render-before-GuiRenderer.render(), + * renderWorld's Camera.update(BlockView,Entity,ZZF)→update's Camera.update(DeltaTracker) + * (the standalone tick counter is itself a DeltaTracker now), renderHand→renderItemInHand, + * and the getFov/loadProjectionMatrix hooks moved to {@link CameraMixin} where fov and the + * projection matrix now live. The Minecraft.getFramebuffer() spoof retargets the + * mainRenderTarget() accessor. + */ @Mixin(GameRenderer.class) class GameRendererMixin { - @Shadow - @Final - private Camera camera; - private GameRendererMixin() { } - @Inject(method = "onResized", at = @At("HEAD")) + @Inject(method = "resize", at = @At("HEAD")) private void onResized(int width, int height, CallbackInfo ci) { // UIBlurShader.setupDimensions(width, height); BlurRenderer.onResize(width, height); PostProcessRenderer.onResize(width, height); } - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;render(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/client/render/RenderTickCounter;)V", shift = At.Shift.BEFORE)) - private void beginRender(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/GuiRenderer;render()V", shift = At.Shift.BEFORE)) + private void beginRender(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + // The 1.21 anchor (before InGameHud.render) only fired with a level loaded; + // GuiRenderer.render() also covers the loading overlay and title screen, so guard + // to preserve the original "in-world only" semantics (and to avoid touching the + // shader pipelines before the first resource reload has loaded their sources). + if (Minecraft.getInstance().level == null) { + return; + } PostProcessRenderer.renderToMinecraftFramebuffer(); + // Builds this frame's guide-line mesh and draws the 8x HDR bloom-feed overlay; the + // VISIBLE lines join the HUD capture later in the frame (MatrixHud.onHudCaptureBegin), + // matching 1.21 where they were hudFramebuffer content over the backdrop blur. + GuideLineRenderer.render(); } @Inject(method = "render", at = @At(value = "TAIL")) - private void endRender(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + private void endRender(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { // PostProcessRenderer.endHudRender(); } - @Inject(method = "getFov", at = @At("TAIL"), cancellable = true) - private void getFov(Camera camera, float tickDelta, boolean changingFov, CallbackInfoReturnable cir) { - final var returnValue = cir.getReturnValueD(); - cir.setReturnValue(returnValue * MatrixHud.fovAnimation.getAnimatedValue()); - } - - @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;update(Lnet/minecraft/world/BlockView;Lnet/minecraft/entity/Entity;ZZF)V")) - private void updateCamera(Camera instance, BlockView area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickDelta) { + @Redirect(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;update(Lnet/minecraft/client/DeltaTracker;)V")) + private void updateCamera(Camera instance, DeltaTracker deltaTracker) { if (TimeController.getPlayerStandaloneRenderTick()) { - camera.update(area, focusedEntity, thirdPerson, inverseView, TimeController.standaloneRenderTickCounter.getTickDelta(true)); + instance.update(TimeController.standaloneRenderTickCounter); } else { - camera.update(area, focusedEntity, thirdPerson, inverseView, tickDelta); - } - } - - @Inject(method = "getFov", at = @At("HEAD")) - private void getFovHead(Camera camera, float tickDelta, boolean changingFov, CallbackInfoReturnable cir, @Local(argsOnly = true) LocalFloatRef tickDeltaRef) { - if (TimeController.getPlayerStandaloneRenderTick()) { - tickDeltaRef.set(TimeController.standaloneRenderTickCounter.getTickDelta(true)); + instance.update(deltaTracker); } } - @Inject(method = "renderHand", at = @At("HEAD")) - private void renderHand(Camera camera, float tickDelta, Matrix4f matrix4f, CallbackInfo ci, @Local(argsOnly = true) LocalFloatRef tickDeltaRef) { + @ModifyVariable(method = "renderItemInHand", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private float renderHand(float tickDelta) { if (TimeController.getPlayerStandaloneRenderTick()) { - tickDeltaRef.set(TimeController.standaloneRenderTickCounter.getTickDelta(true)); + return TimeController.standaloneRenderTickCounter.getGameTimeDeltaPartialTick(true); } + return tickDelta; } @Inject(method = "bobView", at = @At("HEAD"), cancellable = true) - private void bobView(MatrixStack matrices, float tickDelta, CallbackInfo ci) { - final var minecraft = MinecraftClient.getInstance(); + private void bobView(CameraRenderState cameraRenderState, PoseStack matrices, CallbackInfo ci) { + final var minecraft = Minecraft.getInstance(); final var player = minecraft.player; if (player != null && isPhaseWalking(player)) { ci.cancel(); } } - @Inject(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupFrustum(Lnet/minecraft/util/math/Vec3d;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V", shift = At.Shift.BEFORE)) - private void renderWorld(RenderTickCounter tickCounter, CallbackInfo ci, @Local(ordinal = 1) Matrix4f viewMatrix) { - CameraShake.applyCameraShake(viewMatrix); - } - - @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;loadProjectionMatrix(Lorg/joml/Matrix4f;)V")) - private void loadProjectionMatrix(GameRenderer instance, Matrix4f projectionMatrix) { - MatrixRenderSystem.setupMatrix(camera, projectionMatrix); - instance.loadProjectionMatrix(projectionMatrix); + @Inject(method = "mainRenderTarget", at = @At("HEAD"), cancellable = true) + private void getFramebuffer(CallbackInfoReturnable cir) { + final var spoofedFramebuffer = FramebufferSpoof.getSpoofedFramebuffer(); + if (spoofedFramebuffer != null) { + cir.setReturnValue(spoofedFramebuffer); + } } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateAccessor.java new file mode 100644 index 00000000..d64a0f7f --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateAccessor.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.client.renderer.state.gui.GuiRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GuiRenderState.class) +public interface GuiRenderStateAccessor { + @Accessor("firstStratumAfterBlur") + int matrix$getFirstStratumAfterBlur(); + + @Accessor("firstStratumAfterBlur") + void matrix$setFirstStratumAfterBlur(int value); + + @Accessor("strata") + java.util.List matrix$getStrata(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateMixin.java new file mode 100644 index 00000000..91ce4d40 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/GuiRenderStateMixin.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import heckerpowered.matrix.extension.MatrixGuiRenderState; +import net.minecraft.client.renderer.state.gui.GuiRenderState; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +/** + * Stratum bookkeeping for the Matrix HUD capture (see {@link MatrixGuiRenderState}). + */ +@Mixin(GuiRenderState.class) +@Implements(@Interface(iface = MatrixGuiRenderState.class, prefix = "matrix$")) +abstract class GuiRenderStateMixin { + @Shadow + @Final + private List strata; + + @Shadow + private int firstStratumAfterBlur; + + @Shadow + public abstract void nextStratum(); + + @Unique + private int matrix$hudStrataStart = -1; + + @Unique + private int matrix$hudStrataEnd = Integer.MAX_VALUE; + + public void matrix$beginMatrixHudStratum() { + nextStratum(); + matrix$hudStrataStart = strata.size() - 1; + } + + public void matrix$endMatrixHudStratum() { + // The fresh stratum receives everything extracted after the HUD callback (screens, + // tooltips, toasts), so its index is the exclusive end of the captured segment. + nextStratum(); + matrix$hudStrataEnd = strata.size() - 1; + } + + public boolean matrix$hasMatrixHudStratum() { + // Vanilla's fence defaults to Integer.MAX_VALUE and is lowered by blur markers; even + // in-world a trailing vanilla overlay stratum can carry one (observed fence = hudStart + // + 1). The capture split composes as long as the Matrix stratum sits BELOW the fence + // (its draws then live inside the first draw range); otherwise degrade to vanilla. + return matrix$hudStrataStart >= 0 && firstStratumAfterBlur > matrix$hudStrataStart; + } + + public int matrix$matrixHudStrataStart() { + return matrix$hudStrataStart; + } + + public int matrix$matrixHudStrataEnd() { + return matrix$hudStrataEnd; + } + + @Inject(method = "reset", at = @At("TAIL")) + private void reset(CallbackInfo ci) { + matrix$hudStrataStart = -1; + matrix$hudStrataEnd = Integer.MAX_VALUE; + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/GuiRendererMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/GuiRendererMixin.java new file mode 100644 index 00000000..9ce43d19 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/GuiRendererMixin.java @@ -0,0 +1,152 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.RenderTarget; +import heckerpowered.matrix.client.MatrixHud; +import heckerpowered.matrix.client.render.PostProcessRenderer; +import heckerpowered.matrix.extension.MatrixGuiRenderState; +import net.minecraft.client.gui.render.GuiRenderer; +import net.minecraft.client.renderer.state.gui.GuiRenderState; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; +import java.util.function.Supplier; + +/** + * Captures the Matrix HUD stratum into MatrixHud.hudFramebuffer, restoring 1.21's + * "HUD drawn into its own framebuffer, then composited with blur/shadow/bloom" semantics on + * the 26.2 deferred GUI pipeline: + *

+ * prepare(): with vanilla's default fence (Integer.MAX_VALUE = no menu blur) the FIRST mesh + * build covers every stratum; it is split at the Matrix HUD stratum boundary by temporarily + * lowering the firstStratumAfterBlur fence, so the HUD's draws start at a recorded index in + * their own Draw batch. + *

+ * draw(): the first executeDrawRange is split at that index — vanilla GUI keeps rendering + * into the main target, the HUD tail renders into hudFramebuffer, and + * MatrixHud.onHudCaptured() then runs the 1.21 composite chain back onto the main target. + */ +@Mixin(GuiRenderer.class) +abstract class GuiRendererMixin { + @Shadow + @Final + private GuiRenderState renderState; + + @Shadow + @Final + private List draws; + + @Shadow + protected abstract void addElementsToMeshes(GuiRenderState.TraverseRange range); + + @Shadow + protected abstract void executeDrawRange(Supplier name, RenderTarget target, GpuBufferSlice dynamicTransforms, int fromIndex, int toIndex); + + @Unique + private int matrix$hudFirstDrawIndex = Integer.MAX_VALUE; + + @Unique + private int matrix$hudDrawEndIndex = Integer.MAX_VALUE; + + private GuiRendererMixin() { + } + + @Redirect( + method = "prepare", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/render/GuiRenderer;addElementsToMeshes(Lnet/minecraft/client/renderer/state/gui/GuiRenderState$TraverseRange;)V", + ordinal = 0 + ) + ) + private void matrix$splitHudMeshes(GuiRenderer instance, GuiRenderState.TraverseRange range) { + matrix$hudFirstDrawIndex = Integer.MAX_VALUE; + matrix$hudDrawEndIndex = Integer.MAX_VALUE; + final var matrixState = (MatrixGuiRenderState) (Object) renderState; + if (!matrixState.hasMatrixHudStratum()) { + addElementsToMeshes(range); + return; + } + + final var accessor = (GuiRenderStateAccessor) (Object) renderState; + final var savedBlurFence = accessor.matrix$getFirstStratumAfterBlur(); + final var hudStart = matrixState.matrixHudStrataStart(); + // The captured segment is [hudStart, hudEnd); post-HUD strata (screens, tooltips, + // toasts) begin at the end marker, or at the real blur fence if it sits lower + // (observed in-world: a trailing vanilla stratum carries a blur marker). + final var hudEnd = Math.min(matrixState.matrixHudStrataEnd(), savedBlurFence); + @SuppressWarnings("unchecked") final var strata = (List) matrix$strata((GuiRenderState) (Object) renderState); + + // 1) Vanilla GUI below the HUD: fence lowered to hudStart, BEFORE_BLUR = [0, hudStart). + accessor.matrix$setFirstStratumAfterBlur(hudStart); + addElementsToMeshes(GuiRenderState.TraverseRange.BEFORE_BLUR); + matrix$hudFirstDrawIndex = draws.size(); + + // 2) The Matrix HUD segment [hudStart, hudEnd): AFTER_BLUR with the lowered fence + // would run to the END of the strata list, swallowing everything extracted after the + // HUD callback, so the tail beyond hudEnd is detached for this traversal. + final var hudTailFrom = Math.min(hudEnd, strata.size()); + final var hudTail = new java.util.ArrayList<>(strata.subList(hudTailFrom, strata.size())); + strata.subList(hudTailFrom, strata.size()).clear(); + addElementsToMeshes(GuiRenderState.TraverseRange.AFTER_BLUR); + strata.addAll(hudTail); + matrix$hudDrawEndIndex = draws.size(); + + // 3) Post-HUD strata that still belong BEFORE the real blur fence [hudEnd, + // savedBlurFence) — screens/tooltips/toasts when no menu blur is active. Vanilla's own + // AFTER_BLUR pass only covers [savedBlurFence, end), so they are built here (into the + // first draw range, after the captured segment) or they would never render. + final var postTailFrom = Math.min(savedBlurFence, strata.size()); + if (hudTailFrom < postTailFrom) { + final var postTail = new java.util.ArrayList<>(strata.subList(postTailFrom, strata.size())); + strata.subList(postTailFrom, strata.size()).clear(); + accessor.matrix$setFirstStratumAfterBlur(hudTailFrom); + addElementsToMeshes(GuiRenderState.TraverseRange.AFTER_BLUR); + strata.addAll(postTail); + } + accessor.matrix$setFirstStratumAfterBlur(savedBlurFence); + } + + @Redirect( + method = "draw", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/render/GuiRenderer;executeDrawRange(Ljava/util/function/Supplier;Lcom/mojang/blaze3d/pipeline/RenderTarget;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;II)V", + ordinal = 0 + ) + ) + private void matrix$drawHudRange(GuiRenderer instance, Supplier name, RenderTarget target, GpuBufferSlice dynamicTransforms, int fromIndex, int toIndex) { + final var hudFrom = Math.min(matrix$hudFirstDrawIndex, toIndex); + final var hudTo = Math.min(matrix$hudDrawEndIndex, toIndex); + if (fromIndex < hudFrom) { + executeDrawRange(name, target, dynamicTransforms, fromIndex, hudFrom); + } + if (hudFrom < hudTo) { + final var hudFramebuffer = MatrixHud.INSTANCE.getHudFramebuffer(); + PostProcessRenderer.clear(hudFramebuffer); + MatrixHud.onHudCaptureBegin(); + executeDrawRange(name, hudFramebuffer, dynamicTransforms, hudFrom, hudTo); + MatrixHud.onHudCaptured(); + } + if (hudTo < toIndex) { + // Post-HUD GUI (screens, tooltips, toasts) drawn after the composite, back onto + // the main target — the 1.21 ordering, where they rendered after InGameHud. + executeDrawRange(name, target, dynamicTransforms, hudTo, toIndex); + } + } + + @Unique + private static List matrix$strata(GuiRenderState state) { + return ((GuiRenderStateAccessor) (Object) state).matrix$getStrata(); + } +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/ItemStackMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/ItemStackMixin.java index b04d1cd1..96add704 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/ItemStackMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/ItemStackMixin.java @@ -5,7 +5,7 @@ package heckerpowered.matrix.mixin; -import net.minecraft.item.ItemStack; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; @Mixin(ItemStack.class) diff --git a/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java index eabb1b96..933f4f1d 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/KeyboardMixin.java @@ -6,17 +6,22 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.client.MatrixHud; -import net.minecraft.client.Keyboard; +import net.minecraft.client.KeyboardHandler; +import net.minecraft.client.input.KeyEvent; 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.CallbackInfo; -@Mixin(Keyboard.class) +/** + * 26.2: Keyboard is KeyboardHandler and onKey(window, key, scancode, action, modifiers) + * became keyPress(window, action, KeyEvent(key, scancode, modifiers)). + */ +@Mixin(KeyboardHandler.class) class KeyboardMixin { - @Inject(method = "onKey", at = @At("HEAD"), cancellable = true) - private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { - if (MatrixHud.onKey(window, key, scancode, action, modifiers)) { + @Inject(method = "keyPress", at = @At("HEAD"), cancellable = true) + private void onKey(long window, int action, KeyEvent event, CallbackInfo ci) { + if (MatrixHud.onKey(window, event.key(), event.scancode(), action, event.modifiers())) { ci.cancel(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/LevelEntityGetterAdapterAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/LevelEntityGetterAdapterAccessor.java new file mode 100644 index 00000000..8906f7d6 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/LevelEntityGetterAdapterAccessor.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.level.entity.EntitySectionStorage; +import net.minecraft.world.level.entity.LevelEntityGetterAdapter; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** See {@link TickRateManagerAccessor} for why this is an accessor, not a tweaker widening. */ +@Mixin(LevelEntityGetterAdapter.class) +public interface LevelEntityGetterAdapterAccessor { + @Accessor("sectionStorage") + EntitySectionStorage matrix$getSectionStorage(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityAccessor.java new file mode 100644 index 00000000..43b8e702 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityAccessor.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.entity.EntityReference; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +/** + * Mixin accessors instead of class-tweaker field widenings; see + * {@link TickRateManagerAccessor} for why the tweaker's accessible entries cannot be relied + * on in production. + */ +@Mixin(LivingEntity.class) +public interface LivingEntityAccessor { + @Accessor("attackStrengthTicker") + void matrix$setAttackStrengthTicker(int value); + + @Accessor("lastHurtByPlayer") + void matrix$setLastHurtByPlayer(EntityReference value); + + @Accessor("lastHurtByPlayerMemoryTime") + void matrix$setLastHurtByPlayerMemoryTime(int value); + + @Accessor("useItemRemaining") + void matrix$setUseItemRemaining(int value); + + @Invoker("internalSetAbsorptionAmount") + void matrix$internalSetAbsorptionAmount(float amount); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java index b08dd488..21d3349c 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/LivingEntityMixin.java @@ -301,7 +301,8 @@ private void onEquipStack(EquipmentSlot slot, ItemStack oldStack, ItemStack stac @Inject(method = "knockback", at = @At("HEAD"), cancellable = true) private void knockback( - double power, double x, double z, CallbackInfo ci, + // 26.2 release: knockback gained (DamageSource source, float amount, boolean sprinting) + double power, double x, double z, net.minecraft.world.damagesource.DamageSource source, float amount, boolean sprinting, CallbackInfo ci, @Local(argsOnly = true, name = "power") LocalDoubleRef powerReference, @Local(argsOnly = true, name = "xd") LocalDoubleRef xReference, @Local(argsOnly = true, name = "zd") LocalDoubleRef zReference) { diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftClientMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftClientMixin.java index d0f057bb..04a5232c 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftClientMixin.java @@ -8,12 +8,10 @@ import heckerpowered.matrix.client.MatrixClient; import heckerpowered.matrix.client.MatrixHud; import heckerpowered.matrix.client.TimeController; -import heckerpowered.matrix.client.core.FramebufferSpoof; import heckerpowered.matrix.client.event.FinishRenderCallback; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.RunArgs; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.main.GameConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -22,7 +20,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(MinecraftClient.class) +/** + * 26.2: MinecraftClient is Minecraft, render() is runTick(boolean), doAttack() is + * startAttack(), and the render tick counter is a DeltaTracker.Timer + * (beginRenderTick→advanceGameTime, tick→updatePauseState, setTickFrozen→updateFrozenState). + * The former getFramebuffer() spoof hook moved to GameRendererMixin#mainRenderTarget. + */ +@Mixin(Minecraft.class) abstract class MinecraftClientMixin { private MinecraftClientMixin() { } @@ -30,45 +34,41 @@ private MinecraftClientMixin() { @Shadow public abstract void tick(); - @Inject(method = "doAttack", at = @At("HEAD")) + @Inject(method = "startAttack", at = @At("HEAD")) private void doAttack(CallbackInfoReturnable cir) { MatrixHud.onDoAttack(); } - @Inject(method = "getFramebuffer", at = @At("HEAD"), cancellable = true) - private void getFramebuffer(CallbackInfoReturnable cir) { - final var spoofedFramebuffer = FramebufferSpoof.getSpoofedFramebuffer(); - if (spoofedFramebuffer != null) { - cir.setReturnValue(spoofedFramebuffer); - } - } - - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gl/Framebuffer;draw(II)V", shift = At.Shift.BEFORE)) + /** + * The former "before the final framebuffer draw" anchor; the event currently has no + * registered listeners, so end-of-frame is an equivalent firing point. + */ + @Inject(method = "runTick", at = @At("TAIL")) private void onFinishedRender(boolean tick, CallbackInfo ci) { FinishRenderCallback.EVENT.invoker().onFinishRender(); } - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderTickCounter$Dynamic;beginRenderTick(JZ)I")) - private int beginRenderTick(RenderTickCounter.Dynamic instance, long timeMillis, boolean tick) { - final var tickCount = instance.beginRenderTick(timeMillis, tick); - TimeController.beginRenderTick(timeMillis, tick); + @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/DeltaTracker$Timer;advanceGameTime(J)I")) + private int beginRenderTick(DeltaTracker.Timer instance, long timeMillis) { + final var tickCount = instance.advanceGameTime(timeMillis); + TimeController.beginRenderTick(timeMillis, true); return tickCount; } - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderTickCounter$Dynamic;tick(Z)V")) - private void tick(RenderTickCounter.Dynamic instance, boolean paused) { - instance.tick(paused); - TimeController.standaloneRenderTickCounter.tick(paused); + @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/DeltaTracker$Timer;updatePauseState(Z)V")) + private void tick(DeltaTracker.Timer instance, boolean paused) { + instance.updatePauseState(paused); + TimeController.standaloneRenderTickCounter.updatePauseState(paused); } - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderTickCounter$Dynamic;setTickFrozen(Z)V")) - private void setTickFrozen(RenderTickCounter.Dynamic instance, boolean frozen) { - instance.setTickFrozen(frozen); - TimeController.standaloneRenderTickCounter.setTickFrozen(frozen); + @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/DeltaTracker$Timer;updateFrozenState(Z)V")) + private void setTickFrozen(DeltaTracker.Timer instance, boolean frozen) { + instance.updateFrozenState(frozen); + TimeController.standaloneRenderTickCounter.updateFrozenState(frozen); } - @Inject(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/WindowProvider;createWindow(Lnet/minecraft/client/WindowSettings;Ljava/lang/String;Ljava/lang/String;)Lnet/minecraft/client/util/Window;", shift = At.Shift.AFTER)) - private void createWindow(RunArgs args, CallbackInfo ci) { + @Inject(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/Window;(Lcom/mojang/blaze3d/platform/WindowEventHandler;Lcom/mojang/blaze3d/platform/DisplayData;Ljava/lang/String;ZLjava/lang/String;Lcom/mojang/blaze3d/platform/MonitorManager;Lcom/mojang/blaze3d/systems/GpuBackend;)V", shift = At.Shift.AFTER)) + private void createWindow(GameConfig args, CallbackInfo ci) { MatrixClient.onWindowInitialization(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerAccessor.java new file mode 100644 index 00000000..18a74eaa --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerAccessor.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.server.MinecraftServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Mixin accessor instead of class-tweaker field widenings; see {@link TickRateManagerAccessor} + * for why the tweaker's accessible-field entries cannot be relied on in production. + */ +@Mixin(MinecraftServer.class) +public interface MinecraftServerAccessor { + @Accessor("waitingForNextTick") + void matrix$setWaitingForNextTick(boolean value); + + @Accessor("nextTickTimeNanos") + long matrix$getNextTickTimeNanos(); + + @Accessor("nextTickTimeNanos") + void matrix$setNextTickTimeNanos(long value); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java index 897563ed..3e106527 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MinecraftServerMixin.java @@ -6,8 +6,11 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.extension.MatrixMinecraftServer; +import net.minecraft.network.PacketProcessor; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.ServerTickRateManager; +import net.minecraft.server.TickTask; +import net.minecraft.util.Util; +import net.minecraft.util.thread.ReentrantBlockableEventLoop; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -15,29 +18,48 @@ import java.util.function.BooleanSupplier; +/** + * Time-warp server support, restored from 16a3466 ("Fix time warp"): + *

+ * The waitForTasks HEAD hook keeps the integrated server responsive while a warp stretches + * ticks to multiple seconds: 26.2's PacketProcessor queue is only drained at tick-top by + * vanilla (and its enqueue does not wake the parked server thread), so serverbound packets — + * including the warp-restore payload and player movement — are drained here on every wait + * iteration instead, and waitingForNextTick is forced false so the wait uses the short-poll + * branch rather than parking for the whole warped tick. + *

+ * The interface is attached via the classtweaker's inject-interface entry plus the soft + * {@code @Implements} below (NOT a direct {@code implements} on the mixin class). + */ @Mixin(MinecraftServer.class) @Implements(@Interface(iface = MatrixMinecraftServer.class, prefix = "matrix$")) -class MinecraftServerMixin implements MatrixMinecraftServer { - +abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop { @Shadow - @Final - private ServerTickRateManager tickRateManager; + public boolean waitingForNextTick; @Unique long matrix$tickStartTimeNanos; - @Unique - long matrix$tickEndTimeNanos; - + @Shadow + @Final + private PacketProcessor packetProcessor; + public MinecraftServerMixin(String name, boolean propagatesCrashes) { + super(name, propagatesCrashes); + } - private MinecraftServerMixin() { + @Inject(method = "waitForTasks", at = @At("HEAD")) + private void waitForTasks(CallbackInfo ci) { + waitingForNextTick = false; + packetProcessor.processQueuedPackets(); } @Inject(method = "tickServer", at = @At("HEAD")) private void tick(BooleanSupplier haveTime, CallbackInfo ci) { - matrix$tickStartTimeNanos = System.nanoTime(); - matrix$tickEndTimeNanos = matrix$tickStartTimeNanos + tickRateManager.nanosecondsPerTick(); + // Util.getNanos(), not System.nanoTime(): this feeds nextTickTimeNanos math in + // ServerTimeRatio, and the server loop's clock is Util's time source, which the + // client JVM redirects to the GLFW timer (different epoch than System.nanoTime). + matrix$tickStartTimeNanos = Util.getNanos(); } public long matrix$getTickStartTimeNanos() { @@ -47,12 +69,4 @@ private void tick(BooleanSupplier haveTime, CallbackInfo ci) { public void matrix$setTickStartTimeNanos(long l) { matrix$tickStartTimeNanos = l; } - - public long matrix$getTickEndTimeNanos() { - return matrix$tickEndTimeNanos; - } - - public void matrix$setTickEndTimeNanos(long l) { - matrix$tickEndTimeNanos = l; - } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java b/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java index 336ba496..a62caec0 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MixinInGameHud.java @@ -5,37 +5,42 @@ package heckerpowered.matrix.mixin; +import com.mojang.blaze3d.pipeline.RenderPipeline; import heckerpowered.matrix.Matrix; import heckerpowered.matrix.client.MatrixHud; import heckerpowered.matrix.common.effect.ModMobEffects; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.util.Identifier; -import org.joml.Matrix4f; -import org.joml.Matrix4fStack; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.Hud; +import net.minecraft.resources.Identifier; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(InGameHud.class) +/** + * 26.2: InGameHud became the extract-based {@link Hud}; renderHeart/renderCrosshair are now + * extractHeart/extractCrosshair, HeartType.getTexture is getSprite, and the crosshair is + * positioned directly through blitSprite's x/y (no pose translate), so the former + * Matrix4fStack.translate redirect is folded into the blitSprite redirect. + */ +@Mixin(Hud.class) class MixinInGameHud { private MixinInGameHud() { } - @Inject(method = "renderMainHud", at = @At("HEAD")) - private void renderMainHud(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + @Inject(method = "extractRenderState", at = @At("HEAD")) + private void extractRenderState(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { // UIBlurShader.startUIOverlayDrawing(context, tickCounter.getTickDelta(false)); } - @Redirect(method = "drawHeart", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud$HeartType;getTexture(ZZZ)Lnet/minecraft/util/Identifier;")) - private Identifier getTexture(InGameHud.HeartType instance, boolean hardcore, boolean half, boolean blinking) { - final var minecraft = MinecraftClient.getInstance(); + @Redirect(method = "extractHeart", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Hud$HeartType;getSprite(ZZZ)Lnet/minecraft/resources/Identifier;")) + private Identifier getSprite(Hud.HeartType instance, boolean hardcore, boolean half, boolean blinking) { + final var minecraft = Minecraft.getInstance(); final var player = minecraft.player; - if (instance == InGameHud.HeartType.NORMAL && player != null && player.hasStatusEffect(ModMobEffects.getBloodPactEffect())) { + if (instance == Hud.HeartType.NORMAL && player != null && player.hasEffect(ModMobEffects.INSTANCE.getBloodPact())) { if (half) { return blinking ? Matrix.identifier("hud/heart/half_blinking") : Matrix.identifier("hud/heart/half"); } else { @@ -43,22 +48,16 @@ private Identifier getTexture(InGameHud.HeartType instance, boolean hardcore, bo } } - return instance.getTexture(hardcore, half, blinking); - } - - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;translate(FFF)Lorg/joml/Matrix4f;", remap = false)) - private Matrix4f translate(Matrix4fStack instance, float x, float y, float z) { - final var translatedCrosshairPosition = MatrixHud.translateCrosshairPosition(x, y); - return instance.translate(translatedCrosshairPosition.x, translatedCrosshairPosition.y, z); + return instance.getSprite(hardcore, half, blinking); } - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) - private void translate(DrawContext instance, Identifier texture, int x, int y, int width, int height) { + @Redirect(method = "extractCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V")) + private void translateCrosshair(GuiGraphicsExtractor instance, RenderPipeline pipeline, Identifier texture, int x, int y, int width, int height) { if (width != 15 || height != 15) { - instance.drawGuiTexture(texture, x, y, width, height); + instance.blitSprite(pipeline, texture, x, y, width, height); return; } final var translatedCrosshairPosition = MatrixHud.translateCrosshairPosition(x, y); - instance.drawGuiTexture(texture, (int) translatedCrosshairPosition.x, (int) translatedCrosshairPosition.y, width, height); + instance.blitSprite(pipeline, texture, (int) translatedCrosshairPosition.x, (int) translatedCrosshairPosition.y, width, height); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MobAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/MobAccessor.java new file mode 100644 index 00000000..337f09d5 --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/MobAccessor.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.goal.GoalSelector; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** See {@link TickRateManagerAccessor} for why this is an accessor, not a tweaker widening. */ +@Mixin(Mob.class) +public interface MobAccessor { + @Accessor("targetSelector") + GoalSelector matrix$getTargetSelector(); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/MouseMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/MouseMixin.java index 077db336..1c850a24 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/MouseMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/MouseMixin.java @@ -7,21 +7,28 @@ import heckerpowered.matrix.client.MatrixHud; import heckerpowered.matrix.client.core.AimAssist; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.Mouse; +import net.minecraft.client.Minecraft; +import net.minecraft.client.MouseHandler; +import net.minecraft.client.input.MouseButtonInfo; 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.CallbackInfo; -@Mixin(Mouse.class) +/** + * 26.2: onMouseScroll→onScroll, onMouseButton→onButton (button/modifiers wrapped in + * MouseButtonInfo), updateMouse(timeDelta)→handleAccumulatedMovement() (no time argument — + * the frame partial tick is read from the delta tracker instead, which is what the old + * timeDelta fed into AimAssist's view-rotation interpolation). + */ +@Mixin(MouseHandler.class) class MouseMixin { - @Inject(method = "onMouseScroll", at = @At("HEAD"), cancellable = true) + @Inject(method = "onScroll", at = @At("HEAD"), cancellable = true) private void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) { if (!MatrixHud.shouldRenderHud()) { return; } - final var minecraft = MinecraftClient.getInstance(); + final var minecraft = Minecraft.getInstance(); if (vertical < 0) { if (MatrixHud.isPressingRightMouseButton) { MatrixHud.previousZoomLevel(); @@ -41,16 +48,23 @@ private void onMouseScroll(long window, double horizontal, double vertical, Call } } - @Inject(method = "updateMouse", at = @At("HEAD"), cancellable = true) - private void updateMouse(double timeDelta, CallbackInfo ci) { + @Inject(method = "handleAccumulatedMovement", at = @At("HEAD"), cancellable = true) + private void updateMouse(CallbackInfo ci) { + final var minecraft = Minecraft.getInstance(); + // The 1.21 updateMouse hook only ever ran with a player present; 26.2 calls + // handleAccumulatedMovement unconditionally (main menu included), so guard here. + if (minecraft.player == null) { + return; + } + final var timeDelta = minecraft.getDeltaTracker().getGameTimeDeltaPartialTick(true); if (AimAssist.onMouseUpdate(timeDelta)) { ci.cancel(); } } - @Inject(method = "onMouseButton", at = @At("HEAD"), cancellable = true) - private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { - if (MatrixHud.onMouseButton(window, button, action, mods)) { + @Inject(method = "onButton", at = @At("HEAD"), cancellable = true) + private void onMouseButton(long window, MouseButtonInfo info, int action, CallbackInfo ci) { + if (MatrixHud.onMouseButton(window, info.button(), action, info.modifiers())) { ci.cancel(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/PlayerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/PlayerMixin.java index 04604722..d3d53239 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/PlayerMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/PlayerMixin.java @@ -7,6 +7,7 @@ import com.llamalad7.mixinextras.expression.Definition; import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef; @@ -17,7 +18,9 @@ import heckerpowered.matrix.common.entity.rule.LivingDeathContext; import heckerpowered.matrix.common.item.WardenChestplateItem; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.*; @@ -26,6 +29,20 @@ import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; +/** + * 26.2: {@code Player#applyDamage} no longer exists. The armor/magic-absorption and + * exhaustion logic it used to hold is now inlined directly into {@code Player#actuallyHurt} + * (a full override that does not delegate to {@link net.minecraft.world.entity.LivingEntity#actuallyHurt}, + * so {@code LivingEntityMixin} does not observe player damage). The realization/outcome/ + * settlement pipeline that used to run in {@code applyDamage} is re-anchored there. + *

+ * {@code Player#attack} was also decomposed: the sprint/critical/sweep booleans are still + * computed inline, but the sprint-reset and knockback-velocity writes moved into + * {@code causeExtraKnockback}, and the damage-indicator particle spawn moved into + * {@code damageStatsAndHearts}. The critical/sweep-attack flags are now sourced from the + * private helper methods {@code canCriticalAttack}/{@code isSweepAttack}, which are + * overridden directly via {@link ModifyReturnValue} instead of brittle local-variable ordinals. + */ @Mixin(Player.class) class PlayerMixin { private PlayerMixin() { @@ -51,7 +68,7 @@ private void die(DamageSource source, CallbackInfo ci, @Local(argsOnly = true, n } @ModifyVariable( - method = "applyDamage", + method = "actuallyHurt", at = @At("HEAD"), argsOnly = true ) @@ -63,23 +80,23 @@ private DamageSource unwrapSource(DamageSource source, @Share(value = "rawDamage return source; } - @ModifyArg(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;spawnParticles(Lnet/minecraft/particle/ParticleEffect;DDDIDDDD)I")) - private int attack(int count) { + @ModifyArg(method = "damageStatsAndHearts", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;sendParticles(Lnet/minecraft/core/particles/ParticleOptions;DDDIDDDD)I"), index = 4) + private int damageStatsAndHearts(int count) { return Math.min(count, 512); } @SuppressWarnings("DuplicatedCode") - @Definition(id = "modifyAppliedDamage", method = "Lnet/minecraft/entity/player/PlayerEntity;modifyAppliedDamage(Lnet/minecraft/entity/damage/DamageSource;F)F") - @Expression("? = ?.modifyAppliedDamage(?, ?)") + @Definition(id = "getDamageAfterMagicAbsorb", method = "Lnet/minecraft/world/entity/player/Player;getDamageAfterMagicAbsorb(Lnet/minecraft/world/damagesource/DamageSource;F)F") + @Expression("? = ?.getDamageAfterMagicAbsorb(?, ?)") @ModifyVariable( - method = "applyDamage", + method = "actuallyHurt", at = @At(value = "MIXINEXTRAS:EXPRESSION", shift = At.Shift.AFTER), argsOnly = true) - private float applyDamage( + private float actuallyHurt( float amount, @Local(argsOnly = true) DamageSource source, @Share(value = "rawDamage", namespace = Matrix.MOD_ID) LocalFloatRef rawDamageReference) { - final var self = (PlayerEntity) (Object) this; + final var self = self(); final var rawDamage = rawDamageReference.get(); final var realizationContext = new DamageRealizationContext(self, source, rawDamage, amount); DamagePipeline.realization(realizationContext); @@ -95,44 +112,44 @@ private float applyDamage( return settlementContext.getRemainingDamage(); } - @Inject(method = "getAttackCooldownProgress", at = @At(value = "HEAD"), cancellable = true) - private void getAttackCooldownProgress(float baseTime, CallbackInfoReturnable cir) { + @Inject(method = "getAttackStrengthScale", at = @At(value = "HEAD"), cancellable = true) + private void getAttackStrengthScale(float baseTime, CallbackInfoReturnable cir) { if (WardenChestplateItem.isAngered(self()) || isPhaseWalking(self())) { cir.setReturnValue(1.0F); } } - @ModifyVariable(method = "attack", at = @At(value = "LOAD"), ordinal = 2) - private boolean modifyAttackCritical(boolean isCritical) { + @ModifyReturnValue(method = "canCriticalAttack", at = @At("RETURN")) + private boolean canCriticalAttack(boolean isCritical) { if (WardenChestplateItem.isAngered(self()) || isPhaseWalking(self())) { return true; } return isCritical; } - @ModifyVariable(method = "attack", at = @At(value = "LOAD"), ordinal = 3) - private boolean modifyAttackSweep(boolean canSweep) { + @ModifyReturnValue(method = "isSweepAttack", at = @At("RETURN")) + private boolean isSweepAttack(boolean canSweep) { if (WardenChestplateItem.isAngered(self()) || isPhaseWalking(self())) { return true; } return canSweep; } - @Redirect(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;setSprinting(Z)V")) - private void setSprinting(PlayerEntity player, boolean sprinting) { - if (WardenChestplateItem.isAngered(player)) { + @Redirect(method = "causeExtraKnockback", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setSprinting(Z)V")) + private void setSprinting(Player entity, boolean sprinting) { + if (entity == self() && WardenChestplateItem.isAngered(self())) { return; } - player.setSprinting(sprinting); + entity.setSprinting(sprinting); } - @Redirect(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;setVelocity(Lnet/minecraft/util/math/Vec3d;)V")) - private void setVelocity(PlayerEntity player, Vec3d velocity) { - if (player == self() && WardenChestplateItem.isAngered(player)) { + @Redirect(method = "causeExtraKnockback", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;setDeltaMovement(Lnet/minecraft/world/phys/Vec3;)V")) + private void setDeltaMovement(Player entity, Vec3 velocity) { + if (entity == self() && WardenChestplateItem.isAngered(self())) { return; } - player.setVelocity(velocity); + entity.setDeltaMovement(velocity); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/ServerCommonNetworkHandlerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/ServerCommonNetworkHandlerMixin.java index 8171396e..b2c3a7d0 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/ServerCommonNetworkHandlerMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/ServerCommonNetworkHandlerMixin.java @@ -5,15 +5,15 @@ package heckerpowered.matrix.mixin; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketCallbacks; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.s2c.play.EntityS2CPacket; -import net.minecraft.network.packet.s2c.play.EntitySetHeadYawS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; -import net.minecraft.server.network.PlayerAssociatedNetworkHandler; -import net.minecraft.server.network.ServerCommonNetworkHandler; +import io.netty.channel.ChannelFutureListener; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -23,34 +23,39 @@ import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; -@Mixin(ServerCommonNetworkHandler.class) +/** + * 26.2: {@code Entity#getWorld()} (Yarn) is now {@code Entity#level()}. The {@code send} + * overload with a callback no longer takes {@code PacketSendListener} (now a static-helper-only + * class) — it takes {@code io.netty.channel.ChannelFutureListener} directly. + */ +@Mixin(ServerCommonPacketListenerImpl.class) class ServerCommonNetworkHandlerMixin { @Unique @Nullable private Entity getEntity(Packet packet) { - if (!(this instanceof final PlayerAssociatedNetworkHandler handler)) { + if (!(this instanceof final ServerPlayerConnection handler)) { return null; } final var player = handler.getPlayer(); - final var world = player.getWorld(); - if (packet instanceof final EntityS2CPacket entityPacket) { + final var world = player.level(); + if (packet instanceof final ClientboundMoveEntityPacket entityPacket) { return entityPacket.getEntity(world); } - if (packet instanceof final EntitySetHeadYawS2CPacket entityPacket) { + if (packet instanceof final ClientboundRotateHeadPacket entityPacket) { return entityPacket.getEntity(world); } - if (packet instanceof final EntityTrackerUpdateS2CPacket entityPacket) { - return world.getEntityById(entityPacket.id()); + if (packet instanceof final ClientboundSetEntityDataPacket entityPacket) { + return world.getEntity(entityPacket.id()); } return null; } - @Inject(method = "send", at = @At("HEAD"), cancellable = true) - private void send(Packet packet, @Nullable PacketCallbacks callbacks, CallbackInfo ci) { + @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lio/netty/channel/ChannelFutureListener;)V", at = @At("HEAD"), cancellable = true) + private void send(Packet packet, @Nullable ChannelFutureListener callbacks, CallbackInfo ci) { final var targetEntity = getEntity(packet); - if (targetEntity instanceof final PlayerEntity player && isPhaseWalking(player)) { + if (targetEntity instanceof final Player player && isPhaseWalking(player)) { ci.cancel(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/ServerPlayNetworkHandlerMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/ServerPlayNetworkHandlerMixin.java index e85193c1..d7086cc9 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/ServerPlayNetworkHandlerMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/ServerPlayNetworkHandlerMixin.java @@ -6,9 +6,9 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.item.WardenChestplateItem; -import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.server.level.ServerPlayer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -17,23 +17,25 @@ import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; -@Mixin(ServerPlayNetworkHandler.class) +@Mixin(ServerGamePacketListenerImpl.class) class ServerPlayNetworkHandlerMixin { @Shadow - public ServerPlayerEntity player; + public ServerPlayer player; private ServerPlayNetworkHandlerMixin() { } - @Inject(method = "onPlayerInteractItem", at = @At("TAIL")) - private void onPlayerInteractItem(PlayerInteractItemC2SPacket packet, CallbackInfo ci) { + @Inject(method = "handleUseItem", at = @At("TAIL")) + private void onPlayerInteractItem(ServerboundUseItemPacket packet, CallbackInfo ci) { final var instantUse = WardenChestplateItem.isAngered(player) || isPhaseWalking(player); if (instantUse && player.isUsingItem()) { final var activeItem = player.getActiveItem(); - player.itemUseTimeLeft = 0; + // Cross-class write of a protected LivingEntity field: must go through the + // accessor — the class-tweaker widening does not apply in production. + ((LivingEntityAccessor) player).matrix$setUseItemRemaining(0); player.stopUsingItem(); - if (!activeItem.isUsedOnRelease()) { - activeItem.finishUsing(player.getWorld(), player); + if (!activeItem.useOnRelease()) { + activeItem.finishUsingItem(player.level(), player); } } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/SonicBoomTaskMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/SonicBoomTaskMixin.java index 1f71ec88..c5799840 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/SonicBoomTaskMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/SonicBoomTaskMixin.java @@ -6,40 +6,47 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.effect.ManaOverloadEffect; -import net.minecraft.entity.ai.brain.task.SonicBoomTask; -import net.minecraft.entity.mob.WardenEntity; -import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.entity.ai.behavior.warden.SonicBoom; +import net.minecraft.world.entity.monster.warden.Warden; +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.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(SonicBoomTask.class) +/** + * 26.2: the old {@code Task} API ({@code shouldRun}/{@code shouldKeepRunning}/ + * {@code run}/{@code keepRunning}) was replaced by {@code Behavior}'s + * {@code checkExtraStartConditions}/{@code canStillUse}/{@code start}/{@code tick}. Each has a + * generic {@code LivingEntity}-typed bridge overload, so the {@code Warden}-typed descriptor is + * specified explicitly to target the real (non-bridge) method. + */ +@Mixin(SonicBoom.class) class SonicBoomTaskMixin { - @Inject(method = "shouldRun(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/mob/WardenEntity;)Z", at = @At("HEAD"), cancellable = true) - private void shouldRun(ServerWorld serverWorld, WardenEntity wardenEntity, CallbackInfoReturnable cir) { + @Inject(method = "checkExtraStartConditions(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/monster/warden/Warden;)Z", at = @At("HEAD"), cancellable = true) + private void checkExtraStartConditions(ServerLevel serverWorld, Warden wardenEntity, CallbackInfoReturnable cir) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(wardenEntity)) { cir.setReturnValue(false); } } - @Inject(method = "shouldKeepRunning(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/mob/WardenEntity;J)Z", at = @At("HEAD"), cancellable = true) - private void shouldKeepRunning(ServerWorld serverWorld, WardenEntity wardenEntity, long l, CallbackInfoReturnable cir) { + @Inject(method = "canStillUse(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/monster/warden/Warden;J)Z", at = @At("HEAD"), cancellable = true) + private void canStillUse(ServerLevel serverWorld, Warden wardenEntity, long l, CallbackInfoReturnable cir) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(wardenEntity)) { cir.setReturnValue(false); } } - @Inject(method = "run(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/mob/WardenEntity;J)V", at = @At("HEAD"), cancellable = true) - private void run(ServerWorld serverWorld, WardenEntity wardenEntity, long l, CallbackInfo ci) { + @Inject(method = "start(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/monster/warden/Warden;J)V", at = @At("HEAD"), cancellable = true) + private void start(ServerLevel serverWorld, Warden wardenEntity, long l, CallbackInfo ci) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(wardenEntity)) { ci.cancel(); } } - @Inject(method = "keepRunning(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/mob/WardenEntity;J)V", at = @At("HEAD"), cancellable = true) - private void keepRunning(ServerWorld serverWorld, WardenEntity wardenEntity, long l, CallbackInfo ci) { + @Inject(method = "tick(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/monster/warden/Warden;J)V", at = @At("HEAD"), cancellable = true) + private void tick(ServerLevel serverWorld, Warden wardenEntity, long l, CallbackInfo ci) { if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(wardenEntity)) { ci.cancel(); } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/TargetPredicateMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/TargetPredicateMixin.java index d912f25c..f095c95a 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/TargetPredicateMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/TargetPredicateMixin.java @@ -5,9 +5,10 @@ package heckerpowered.matrix.mixin; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.TargetPredicate; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.targeting.TargetingConditions; +import net.minecraft.world.entity.player.Player; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -15,11 +16,15 @@ import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; -@Mixin(TargetPredicate.class) +/** + * 26.2: {@code TargetPredicate#test(LivingEntity, LivingEntity)} (Yarn) gained a leading + * {@code ServerLevel} parameter: {@code TargetingConditions#test(ServerLevel, LivingEntity, LivingEntity)}. + */ +@Mixin(TargetingConditions.class) class TargetPredicateMixin { @Inject(method = "test", at = @At("HEAD"), cancellable = true) - private void test(LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable cir) { - if (targetEntity instanceof final PlayerEntity player && isPhaseWalking(player)) { + private void test(ServerLevel level, LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable cir) { + if (targetEntity instanceof final Player player && isPhaseWalking(player)) { cir.setReturnValue(false); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/TickRateManagerAccessor.java b/common/src/main/java/heckerpowered/matrix/mixin/TickRateManagerAccessor.java new file mode 100644 index 00000000..9146f38b --- /dev/null +++ b/common/src/main/java/heckerpowered/matrix/mixin/TickRateManagerAccessor.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.mixin; + +import net.minecraft.world.TickRateManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Mixin accessor instead of a class-tweaker field widening: in production the tweaker's + * interface injections apply but the accessible-field entries did NOT reach this class + * (IllegalAccessError on first slow-time engage), while mixin accessors behave identically + * in dev and production. + */ +@Mixin(TickRateManager.class) +public interface TickRateManagerAccessor { + @Accessor("nanosecondsPerTick") + long matrix$getNanosecondsPerTick(); + + @Accessor("nanosecondsPerTick") + void matrix$setNanosecondsPerTick(long value); +} diff --git a/common/src/main/java/heckerpowered/matrix/mixin/TridentEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/TridentEntityMixin.java index 50f1197b..f8c283ad 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/TridentEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/TridentEntityMixin.java @@ -5,12 +5,12 @@ package heckerpowered.matrix.mixin; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.projectile.PersistentProjectileEntity; -import net.minecraft.entity.projectile.TridentEntity; -import net.minecraft.world.World; +import net.minecraft.world.entity.EntityType; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.arrow.AbstractArrow; +import net.minecraft.world.entity.projectile.arrow.ThrownTrident; +import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,31 +20,37 @@ import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; -@Mixin(TridentEntity.class) -abstract class TridentEntityMixin extends PersistentProjectileEntity { +/** + * 26.2: the loyalty-level accessor field is {@code ID_LOYALTY} (was {@code LOYALTY}), read via + * inherited {@code Entity#entityData} (was {@code dataTracker}). {@code isNoClip()} is now + * {@code AbstractArrow#isNoPhysics()}, {@code asItemStack()} is {@code ThrownTrident#getWeaponItem()}, + * and {@code PlayerInventory#insertStack} is {@code Inventory#add}. + */ +@Mixin(ThrownTrident.class) +abstract class TridentEntityMixin extends AbstractArrow { @Shadow @Final - private static TrackedData LOYALTY; + private static EntityDataAccessor ID_LOYALTY; @Shadow private boolean dealtDamage; - TridentEntityMixin(EntityType entityType, World world) { + TridentEntityMixin(EntityType entityType, Level world) { super(entityType, world); } @Inject(method = "tick", at = @At("HEAD")) private void tick(CallbackInfo ci) { final var owner = getOwner(); - if (!(owner instanceof final PlayerEntity player)) { + if (!(owner instanceof final Player player)) { return; } if (!isPhaseWalking(player)) { return; } - int i = this.dataTracker.get(LOYALTY); - if (i > 0 && (dealtDamage || isNoClip())) { - player.getInventory().insertStack(asItemStack()); + int i = this.entityData.get(ID_LOYALTY); + if (i > 0 && (dealtDamage || isNoPhysics())) { + player.getInventory().add(((ThrownTrident) (Object) this).getWeaponItem()); discard(); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/TridentItemMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/TridentItemMixin.java index 02c1180e..66847dcb 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/TridentItemMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/TridentItemMixin.java @@ -5,27 +5,42 @@ package heckerpowered.matrix.mixin; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.projectile.TridentEntity; -import net.minecraft.item.TridentItem; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.TridentItem; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; import static heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking; +/** + * 26.2: {@code TridentItem#onStoppedUsing} (Yarn) is now {@code releaseUsing}, and the plain + * (non-Riptide) throw no longer builds a {@code ThrownTrident} first and then calls + * {@code setVelocity(Entity, F,F,F,F,F)} on it — it constructs-and-shoots atomically via the + * static factory {@link net.minecraft.world.entity.projectile.Projectile#spawnProjectileFromRotation} + * (args: factory, level, stack, shooter, pitch=0, velocity=2.5, divergence=1). The old + * {@code speed} doubling on phase-walking shooters is re-anchored to the {@code velocity} arg + * of that call, keyed off the {@code shooter} arg instead of a redirect receiver. + */ @Mixin(TridentItem.class) abstract class TridentItemMixin { TridentItemMixin() { } - @Redirect(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/TridentEntity;setVelocity(Lnet/minecraft/entity/Entity;FFFFF)V")) - private void setVelocity(TridentEntity trident, Entity shooter, float pitch, float yaw, float roll, float speed, float divergence) { - if (shooter instanceof final PlayerEntity player && isPhaseWalking(player)) { - speed *= 2.0F; + @ModifyArgs( + method = "releaseUsing", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/projectile/Projectile;spawnProjectileFromRotation(Lnet/minecraft/world/entity/projectile/Projectile$ProjectileFactory;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;FFF)Lnet/minecraft/world/entity/projectile/Projectile;" + ) + ) + private void spawnProjectileFromRotation(Args args) { + final LivingEntity shooter = args.get(3); + if (shooter instanceof final Player player && isPhaseWalking(player)) { + final float velocity = args.get(5); + args.set(5, velocity * 2.0F); } - - trident.setVelocity(shooter, pitch, yaw, roll, speed, divergence); } } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/WitchEntityMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/WitchEntityMixin.java index 9dada033..b30ff26c 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/WitchEntityMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/WitchEntityMixin.java @@ -6,18 +6,22 @@ package heckerpowered.matrix.mixin; import heckerpowered.matrix.common.effect.ManaOverloadEffect; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.mob.WitchEntity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Witch; 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.CallbackInfo; -@Mixin(WitchEntity.class) +/** + * 26.2: {@code WitchEntity#shootAt} (Yarn) is now {@code Witch#performRangedAttack} + * (the {@code RangedAttackMob} interface method). + */ +@Mixin(Witch.class) class WitchEntityMixin { - @Inject(method = "shootAt", at = @At("HEAD"), cancellable = true) - private void shootAt(LivingEntity target, float pullProgress, CallbackInfo ci) { - final var self = (WitchEntity) (Object) this; + @Inject(method = "performRangedAttack", at = @At("HEAD"), cancellable = true) + private void performRangedAttack(LivingEntity target, float pullProgress, CallbackInfo ci) { + final var self = (Witch) (Object) this; if (ManaOverloadEffect.INSTANCE.isMagicAbilityDisabled(self)) { ci.cancel(); } diff --git a/common/src/main/java/heckerpowered/matrix/mixin/WorldRendererMixin.java b/common/src/main/java/heckerpowered/matrix/mixin/WorldRendererMixin.java index 3b89e62d..e3548a7f 100644 --- a/common/src/main/java/heckerpowered/matrix/mixin/WorldRendererMixin.java +++ b/common/src/main/java/heckerpowered/matrix/mixin/WorldRendererMixin.java @@ -5,28 +5,81 @@ package heckerpowered.matrix.mixin; -import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.resource.ResourceHandle; import heckerpowered.matrix.client.render.ScreenEffectRenderer; -import net.minecraft.client.render.*; -import org.joml.Matrix4f; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher.PreparedFrame; +import net.minecraft.client.renderer.state.level.LevelRenderState; +import net.minecraft.util.profiling.ProfilerFiller; 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.CallbackInfo; -@Mixin(WorldRenderer.class) +/** + * 26.2: {@code WorldRenderer} (Yarn) / {@code LevelRenderer} (Mojang) no longer renders + * entities through a single linear {@code render} method with a shared immediate + * {@link net.minecraft.client.renderer.MultiBufferSource.BufferSource}. Entity/terrain + * submission now happens inside the frame-graph pass built by {@code addMainPass}, whose + * body is compiled into the synthetic lambda {@code lambda$addMainPass$0}. Solid entities are + * drawn during {@link PreparedFrame#executeSolid()} and translucent-after-terrain entities + * during {@link PreparedFrame#executeTranslucentAfterTerrain()}, so the begin/end hooks are + * re-anchored immediately before/after those calls to preserve the original bracketing of + * {@link ScreenEffectRenderer#beginRenderEntity()}/{@link ScreenEffectRenderer#endRenderEntity()} + * around entity rendering. + */ +@Mixin(LevelRenderer.class) class WorldRendererMixin { private WorldRendererMixin() { } - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/BufferBuilderStorage;getEntityVertexConsumers()Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;", shift = At.Shift.AFTER)) - private void beginRenderEntity(RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2, CallbackInfo ci) { + @Inject( + method = "lambda$addMainPass$0", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/feature/FeatureRenderDispatcher$PreparedFrame;executeSolid()V", + shift = At.Shift.BEFORE + ) + ) + private void beginRenderEntity( + GpuBufferSlice gpuBufferSlice, + LevelRenderState levelRenderState, + ProfilerFiller profiler, + ChunkSectionsToRender sectionsToRender, + ResourceHandle resourceHandle, + PreparedFrame preparedFrame, + ResourceHandle resourceHandle2, + ResourceHandle resourceHandle3, + ResourceHandle resourceHandle4, + ResourceHandle resourceHandle5, + CallbackInfo ci + ) { ScreenEffectRenderer.beginRenderEntity(); } - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;draw(Lnet/minecraft/client/render/RenderLayer;)V", shift = At.Shift.AFTER, ordinal = 3)) - private void endRenderEntity(RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2, CallbackInfo ci, @Local LocalRef immediate) { + @Inject( + method = "lambda$addMainPass$0", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/feature/FeatureRenderDispatcher$PreparedFrame;executeTranslucentAfterTerrain()V", + shift = At.Shift.AFTER + ) + ) + private void endRenderEntity( + GpuBufferSlice gpuBufferSlice, + LevelRenderState levelRenderState, + ProfilerFiller profiler, + ChunkSectionsToRender sectionsToRender, + ResourceHandle resourceHandle, + PreparedFrame preparedFrame, + ResourceHandle resourceHandle2, + ResourceHandle resourceHandle3, + ResourceHandle resourceHandle4, + ResourceHandle resourceHandle5, + CallbackInfo ci + ) { ScreenEffectRenderer.endRenderEntity(); } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt b/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt index 2f05d200..0071ab46 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/Matrix.kt @@ -16,6 +16,7 @@ import heckerpowered.matrix.common.item.ModComponents import heckerpowered.matrix.common.item.ModCreativeTab import heckerpowered.matrix.common.item.ModItems import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.recipe.MatrixRecipeSerializer import net.fabricmc.api.ModInitializer import net.minecraft.resources.Identifier import org.slf4j.Logger @@ -27,6 +28,9 @@ object Matrix : ModInitializer { @JvmField val LOGGER: Logger = LoggerFactory.getLogger("matrix") + @JvmField + var proxy: MatrixCommonProxy = MatrixCommonProxy() + override fun onInitialize() { MatrixServerPlayNetworking.onInitialize() MagicSystem.onInitialize() @@ -39,6 +43,7 @@ object Matrix : ModInitializer { MatrixPotions.onInitialize() ModEntityTypes.onInitialize() MatrixEntityAttributes.onInitialize() + MatrixRecipeSerializer.onInitialize() } @JvmStatic diff --git a/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt b/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt new file mode 100644 index 00000000..8258cc86 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/MatrixCommonProxy.kt @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix + +import heckerpowered.matrix.common.magic.resource.Mana +import heckerpowered.matrix.core.isInfiniteMana +import heckerpowered.matrix.core.mana +import heckerpowered.matrix.core.maxMana +import net.minecraft.world.entity.player.Player + +open class MatrixCommonProxy { + open fun getPlayerMana(player: Player): Mana { + return player.mana + } + + open fun getPlayerMaxMana(player: Player): Mana { + return player.maxMana + } + + open fun isInfiniteMana(player: Player): Boolean { + return player.isInfiniteMana + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/ModDataGenerator.kt b/common/src/main/kotlin/heckerpowered/matrix/ModDataGenerator.kt index 74e55bfe..df1267f4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/ModDataGenerator.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/ModDataGenerator.kt @@ -5,19 +5,27 @@ package heckerpowered.matrix +import heckerpowered.matrix.common.magic.system.Magics import heckerpowered.matrix.data.enchantment.ModEnchantmentGenerator import heckerpowered.matrix.data.language.ModChineseLangProvider import heckerpowered.matrix.data.language.ModEnglishLangProvider import heckerpowered.matrix.data.recipe.ModRecipeProvider +import heckerpowered.matrix.common.tag.MatrixDamageTypes import heckerpowered.matrix.data.tag.ModDamageTypeProvider import heckerpowered.matrix.data.tag.ModItemTagProvider import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator import net.minecraft.core.RegistrySetBuilder import net.minecraft.core.registries.Registries +import net.minecraft.world.damagesource.DamageScaling +import net.minecraft.world.damagesource.DamageType object ModDataGenerator : DataGeneratorEntrypoint { override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { + // The enchantment generator loops over the magic registry (one enchantment per magic); + // make sure it is populated even if the mod initializer did not run first (idempotent). + Magics.onInitialize() + val pack = fabricDataGenerator.createPack() pack.addProvider(::ModChineseLangProvider) @@ -29,6 +37,13 @@ object ModDataGenerator : DataGeneratorEntrypoint { } override fun buildRegistry(registryBuilder: RegistrySetBuilder) { + Magics.onInitialize() registryBuilder.add(Registries.ENCHANTMENT, ModEnchantmentGenerator::bootstrap) + // 26.2: tag providers resolve references against the built registries only, so the + // damage type must be bootstrapped here for ModDamageTypeProvider's bypasses_shield + // entry; values mirror data/matrix/damage_type/magic.json exactly. + registryBuilder.add(Registries.DAMAGE_TYPE) { context -> + context.register(MatrixDamageTypes.magic, DamageType("magic", DamageScaling.NEVER, 0.1F)) + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt index 95f74111..0763402e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClient.kt @@ -9,29 +9,35 @@ import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.network.MatrixClientPlayNetworking import heckerpowered.matrix.client.render.ChannelSequenceRenderer import heckerpowered.matrix.client.render.MatrixRenderSystem +import heckerpowered.matrix.client.render.dump +import heckerpowered.matrix.client.render.mainRenderTarget import heckerpowered.matrix.client.render.ScreenEffectRenderer import heckerpowered.matrix.client.render.entity.DevEntityRenderer import heckerpowered.matrix.client.render.entity.EmptyRenderer import heckerpowered.matrix.client.render.entity.FinderArrowEntityRenderer import heckerpowered.matrix.client.render.entity.MagicLightningEntityRenderer -import heckerpowered.matrix.client.render.item.VortexItemRenderer -import heckerpowered.matrix.client.shader.ShaderStageStore import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.common.entity.ModEntityTypes -import heckerpowered.matrix.common.item.MagicTalismanItem +import heckerpowered.matrix.common.item.getMagics import heckerpowered.matrix.common.magic.core.Magic -import heckerpowered.matrix.common.magic.system.MagicSystem import net.fabricmc.api.ClientModInitializer -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry -import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback -import net.minecraft.client.render.entity.feature.FeatureRendererContext -import net.minecraft.client.render.entity.model.EntityModel -import net.minecraft.entity.LivingEntity +import net.minecraft.client.Minecraft import org.joml.Matrix4f import java.time.Duration +// Restored from pre-migration MatrixClient.kt (accidentally deleted in 53dcdd6); +// same non-null semantics as the original 1.21 definitions. +val minecraft + get() = Minecraft.getInstance()!! + +val world + get() = Minecraft.getInstance().level!! + +val player + get() = Minecraft.getInstance().player!! + val projectionMatrix: Matrix4f get() { // Basic projection calculation: @@ -72,12 +78,19 @@ class MatrixClient : ClientModInitializer { MatrixKeyBindings.onInitialize() registerEntityRenderers() - LivingEntityFeatureRendererRegistrationCallback.EVENT.register { _, entityRenderer, registrationHelper, _ -> - @Suppress("UNCHECKED_CAST") - registrationHelper.register(ChannelSequenceRenderer(entityRenderer as FeatureRendererContext>)) - } + // 26.2: ChannelSequenceRenderer is no longer a per-entity-type RenderLayer registered + // through LivingEntityRenderLayerRegistrationCallback — see the structural-decision + // note at the top of ChannelSequenceRenderer.kt for why (no Fabric API extraction hook + // exists to get the source LivingEntity into an arbitrary LivingEntityRenderState + // without a Mixin). It is now a self-contained HUD overlay; onInitialize() registers + // both its ClientTickEvents animation driver and its HudElementRegistry draw callback. + ChannelSequenceRenderer.onInitialize() + + // 26.2: BuiltinItemRendererRegistry/DynamicItemRenderer (Fabric API) is gone; custom + // item GPU rendering now goes through the data-driven SpecialModelRenderer system + // (item model JSON + registered Unbaked/codec type), which is out of scope for this + // renderer-only port pass. See the TODO(26.2) note at the top of VortexItemRenderer.kt. - BuiltinItemRendererRegistry.INSTANCE.register(MagicTalismanItem, VortexItemRenderer) } private fun registerEntityRenderers() { @@ -91,7 +104,9 @@ class MatrixClient : ClientModInitializer { private var lastNonEmptyMagicList: List? = null fun getPlayerMagics(): List { - val magics = MagicSystem.getMagics(player) + // The old MagicManager/MagicSystem lookup was replaced by the Player.getMagics() + // extension during the magic-system refactor; same enchantment-derived list. + val magics = player.getMagics().toList() if (magics.isNotEmpty()) { this.lastNonEmptyMagicList = magics } @@ -100,8 +115,7 @@ class MatrixClient : ClientModInitializer { @JvmStatic fun onWindowInitialization() { - ShaderStageStore.Default.discoverFiles() - ShaderStageStore.Default.precompileAll() + // 26.2: shader pipelines are compiled by the vanilla ShaderManager on demand } } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt index 37e87cf2..9575a6c1 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixClientProxy.kt @@ -5,14 +5,15 @@ package heckerpowered.matrix.client +import heckerpowered.matrix.MatrixCommonProxy import heckerpowered.matrix.common.magic.resource.Mana import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.world.entity.player.Player +import net.minecraft.server.level.ServerPlayer class MatrixClientProxy : MatrixCommonProxy() { - override fun getPlayerMana(player: PlayerEntity): Mana { - if (player is ServerPlayerEntity) { + override fun getPlayerMana(player: Player): Mana { + if (player is ServerPlayer) { return super.getPlayerMana(player) } if (minecraft.player == null || player != ::player.get()) { @@ -22,8 +23,8 @@ class MatrixClientProxy : MatrixCommonProxy() { return (MatrixHud.mana - MatrixHud.manaUsage).mana } - override fun getPlayerMaxMana(player: PlayerEntity): Mana { - if (player is ServerPlayerEntity) { + override fun getPlayerMaxMana(player: Player): Mana { + if (player is ServerPlayer) { return super.getPlayerMaxMana(player) } if (minecraft.player == null || player != ::player.get()) { @@ -33,8 +34,8 @@ class MatrixClientProxy : MatrixCommonProxy() { return MatrixHud.maxMana.mana } - override fun isInfiniteMana(player: PlayerEntity): Boolean { - if (player is ServerPlayerEntity) { + override fun isInfiniteMana(player: Player): Boolean { + if (player is ServerPlayer) { return super.isInfiniteMana(player) } return false diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt index 420d13e6..4d71ba31 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixHud.kt @@ -5,8 +5,8 @@ package heckerpowered.matrix.client -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.systems.VertexSorter +import com.mojang.blaze3d.pipeline.BlendFunction +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.core.AimAssist import heckerpowered.matrix.client.core.ClientOptions.aimAssistEnabled import heckerpowered.matrix.client.core.ClientOptions.aimAssistFov @@ -16,14 +16,8 @@ import heckerpowered.matrix.client.event.MouseButtonEvent import heckerpowered.matrix.client.render.* import heckerpowered.matrix.client.render.post.BloomEffect import heckerpowered.matrix.client.render.shader.GaussianBlurRenderer -import heckerpowered.matrix.client.render.shader.opacityMask -import heckerpowered.matrix.client.render.state.* -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.CapabilityState -import heckerpowered.matrix.client.render.state.capabilities.CullFaceState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState +import heckerpowered.matrix.client.render.shader.OpacityMaskRenderer import heckerpowered.matrix.client.shader.* -import heckerpowered.matrix.client.shader.component.TransformFeedback import heckerpowered.matrix.client.ui.element.* import heckerpowered.matrix.client.ui.foundation.animation.* import heckerpowered.matrix.common.effect.isBloodPactActive @@ -33,48 +27,52 @@ import heckerpowered.matrix.common.item.LightningChestplate1.isPhaseWalking import heckerpowered.matrix.common.item.WizardHelmet5 import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus import heckerpowered.matrix.common.magic.core.Magic +import heckerpowered.matrix.common.magic.core.MagicAvailability +import heckerpowered.matrix.common.magic.core.MagicAvailableStatus import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.common.magic.core.description import heckerpowered.matrix.common.network.ServerboundActivateBloodPactPayload +import heckerpowered.matrix.common.network.ServerboundBorrowedTimePayload +import heckerpowered.matrix.client.render.gui.DissolveRect +import heckerpowered.matrix.client.render.gui.DissolveRectRenderState +import heckerpowered.matrix.extension.MatrixGuiRenderState +import heckerpowered.matrix.common.network.ServerboundOverclockPayload import heckerpowered.matrix.common.network.ServerboundUseMagicPayload import heckerpowered.matrix.common.persistent.isWizard import heckerpowered.matrix.common.persistent.wizardHelmetStack import heckerpowered.matrix.core.approximatelyEqual import heckerpowered.matrix.core.inverseLerp import heckerpowered.matrix.core.lerp +import heckerpowered.matrix.core.utility.getEntitiesNearSight import heckerpowered.matrix.core.worldToScreen import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.util.InputUtil -import net.minecraft.entity.Entity -import net.minecraft.entity.EquipmentSlot -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.boss.dragon.EnderDragonPart -import net.minecraft.entity.projectile.ProjectileUtil -import net.minecraft.sound.SoundCategory -import net.minecraft.sound.SoundEvents -import net.minecraft.text.Text -import net.minecraft.util.Util -import net.minecraft.util.math.Box -import net.minecraft.util.math.ColorHelper -import net.minecraft.util.math.MathHelper -import net.minecraft.util.math.Vec3d -import net.minecraft.world.RaycastContext +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.DeltaTracker +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiGraphicsExtractor +import com.mojang.blaze3d.platform.InputConstants +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.boss.enderdragon.EnderDragonPart +import net.minecraft.world.entity.projectile.ProjectileUtil +import net.minecraft.sounds.SoundSource +import net.minecraft.sounds.SoundEvents +import net.minecraft.network.chat.Component +import net.minecraft.world.phys.AABB +import net.minecraft.util.ARGB +import net.minecraft.util.Mth +import net.minecraft.world.phys.Vec3 +import net.minecraft.world.level.ClipContext import org.joml.Vector2f import org.lwjgl.glfw.GLFW -import org.lwjgl.opengl.GL15.glDeleteBuffers -import org.lwjgl.opengl.GL30.glDeleteVertexArrays -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryUtil import java.math.BigDecimal import java.math.RoundingMode import java.time.Duration import kotlin.math.abs import kotlin.math.min import kotlin.math.round +import kotlin.math.roundToInt import kotlin.random.Random object MatrixHud { @@ -140,7 +138,7 @@ object MatrixHud { private val healthAnimation = SimpleDoubleAnimation() private val maxHealthAnimation = SimpleDoubleAnimation() private var previousDisplayEntityNameHashCode: Int = 0 - private var displayEntityName: Text = Text.empty() + private var displayEntityName: Component = Component.empty() private var displayEntityNameOpacityAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(150), initValue = 1.0) private var previousCandidateEntities: Int = 0 private var displayCandidateEntities: Int = 0 @@ -159,8 +157,8 @@ object MatrixHud { private val dissolveAnimation = SimpleDoubleAnimation(from = 1.0) private val magicDescriptionChangedAnimation = SimpleDoubleAnimation(initValue = 1.0, duration = Duration.ofMillis(150)) - private var currentDescription: Text = Text.empty() - private var displayDescription: Text = Text.empty() + private var currentDescription: Component = Component.empty() + private var displayDescription: Component = Component.empty() private val descriptionYOffsetAnimation = SimpleDoubleAnimation(duration = Duration.ofMillis(300)) @@ -180,7 +178,11 @@ object MatrixHud { val fovAnimation = SimpleDoubleAnimation(initValue = 1.0) private var fovZoomRatio = .0 - private val hudFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } + // 26.2: no longer private -- StatusHud's progress-ring pass previously drew into this target + // implicitly (it was the bound framebuffer during onHudRender); explicit targets are now + // required, so HUD elements that composite through the blur/bloom chain reference it. + @JvmStatic + val hudFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } private val blurFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } private val emissiveFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } @@ -209,36 +211,46 @@ object MatrixHud { return cachedMagicDisplayData } + // 26.2: post/the_world.fsh is std140-converted -- `layout(std140) uniform MatrixPostUniforms + // { vec4 MatrixPostData0..3; }` with `#define grayscaleIntensity MatrixPostData0.x`, plus a + // `framebuffer` sampler bound to the previous pass output. private val theWorldShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/the_world.fsh", GL_FRAGMENT_SHADER), + "post/the_world.fsh", uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("grayscaleIntensity") { pointer -> - glUniform1f(pointer, grayscaleIntensityAnimation.animatedValue.toFloat()) + UniformProvider("MatrixPostUniforms") { + putVec4(grayscaleIntensityAnimation.animatedValue.toFloat(), 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } - ) + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) } - private val pointSpriteProgram by lazy { - Program( - ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("time") { pointer -> - val timeSeconds = System.nanoTime() / 1_000_000_000.0 - glUniform1f(pointer, timeSeconds.toFloat()) - }), - components = arrayOf( - TransformFeedback( - arrayOf("OutPosition"), - (points.size / 2), - bufferSize = (points.size / 2).toLong() * 4 * 2 - ) - ) - ) - } + // TODO(26.2): the point-sprite program rendered GL_POINTS with GL_PROGRAM_POINT_SIZE through + // a transform-feedback component (see renderPoints below). The dual-backend wrapper API has + // no transform feedback, no point-sprite primitive, and no client vertex-array path, so this + // debug-only effect (never invoked from any live code path) cannot be ported as-is. Kept for + // reference: + // private val pointSpriteProgram by lazy { + // Program( + // ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.vsh", GL_VERTEX_SHADER), + // ResourceShader("/assets/matrix/shaders/point_sprite/point_sprite.fsh", GL_FRAGMENT_SHADER), + // uniforms = arrayOf(UniformProvider("time") { pointer -> + // val timeSeconds = System.nanoTime() / 1_000_000_000.0 + // glUniform1f(pointer, timeSeconds.toFloat()) + // }), + // components = arrayOf( + // TransformFeedback( + // arrayOf("OutPosition"), + // (points.size / 2), + // bufferSize = (points.size / 2).toLong() * 4 * 2 + // ) + // ) + // ) + // } init { easingFunction.easingMode = EasingMode.OUT @@ -328,23 +340,23 @@ object MatrixHud { } private fun processKeyInput() { - if (MatrixKeyBindings.useMagic.wasPressed()) { + if (MatrixKeyBindings.useMagic.consumeClick()) { useCurrentMagic() } - while (MatrixKeyBindings.useMagic.wasPressed()) { + while (MatrixKeyBindings.useMagic.consumeClick()) { useCurrentMagic() } - while (MatrixKeyBindings.nextMagic.wasPressed()) { + while (MatrixKeyBindings.nextMagic.consumeClick()) { nextMagic() } - while (MatrixKeyBindings.previousMagic.wasPressed()) { + while (MatrixKeyBindings.previousMagic.consumeClick()) { previousMagic() } - while (MatrixKeyBindings.overclockMagic.wasPressed()) { - val difference = if (player.isSneaking) { + while (MatrixKeyBindings.overclockMagic.consumeClick()) { + val difference = if (player.isShiftKeyDown) { -0.5 } else { 0.5 @@ -353,11 +365,11 @@ object MatrixHud { 1.0..10.0 ) magicOverclock.currentValue = newOverclock - ClientPlayNetworking.send(OverclockPayload(manaOverclock.currentValue, magicOverclock.currentValue)) + ClientPlayNetworking.send(ServerboundOverclockPayload(manaOverclock.currentValue, magicOverclock.currentValue)) } - while (MatrixKeyBindings.overclockMana.wasPressed()) { - val difference = if (player.isSneaking) { + while (MatrixKeyBindings.overclockMana.consumeClick()) { + val difference = if (player.isShiftKeyDown) { -0.5 } else { 0.5 @@ -367,7 +379,7 @@ object MatrixHud { ) manaOverclock.currentValue = newOverclock ClientPlayNetworking.send( - OverclockPayload( + ServerboundOverclockPayload( manaOverclock.currentValue, magicOverclock.currentValue ) ) @@ -375,7 +387,10 @@ object MatrixHud { } fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) + // 26.2: HudRenderCallback was replaced by HudElementRegistry; still invoked once per rendered frame. + HudElementRegistry.addLast(Matrix.identifier("matrix_hud")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) + } SystemCrashBar.onInitialize() StatusHud.onInitialize() DamageNumberHud.onInitialize() @@ -387,8 +402,9 @@ object MatrixHud { 1.0..10.0 ) manaOverclock.currentValue = newOverclock + // 26.2: see the ServerboundOverclockPayload comment in processKeyInput. ClientPlayNetworking.send( - OverclockPayload( + ServerboundOverclockPayload( manaOverclock.currentValue, magicOverclock.currentValue ) ) @@ -400,8 +416,9 @@ object MatrixHud { 1.0..10.0 ) manaOverclock.currentValue = newOverclock + // 26.2: see the ServerboundOverclockPayload comment in processKeyInput. ClientPlayNetworking.send( - OverclockPayload( + ServerboundOverclockPayload( manaOverclock.currentValue, magicOverclock.currentValue ) ) @@ -413,8 +430,9 @@ object MatrixHud { 1.0..10.0 ) magicOverclock.currentValue = newOverclock + // 26.2: see the ServerboundOverclockPayload comment in processKeyInput. ClientPlayNetworking.send( - OverclockPayload( + ServerboundOverclockPayload( manaOverclock.currentValue, magicOverclock.currentValue ) ) @@ -426,8 +444,9 @@ object MatrixHud { 1.0..10.0 ) magicOverclock.currentValue = newOverclock + // 26.2: see the ServerboundOverclockPayload comment in processKeyInput. ClientPlayNetworking.send( - OverclockPayload( + ServerboundOverclockPayload( manaOverclock.currentValue, magicOverclock.currentValue ) ) @@ -487,7 +506,7 @@ object MatrixHud { val magic = MatrixClient.getPlayerMagics()[index] val target = this.targetedEntity ?: return val calculationContext = MagicCalculationContext.fromEntity(player, target) - if (magic.availableStatus(calculationContext) != LMagicAvailableStatus.AVAILABLE) { + if (!magic.availableStatus(calculationContext).isAvailable) { return } @@ -499,10 +518,10 @@ object MatrixHud { val cost = magic.getCost(calculationContext) val mana = mana - manaUsage if (player.isBloodPactActive && mana < cost) { - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1f) - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_WARDEN_HEARTBEAT, SoundCategory.PLAYERS, 1.0f, 1f) + minecraft.level!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1f) + minecraft.level!!.playSound(player, player.x, player.y, player.z, SoundEvents.WARDEN_HEARTBEAT, SoundSource.PLAYERS, 1.0f, 1f) } else { - minecraft.world!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0f, 1f) + minecraft.level!!.playSound(player, player.x, player.y, player.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1f) } channelMagic(magic, target) @@ -622,11 +641,31 @@ object MatrixHud { private fun getMagicAvailableStatus(magic: Magic): LMagicAvailableStatus { val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) - return magic.availableStatus(calculationContext) + return magic.availableStatus(calculationContext).toLegacyStatus() + } + + /** + * 26.2 port: [Magic.availableStatus] now returns a [MagicAvailability] (set of + * [MagicAvailableStatus] entries) instead of the legacy [LMagicAvailableStatus] enum this + * HUD renders with. Maps the first reported status onto the legacy enum, preserving the old + * per-status color/animation behavior. + */ + private fun MagicAvailability.toLegacyStatus(): LMagicAvailableStatus { + val status = firstOrNull() ?: return LMagicAvailableStatus.AVAILABLE + return when (status.identifier.path) { + MagicAvailableStatus.InsufficientMana.identifier.path -> LMagicAvailableStatus.AVAILABLE_MANA_NOT_ENOUGH + MagicAvailableStatus.TargetImmune.identifier.path -> LMagicAvailableStatus.TARGET_IMMUNE + MagicAvailableStatus.Unavailable.identifier.path -> LMagicAvailableStatus.UNAVAILABLE + MagicAvailableStatus.ChannelQueueFull.identifier.path -> LMagicAvailableStatus.CHANNEL_QUEUE_FULL + MagicAvailableStatus.ChannelQueueLocked.identifier.path -> LMagicAvailableStatus.CHANNEL_QUEUE_LOCKED + MagicAvailableStatus.TargetMissing.identifier.path -> LMagicAvailableStatus.TARGET_MISSING + "sculk_catalyst_is_already_active" -> LMagicAvailableStatus.SCULK_CATALYST_IS_ALREADY_ACTIVE + else -> LMagicAvailableStatus.UNAVAILABLE + } } private fun renderMagicAvailableStatus( - drawContext: DrawContext, + drawContext: GuiGraphicsExtractor, renderer: LegacyMatrixUIRenderer, ) { val status = getMagicAvailableStatus(selectedMagic) @@ -641,7 +680,7 @@ object MatrixHud { private fun updateAimAssist( updateRotation: Boolean, - tickCounter: RenderTickCounter, + tickCounter: DeltaTracker, ) { targetedEntity?.apply { if (aimEntity == null) { @@ -655,20 +694,20 @@ object MatrixHud { } aimEntity?.apply { - val tickDelta = tickCounter.getTickDelta( + val tickDelta = tickCounter.getGameTimeDeltaPartialTick( true ) val x = lerp( - tickDelta.toDouble(), prevX, x + tickDelta.toDouble(), xo, x ) val y = lerp( - tickDelta.toDouble(), prevY, y + tickDelta.toDouble(), yo, y ) val z = lerp( - tickDelta.toDouble(), prevZ, z + tickDelta.toDouble(), zo, z ) AimAssist.lookAt( - Vec3d( + Vec3( x, y - 0.5, z ), tickDelta.toDouble() ) @@ -686,11 +725,11 @@ object MatrixHud { var renderHud = false var useBlur = false - private fun renderOtherHuds(drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun renderOtherHuds(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { renderWitherArmorHud(drawContext, tickCounter) } - private fun onBeginHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun onBeginHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { renderOtherHuds(drawContext, tickCounter) if (!isHudInvisible) { @@ -709,82 +748,75 @@ object MatrixHud { } } - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - StateIsolation.isolate( - FramebufferState(hudFramebuffer), ViewportState(hudFramebuffer), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - onBeginHudRender(drawContext, tickCounter) - renderHud(drawContext, tickCounter) - onEndHudRender(drawContext, tickCounter) - } + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + // 26.2 capture semantics: everything this callback extracts goes into a dedicated GUI + // stratum; GuiRendererMixin renders that stratum into hudFramebuffer at draw time + // (the 1.21 "bind hudFramebuffer while the HUD draws" equivalent) and then invokes + // onHudCaptured() for the blur/shadow/bloom composite back onto the main target. + // Use the extractor's own state instance — the one GuiRenderer will actually render. + val matrixRenderState = drawContext.guiRenderState as MatrixGuiRenderState + matrixRenderState.beginMatrixHudStratum() + onBeginHudRender(drawContext, tickCounter) + renderHud(drawContext, tickCounter) + // Everything extracted past this marker (screens, tooltips, toasts) stays OUT of the + // capture — without it the segment would run to the blur fence and swallow them. + matrixRenderState.endMatrixHudStratum() } - private fun renderCandidateEntities(drawContext: DrawContext, tickCounter: RenderTickCounter) { + /** + * Runs right after GuiRendererMixin clears [hudFramebuffer] and BEFORE the HUD stratum + * renders into it: extraction-time framebuffer passes that must sit under the stratum's + * own draws (the 1.21 in-place ordering) are flushed here. + */ + @JvmStatic + fun onHudCaptureBegin() { + StatusHud.flushPendingRings() + // 1.21 order within the HUD layer: progress rings, then the aim guide lines, then the + // stratum's own panels/text draw over both. + GuideLineRenderer.renderToCapturedHud(hudFramebuffer) + } + + /** + * Runs the 1.21 end-of-HUD composite (backdrop blur, drop shadow, HUD copy, bloom) onto + * the main target. Called by GuiRendererMixin right after the HUD stratum has been + * rendered into [hudFramebuffer] — during the actual GUI render pass, not extraction. + */ + @JvmStatic + fun onHudCaptured() { + onEndHudRender() + } + + private fun renderCandidateEntities(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + // 1.21 drew world-space DEBUG_LINES immediately here; the 26.2 deferred GUI pipeline + // only extracts state, so this now records the line list (endpoints computed with the + // extraction-time partial tick) and GuideLineRenderer draws it at render time from the + // GameRendererMixin.beginRender hook, before the post chain runs over the main target. + GuideLineRenderer.clear() if (!shouldRenderHud()) { return } - val tickDelta = tickCounter.getTickDelta(true) + val tickDelta = tickCounter.getGameTimeDeltaPartialTick(true) - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR) - - val modelViewStack = RenderSystem.getModelViewStack() - modelViewStack.pushMatrix() - modelViewStack.set(viewMatrix) - RenderSystem.applyModelViewMatrix() - RenderSystem.backupProjectionMatrix() - RenderSystem.setProjectionMatrix(projectionMatrix, VertexSorter.BY_DISTANCE) - - var from = player.getLerpedPos(tickDelta).add(.0, player.boundingBox.lengthY / 2, .0)// Vector2d(crosshairX.animatedValue + 7.5, crosshairY.animatedValue + 7.5) + var from = player.getPosition(tickDelta).add(.0, player.boundingBox.ysize / 2, .0)// Vector2d(crosshairX.animatedValue + 7.5, crosshairY.animatedValue + 7.5) val targetedEntity = this.targetedEntity if (targetedEntity != null) { - val to = targetedEntity.getLerpedPos(tickDelta).add(.0, targetedEntity.boundingBox.lengthY / 2, .0) - val color = ColorHelper.Argb.getArgb(255, 25, 255, 25) - buffer.vertex(from.x.toFloat(), from.y.toFloat(), from.z.toFloat()) - .color(color) - buffer.vertex(to.x.toFloat(), to.y.toFloat(), to.z.toFloat()) - .color(color) + val to = targetedEntity.getPosition(tickDelta).add(.0, targetedEntity.boundingBox.ysize / 2, .0) + GuideLineRenderer.addLine(from, to, ARGB.color(255, 25, 255, 25)) from = to } for (candidateEntity in candidateAimAssistEntities) { - val targetPosition = candidateEntity.getLerpedPos(tickDelta).add(.0, candidateEntity.boundingBox.lengthY / 2, .0) + val targetPosition = candidateEntity.getPosition(tickDelta).add(.0, candidateEntity.boundingBox.ysize / 2, .0) - val color = ColorHelper.Argb.getArgb(255, 255, 25, 25) - buffer.vertex(from.x.toFloat(), from.y.toFloat(), from.z.toFloat()) - .color(color) - buffer.vertex(targetPosition.x.toFloat(), targetPosition.y.toFloat(), targetPosition.z.toFloat()) - .color(color) + GuideLineRenderer.addLine(from, targetPosition, ARGB.color(255, 255, 25, 25)) from = targetPosition } - - StateIsolation.isolate( - LineWidthState(1.0F), - BlendState(false), - BlendFuncSeparateState(), - DepthTestState(false), - CullFaceState(false), - ShaderProgramState(GameRenderer::getPositionColorProgram), - CapabilityState(GL_MULTISAMPLE, true) - ) { - val mul = 8.0F - RenderSystem.setShaderColor(mul, mul, mul, 1.0F) - buffer.endNullable()?.let { - BufferRenderer.drawWithGlobalProgram(it) - } - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - } - - RenderSystem.restoreProjectionMatrix() - modelViewStack.popMatrix() - RenderSystem.applyModelViewMatrix() } - private fun renderWitherArmorHud(drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun renderWitherArmorHud(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { StatusHud.onHudRender(drawContext, tickCounter) } - private fun renderHud(drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun renderHud(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { if (selectedIndex - 1 !in MatrixClient.getPlayerMagics().indices || previousIndex - 1 !in MatrixClient.getPlayerMagics().indices ) { @@ -792,7 +824,7 @@ object MatrixHud { previousIndex = 1 } - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) + val renderer = LegacyMatrixUIRenderer(drawContext) renderCandidateEntities(drawContext, tickCounter) checkVisibilityChanges() warp() @@ -805,7 +837,7 @@ object MatrixHud { targetedEntity = null } fovAnimation.value = 1.0 - fovZoomRatio - lastNanos = Util.getMeasuringTimeNano() + lastNanos = System.nanoTime() // magicShownAnimationClock.let { // it.from = magicShownAnimation.animatedValue @@ -847,7 +879,7 @@ object MatrixHud { } } - private fun onEndHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun onEndHudRender() { if (!renderHud) { return } @@ -855,36 +887,34 @@ object MatrixHud { if (useBlur) { val strength = magicShownOpacityAnimation.animatedValue.toFloat() GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(strength, maxSigma = 8F) - BlurRenderer.renderGaussianBlur(minecraft.framebuffer) + BlurRenderer.renderGaussianBlur(minecraft.mainRenderTarget) dropHudShadow() - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - renderHudBlur() - } + // Previously drawn while minecraft's framebuffer was bound with + // (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) blending; the target/blend now travel with the + // copy calls inside renderHudBlur. + renderHudBlur() } else { - StateIsolation.isolate( - FramebufferState(blurFramebuffer), ViewportState(blurFramebuffer), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - PostProcessRenderer.copyFramebuffer(hudFramebuffer, blurFramebuffer, false) - PostProcessRenderer.copyFramebuffer(hudFramebuffer, minecraft.framebuffer, false) - } + // Previously bound blurFramebuffer with (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) blending; + // copyFramebuffer(from, to, disableBlend = false) used the wrapper-set blend func. + PostProcessRenderer.copyFramebuffer(hudFramebuffer, blurFramebuffer, BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA) + PostProcessRenderer.copyFramebuffer(hudFramebuffer, minecraft.mainRenderTarget, BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA) } BloomEffect.brightnessPassFramebuffer = blurFramebuffer BloomEffect.brightnessThreshold = 1F - StateIsolation.isolate(BlendState(true), BlendFuncState(GL_ONE, GL_ONE)) { - BloomEffect.renderBloom() - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) - } + // Old wrapper: BlendState(true) + BlendFuncState(GL_ONE, GL_ONE) -> additive composite. + // The guide-line 8x energy joins exactly this pass (its 1.21 home was the HDR + // hudFramebuffer content this brightness pass read); see BloomEffect doc. + BloomEffect.includeGuideLineOverlay = true + BloomEffect.renderBloom() + BloomEffect.includeGuideLineOverlay = false + PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.mainRenderTarget, BlendFunction.ADDITIVE) - hudFramebuffer.clear(true) - blurFramebuffer.clear(true) + PostProcessRenderer.clear(hudFramebuffer) + PostProcessRenderer.clear(blurFramebuffer) renderHud = false useBlur = false @@ -895,68 +925,45 @@ object MatrixHud { GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(1.0F, maxSigma = 20F) BlurRenderer.renderGaussianBlur(hudFramebuffer, blurFramebuffer) - StateIsolation.isolate( - FramebufferState(blurFramebuffer), - ViewportState(blurFramebuffer), - BlendState(true), - BlendFuncState(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), - ) { - // Render the blurred hud background to blurFramebuffer - hudFramebuffer opacityMask BlurRenderer.blurFramebuffer + // Render the blurred hud background to blurFramebuffer. The old code bound + // blurFramebuffer via FramebufferState with (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) blending, + // which maps to TRANSLUCENT_PREMULTIPLIED_ALPHA on the wrapper API. + OpacityMaskRenderer.render( + hudFramebuffer, BlurRenderer.blurFramebuffer, blurFramebuffer, + BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA + ) - // Render half-transparent hud on the blurred hud background - hudFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) - } + // Render half-transparent hud on the blurred hud background. 1.21 used vanilla + // Framebuffer.draw here — NO discard — or the pure-black panel fills drop out and + // the boxes lose their dark tint (the discarding copyFramebuffer path ate them). + PostProcessRenderer.drawFramebuffer(hudFramebuffer, blurFramebuffer, BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA) } private fun renderHudBlur() { + // Both branches ended in vanilla Framebuffer.draw pre-migration (no discard) — the + // shadow's pure-black rgb must survive the composite onto the main target. val strength = 1.0F - magicShownOpacityAnimation.animatedValue.toFloat() if (strength == .0F) { - blurFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) + PostProcessRenderer.drawFramebuffer(blurFramebuffer, minecraft.mainRenderTarget, BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA) return } GaussianBlurRenderer.gaussianKernel = GaussianBlurRenderer.generateSymmetricGaussianKernel(strength, maxSigma = 20F) BlurRenderer.renderGaussianBlurFullResolution(blurFramebuffer) - BlurRenderer.blurFramebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, false) + PostProcessRenderer.drawFramebuffer(BlurRenderer.blurFramebuffer, minecraft.mainRenderTarget, BlendFunction.TRANSLUCENT_PREMULTIPLIED_ALPHA) } + // TODO(26.2): renderPoints drew `points` as GL_POINTS with GL_PROGRAM_POINT_SIZE through raw + // client vertex arrays and the transform-feedback pointSpriteProgram above. None of that has + // a dual-backend wrapper equivalent (no point primitives, no transform feedback, no raw VAO + // path), and the function was never called from any live code path; kept as a no-op stub so + // the debug entry point (and the `points` data set) survives for a future reimplementation. + @Suppress("unused", "UNUSED_PARAMETER") private fun renderPoints() { - val result = IntArray(1) - glGenVertexArrays(result) - - val vertexArray = result[0] - val vertexBuffer = glGenBuffers() - - glBindVertexArray(vertexArray) - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer) - - val buffer = MemoryUtil.memAllocFloat(points.size).put(points).flip() - glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW) - MemoryUtil.memFree(buffer) - glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * 4, 0L) - glEnableVertexAttribArray(0) - - pointSpriteProgram.enableShader() - glBindVertexArray(vertexArray) - glEnable(GL_PROGRAM_POINT_SIZE) - glDrawArrays(GL_POINTS, 0, points.size / 2) - pointSpriteProgram.disableShader() - - glBindVertexArray(0) - glBindBuffer(GL_ARRAY_BUFFER, 0) - glDisableVertexAttribArray(0) - glDisable(GL_PROGRAM_POINT_SIZE) - - glDeleteBuffers(vertexBuffer) - glDeleteVertexArrays(vertexArray) - - glBindFramebuffer(GL_FRAMEBUFFER, 0) - glDisable(GL_BLEND) } private fun performChannelMagicAnimation() { - val delta = Util.getMeasuringTimeNano() - lastNanos + val delta = System.nanoTime() - lastNanos for (magic in usingMagicList) { magic.setValue( magic.value + delta / 2000000 @@ -972,11 +979,11 @@ object MatrixHud { if (MatrixClient.getPlayerMagics().isEmpty() || !player.isWizard) { return false } - return MinecraftClient.getInstance().options.playerListKey.isPressed + return Minecraft.getInstance().options.keyPlayerList.isDown } private val isPressingTab - get() = MinecraftClient.getInstance().options.playerListKey.isPressed + get() = Minecraft.getInstance().options.keyPlayerList.isDown @JvmField var isPressingRightMouseButton = false @@ -985,9 +992,9 @@ object MatrixHud { var isPressingLeftMouseButton = false fun shouldSlowTime(): Boolean { - val minecraft = MinecraftClient.getInstance() - val server = minecraft.server - return minecraft.isIntegratedServerRunning && (server != null && !server.isRemote) + val minecraft = Minecraft.getInstance() + val server = minecraft.singleplayerServer + return minecraft.isLocalServer && (server != null && !server.isPublished) } private fun onHudVisibilityChanged(visibility: Boolean) { @@ -1054,7 +1061,7 @@ object MatrixHud { AimAssist.resetAnimation() if (firstShow) { firstShow = false - selectTargetEntity(RenderTickCounter.ZERO) + selectTargetEntity(DeltaTracker.ZERO) if (targetedEntity == null) { descriptionYOffsetAnimation.animatedValue = -35.0 } @@ -1062,20 +1069,20 @@ object MatrixHud { } private fun renderManaBar( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, ) { val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) val magicCost = selectedMagic.getCost(calculationContext).toDouble() manaBar.manaCost.value = magicCost - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) + val renderer = LegacyMatrixUIRenderer(drawContext) manaBar.render(drawContext, renderer) } private fun renderLeftPart( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, ) { val magics = MatrixClient.getPlayerMagics() val indentList = generateIndentList(magics.size) @@ -1093,11 +1100,11 @@ object MatrixHud { string: String, width: Double, ): String { - val textRenderer = MinecraftClient.getInstance().textRenderer + val textRenderer = Minecraft.getInstance().font var length = 0 var index = 0 for (character in string) { - length += textRenderer.getWidth( + length += textRenderer.width( character.toString() ) if (length > width) { @@ -1110,8 +1117,8 @@ object MatrixHud { } private fun renderMagic( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, index: Int, magic: Magic, indentList: List, @@ -1122,14 +1129,14 @@ object MatrixHud { val animatedColor = magicColorAnimations.getOrNull( index - 1 ) - val color = ColorHelper.Argb.getArgb( + val color = ARGB.color( (magicShownOpacityAnimation.animatedValue * 127.5).toInt(), animatedColor?.red?.animatedValue?.toInt() ?: 0, animatedColor?.green?.animatedValue?.toInt() ?: 0, animatedColor?.blue?.animatedValue?.toInt() ?: 0 ) val height = 20.0 val margin = 5.0 - val startY = (index * (height + margin) + drawContext.scaledWindowHeight / 2 - (indentList.size + 1) * (height + margin) / 2).toInt() + val startY = (index * (height + margin) + drawContext.guiHeight() / 2 - (indentList.size + 1) * (height + margin) / 2).toInt() val endY = (startY + height).toInt() val status = getMagicAvailableStatus( @@ -1171,12 +1178,12 @@ object MatrixHud { } val statusString = displayData.displayStatus.description - val textRenderer = MinecraftClient.getInstance().textRenderer - displayData.costWidthAnimation.value = textRenderer.getWidth(costString).toDouble() + val textRenderer = Minecraft.getInstance().font + displayData.costWidthAnimation.value = textRenderer.width(costString).toDouble() - val magicNameWidth = textRenderer.getWidth(magic.definition.name) + val magicNameWidth = textRenderer.width(magic.definition.name) val costStringWidth = displayData.costWidthAnimation.animatedValue - val statusStringWidth = textRenderer.getWidth(status.description) + val statusStringWidth = textRenderer.width(status.description) val extraWidth = magicNameWidth + costStringWidth + statusStringWidth + 30 /* padding */ val extraWidthAnimation = magicExtraWidthAnimations[index - 1].animation extraWidthAnimation.currentValue = extraWidth @@ -1185,52 +1192,31 @@ object MatrixHud { xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY ) - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - val blurBackgroundStartX = xIndent + 50 + magicShownAnimation.animatedValue.toInt() val blurBackgroundEndX = xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt() - val builder = Tessellator.getInstance() - var buffer = builder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR) - buffer.vertex(transformationMatrix, blurBackgroundEndX.toFloat(), endY.toFloat(), 0f).color(color).texture(1.0F, 1.0F) - buffer.vertex(transformationMatrix, blurBackgroundEndX.toFloat(), startY.toFloat(), 0f).color(color).texture(1.0F, .0F) - buffer.vertex(transformationMatrix, blurBackgroundStartX.toFloat(), startY.toFloat(), 0f).color(color).texture(.0F, .0F) - buffer.vertex(transformationMatrix, blurBackgroundStartX.toFloat(), endY.toFloat(), 0f).color(color).texture(.0F, 1.0F) - - StateIsolation.isolate( - BlendState(true), - ShaderProgramState(GameRenderer::getPositionColorProgram) - ) { - BufferRenderer.drawWithGlobalProgram(buffer.end()) - } + // 26.2: the POSITION_COLOR triangle-fan quad (drawn through the global position-color + // program with blending) is an axis-aligned rectangle -- drawContext.fill is equivalent. + drawContext.fill(blurBackgroundStartX, startY, blurBackgroundEndX, endY, color) // dissolveShader.disableShader() - // drawContext.fill(xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY, 0, color) - val alpha = magicShownOpacityAnimation.animatedValue * 255 - val foregroundColor = ColorHelper.Argb.getArgb(alpha.toInt(), 255, 255, 255) + val foregroundColor = ARGB.color(alpha.toInt(), 255, 255, 255) if (alpha > 4) { - val multiplier = 1.0F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - drawContext.drawText(textRenderer, magic.definition.name, xIndent + 55 + magicShownAnimation.animatedValue.toInt(), startY + 5, foregroundColor, false) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + drawContext.text(textRenderer, magic.definition.name, xIndent + 55 + magicShownAnimation.animatedValue.toInt(), startY + 5, foregroundColor, false) } val costAlpha = min(alpha, displayData.costChangedAnimation.animatedValue * 255) // println((displayData.costChangedAnimation.animatedValue * 255).toInt()) if (costAlpha > 4) { - val multiplier = 1.0F - val costForegroundColor = ColorHelper.Argb.getArgb(costAlpha.toInt(), 255, 255, 255) - RenderSystem.setShaderColor(1.0F, multiplier, 1.0F, 1.0F) - drawContext.drawText(textRenderer, Text.literal(costString), xIndent + 65 + magicNameWidth + magicShownAnimation.animatedValue.toInt(), startY + 5, costForegroundColor, false) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + val costForegroundColor = ARGB.color(costAlpha.toInt(), 255, 255, 255) + drawContext.text(textRenderer, Component.literal(costString), xIndent + 65 + magicNameWidth + magicShownAnimation.animatedValue.toInt(), startY + 5, costForegroundColor, false) } val statusAlpha = min(alpha, displayData.statusChangedAnimation.animatedValue * 255) if (statusAlpha > 4) { - val statusForegroundColor = ColorHelper.Argb.getArgb(statusAlpha.toInt(), 255, 255, 255) - drawContext.drawText(textRenderer, statusString, xIndent + 75 + magicNameWidth + costStringWidth.toInt() + magicShownAnimation.animatedValue.toInt(), startY + 5, statusForegroundColor, false) + val statusForegroundColor = ARGB.color(statusAlpha.toInt(), 255, 255, 255) + drawContext.text(textRenderer, statusString, xIndent + 75 + magicNameWidth + costStringWidth.toInt() + magicShownAnimation.animatedValue.toInt(), startY + 5, statusForegroundColor, false) } drawContext.disableScissor() @@ -1253,144 +1239,37 @@ object MatrixHud { } val animationProgress = (startX - xIndent - 50) / extraWidth - val progressColor = Color( - 25, 192, 25, (magicShownOpacityAnimation.animatedValue * 128).toInt() - ) - val brightProgressColor = Color( - 25, 255, 25, (magicShownOpacityAnimation.animatedValue * 255).toInt().coerceAtMost( - 255 - ) + + // 26.2: the four POSITION_COLOR triangle-strip parallelograms are now drawn as + // per-row fills through drawSlantedBand. The old RenderSystem.setShaderColor + // (4x, 4x, 4x, 0.7 - progress) HDR multiplier is folded directly into the vertex + // colors (rgb clamped to 255, alpha multiplied); the bloom-oriented >1.0 brightness + // cannot be expressed in the LDR GUI color path. + val shaderAlpha = (0.7 - animationProgress).coerceIn(.0, 1.0) + val progressColor = ARGB.color( + (magicShownOpacityAnimation.animatedValue * 128 * shaderAlpha).toInt().coerceIn(0, 255), + 100, 255, 100 ) - val transparentColor = Color( - 0, 0, 0, 0 + val brightProgressColor = ARGB.color( + ((magicShownOpacityAnimation.animatedValue * 255).coerceAtMost(255.0) * shaderAlpha).toInt().coerceIn(0, 255), + 100, 255, 100 ) - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - - // We're drawing in triangle strip mode, the first 3 vertices form the first triangle. - // Each added vertex forms a new triangle with the first vertex and the last vertex. - // - // We need to draw a parallelogram, we split the parallelogram into two triangles to render - // in this mode, first we draw the left triangle by the following order: - // 1. lower left corner (startX, endY) - // 2. lower right corner (endX, endY) - // 3. upper right corner (endX, startY) - // Then we draw the right triangle, in this mode we only need to draw a new vertex that will - // form a new triangle with the first two vertices, so we only need to draw the upper right - // of the right triangle (endX + width, startY) drawContext.enableScissor( xIndent + 50 + magicShownAnimation.animatedValue.toInt(), startY, xIndent + 50 + extraWidthAnimation.animatedValue.toInt() + magicShownAnimation.animatedValue.toInt(), endY ) - val halfTransparentColor = Color(0, 255, 0, (magicShownOpacityAnimation.animatedValue * 255 * (1.0 - animationProgress)).toInt()) - buffer = tessellator.begin(VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR) - buffer.vertex( - transformationMatrix, startX.toFloat(), endY.toFloat(), 0f - ).color( - transparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), endY.toFloat(), 0f - ).color( - halfTransparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), startY.toFloat(), 0f - ).color( - transparentColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + height).toFloat(), startY.toFloat(), 0f - ).color( - halfTransparentColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram(buffer.end()) - - val multiplier = 4.0F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, (0.7F - animationProgress).toFloat()) - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, startX.toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, endX.toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + height).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram( - buffer.end() + // TODO(26.2): the first band originally faded horizontally (transparent -> green) + // across the parallelogram via per-vertex colors; drawn solid at the brighter edge + // color here (per-row fills cannot express a horizontal gradient). + val halfTransparentColor = ARGB.color( + (magicShownOpacityAnimation.animatedValue * 255 * (1.0 - animationProgress)).toInt().coerceIn(0, 255), + 0, 255, 0 ) - - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, (startX + 20).toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20).toFloat(), endY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 20 + height).toFloat(), startY.toFloat(), 0f - ).color( - progressColor.toInt() - ) - BufferRenderer.drawWithGlobalProgram( - buffer.end() - ) - - buffer = tessellator.begin( - VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR - ) - buffer.vertex( - transformationMatrix, (startX + 10).toFloat(), endY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 10).toFloat(), endY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 10).toFloat(), startY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - buffer.vertex( - transformationMatrix, (endX + 10 + height).toFloat(), startY.toFloat(), 0f - ).color( - brightProgressColor.toInt() - ) - - RenderSystem.enableBlend() - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.defaultBlendFunc() - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) + drawSlantedBand(drawContext, startX, startY, endY, height, halfTransparentColor) + drawSlantedBand(drawContext, startX, startY, endY, height, progressColor) + drawSlantedBand(drawContext, startX + 20, startY, endY, height, progressColor) + drawSlantedBand(drawContext, startX + 10, startY, endY, height, brightProgressColor) // val renderer = MatrixUIRenderer(drawContext.vertexConsumers) // renderer.renderRectangle( @@ -1404,18 +1283,46 @@ object MatrixHud { } } + /** + * Draws the slanted progress parallelogram (bottom edge at [startX], top edge shifted right + * by [bandWidth]) as per-row 1px fills -- the 26.2 replacement for the old POSITION_COLOR + * triangle strips. + */ + private fun drawSlantedBand( + drawContext: GuiGraphicsExtractor, + startX: Double, + top: Int, + bottom: Int, + bandWidth: Double, + color: Int, + ) { + val rows = (bottom - top).coerceAtLeast(1) + for (row in 0 until rows) { + val rowFraction = row / rows.toDouble() + val left = startX + bandWidth * (1.0 - rowFraction) + val right = left + bandWidth + drawContext.fill( + left.roundToInt(), + top + row, + right.roundToInt().coerceAtLeast(left.roundToInt() + 1), + top + row + 1, + color + ) + } + } + private fun renderOverclock( - drawContext: DrawContext, - tickCounter: RenderTickCounter, + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, ) { val renderer = LegacyMatrixUIRenderer( - drawContext.vertexConsumers + drawContext ) val manaOverclockMinPoint = Point( renderer.scaledWindowWidth - 5.0, renderer.scaledWindowHeight.toDouble() - 25.0 ) val manaOverclockMaxPoint = Point( - renderer.scaledWindowWidth - 10.0, MathHelper.lerp( + renderer.scaledWindowWidth - 10.0, Mth.lerp( manaOverclock.animatedValue / 10, renderer.scaledWindowHeight.toDouble() - 25.0, 25.0 ) ) @@ -1425,23 +1332,23 @@ object MatrixHud { ) val magicOverclockMaxPoint = Point( - renderer.scaledWindowWidth - 20.0, MathHelper.lerp( + renderer.scaledWindowWidth - 20.0, Mth.lerp( magicOverclock.animatedValue / 10, renderer.scaledWindowHeight.toDouble() - 25.0, 25.0 ) ) val magicOverclockColor = Color( - MathHelper.lerp( + Mth.lerp( magicOverclock.animatedValue / 10.0, 0.0, 255.0 - ).toInt(), MathHelper.lerp( + ).toInt(), Mth.lerp( magicOverclock.animatedValue / 10.0, 255.0, 0.0 ).toInt(), 0, 128 ) val manaOverclockColor = Color( - MathHelper.lerp( + Mth.lerp( manaOverclock.animatedValue / 10.0, 0.0, 255.0 - ).toInt(), MathHelper.lerp( + ).toInt(), Mth.lerp( manaOverclock.animatedValue / 10.0, 255.0, 0.0 ).toInt(), 0, 128 ) @@ -1458,10 +1365,10 @@ object MatrixHud { ) } - private fun selectTargetEntity(tickCounter: RenderTickCounter) { - var targetedEntity = getTargetedEntity(tickCounter.getTickDelta(true)) + private fun selectTargetEntity(tickCounter: DeltaTracker) { + var targetedEntity = getTargetedEntity(tickCounter.getGameTimeDeltaPartialTick(true)) if (targetedEntity is EnderDragonPart) { - targetedEntity = targetedEntity.owner + targetedEntity = targetedEntity.parentMob } if (targetedEntity != this.targetedEntity) { if (targetedEntity == null) { @@ -1478,17 +1385,15 @@ object MatrixHud { this.targetedEntity = targetedEntity as? LivingEntity? } - private fun renderRightPart(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val backgroundColor = ColorHelper.Argb.getArgb((magicShownOpacityAnimation.animatedValue * 127.5).toInt(), 255, 255, 255) + private fun renderRightPart(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + val backgroundColor = ARGB.color((magicShownOpacityAnimation.animatedValue * 127.5).toInt(), 255, 255, 255) val alpha = (magicShownOpacityAnimation.animatedValue * 255).coerceIn(.0..255.0).toInt() - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) val offsetX = magicShownAnimation.animatedValue.toFloat() val offsetY = descriptionExtraHeightAnimation.animatedValue.toFloat() - val windowWidth = drawContext.scaledWindowWidth - val windowHeight = drawContext.scaledWindowHeight + val windowWidth = drawContext.guiWidth() + val windowHeight = drawContext.guiHeight() val leftX = windowWidth - 200 - offsetX val rightX = windowWidth - 25 - offsetX @@ -1498,31 +1403,28 @@ object MatrixHud { val width = rightX - leftX val height = bottomY - topY - buffer.vertex(rightX, topY, 0F).texture(0F, 0F).color(backgroundColor) - buffer.vertex(leftX, topY, 0F).texture(1F, 0F).color(backgroundColor) - buffer.vertex(leftX, bottomY, 0F).texture(1F, 1F).color(backgroundColor) - buffer.vertex(rightX, bottomY, 0F).texture(0F, 1F).color(backgroundColor) - - dissolveShader.dissolveFactor = dissolveAnimation.animatedValue.toFloat() - dissolveShader.resolutionX = width - dissolveShader.resolutionY = height - dissolveShader.enableShader() - - StateIsolation.isolate(BlendState(true)) { - BufferRenderer.draw(buffer.end()) - } - - dissolveShader.disableShader() - dissolveShader.resolutionX = 1.0F - dissolveShader.resolutionY = 1.0F + // 26.2: the 1.21 mesh-attached dissolve program (DissolveShader around a + // POSITION_TEXTURE_COLOR quad) is a GUI-pipeline element now; the per-draw uniforms + // (factor, height/width ratio, time) travel packed in the Normal attribute. + DissolveRect.precompile() + drawContext.guiRenderState.addGuiElement( + DissolveRectRenderState( + leftX, topY, rightX, bottomY, + backgroundColor, + dissolveAnimation.animatedValue.toFloat(), + height / width, + (System.nanoTime() % 10_000_000_000L) / 1_000_000_000F, + scissor = null, + ) + ) val descriptionAlpha = min(magicShownOpacityAnimation.animatedValue * 255, entityDescriptionOpacityAnimation.animatedValue * 255).toInt() val cachedTargetedEntity = this.cachedTargetedEntity - val textRenderer = MinecraftClient.getInstance().textRenderer + val textRenderer = Minecraft.getInstance().font if (cachedTargetedEntity != null) { - val red = ColorHelper.Argb.getArgb(descriptionAlpha, 255, 25, 25) - val green = ColorHelper.Argb.getArgb(descriptionAlpha, 25, 255, 25) + val red = ARGB.color(descriptionAlpha, 255, 25, 25) + val green = ARGB.color(descriptionAlpha, 25, 255, 25) val health = cachedTargetedEntity.health.toDouble() val maxHealth = cachedTargetedEntity.maxHealth.toDouble() @@ -1536,7 +1438,7 @@ object MatrixHud { healthPercentageAnimation.value = (health / maxHealth).coerceIn(.0..1.0) val percentage = healthPercentageAnimation.animatedValue - val lerpedColor = ColorHelper.Argb.lerp(percentage.toFloat(), red, green) + val lerpedColor = lerpColor(percentage.toFloat(), red, green) val sizeReduced = if (sizeScalingAnimation) { 10 - (entityDescriptionOpacityAnimation.animatedValue * 10).toInt() @@ -1544,27 +1446,27 @@ object MatrixHud { 0 } - val progressBarX = MathHelper.lerp(percentage.toFloat(), 190, 35) - val x1 = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() + sizeReduced - val x2 = drawContext.scaledWindowWidth - progressBarX - magicShownAnimation.animatedValue.toInt() - sizeReduced + val progressBarX = Mth.lerpInt(percentage.toFloat(), 190, 35) + val x1 = drawContext.guiWidth() - 190 - magicShownAnimation.animatedValue.toInt() + sizeReduced + val x2 = drawContext.guiWidth() - progressBarX - magicShownAnimation.animatedValue.toInt() - sizeReduced - val multiplier = lerp(1.0 - percentage, 1.0, 5.0).toFloat() - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) + // TODO(26.2): the health bar fill was brightened up to 5x via + // RenderSystem.setShaderColor (HDR input for the bloom pass); the LDR GUI color path + // cannot express >1.0 channel multipliers, so the boost is dropped. drawContext.fill( x1.coerceAtMost(x2), - drawContext.scaledWindowHeight / 2 - 80 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, + drawContext.guiHeight() / 2 - 80 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, x2, - drawContext.scaledWindowHeight / 2 - 75 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, + drawContext.guiHeight() / 2 - 75 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - sizeReduced, lerpedColor ) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) val fontSizeReduced = if (sizeScalingAnimation) { entityDescriptionOpacityAnimation.animatedValue.toFloat() } else { 1F } - val descriptionForegroundColor = ColorHelper.Argb.getArgb(descriptionAlpha, 255, 255, 255) + val descriptionForegroundColor = ARGB.color(descriptionAlpha, 255, 255, 255) if (descriptionAlpha > 3) { val currentHealth = BigDecimal.valueOf(healthAnimation.animatedValue) .setScale(2, RoundingMode.HALF_UP) @@ -1578,20 +1480,20 @@ object MatrixHud { .append(maxHealth) .toString() - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() - val textY = drawContext.scaledWindowHeight / 2 - 70 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() + val textX = drawContext.guiWidth() - 190 - magicShownAnimation.animatedValue.toInt() + val textY = drawContext.guiHeight() / 2 - 70 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - val textWidth = textRenderer.getWidth(healthText) + val textWidth = textRenderer.width(healthText) val textCenterX = textX + textWidth / 2.0 val textCenterY = textY.toDouble() - 15 - drawContext.matrices.push() + drawContext.pose().pushMatrix() - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) + drawContext.pose().translate(textCenterX.toFloat(), textCenterY.toFloat()) + drawContext.pose().scale(fontSizeReduced, fontSizeReduced) + drawContext.pose().translate(-textCenterX.toFloat(), -textCenterY.toFloat()) - drawContext.drawText( + drawContext.text( textRenderer, healthText, textX, @@ -1599,7 +1501,7 @@ object MatrixHud { descriptionForegroundColor, false ) - drawContext.matrices.pop() + drawContext.pose().popMatrix() } val hashCode = cachedTargetedEntity.name.hashCode() @@ -1612,24 +1514,24 @@ object MatrixHud { displayEntityName = cachedTargetedEntity.name } val entityNameAlpha = min(descriptionAlpha, (displayEntityNameOpacityAnimation.animatedValue * 255).toInt()) - val entityNameForegroundColor = ColorHelper.Argb.getArgb(entityNameAlpha, 255, 255, 255) + val entityNameForegroundColor = ARGB.color(entityNameAlpha, 255, 255, 255) if (entityNameAlpha > 3) { - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() - val textY = drawContext.scaledWindowHeight / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() + val textX = drawContext.guiWidth() - 190 - magicShownAnimation.animatedValue.toInt() + val textY = drawContext.guiHeight() / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() - val textWidth = textRenderer.getWidth(displayEntityName) + val textWidth = textRenderer.width(displayEntityName) val textCenterX = textX + textWidth / 2.0 - val textCenterY = textY + textRenderer.fontHeight / 2.0 + val textCenterY = textY + textRenderer.lineHeight / 2.0 - drawContext.matrices.push() + drawContext.pose().pushMatrix() - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) + drawContext.pose().translate(textCenterX.toFloat(), textCenterY.toFloat()) + drawContext.pose().scale(fontSizeReduced, fontSizeReduced) + drawContext.pose().translate(-textCenterX.toFloat(), -textCenterY.toFloat()) - drawContext.drawText(textRenderer, displayEntityName, textX, textY, entityNameForegroundColor, true) + drawContext.text(textRenderer, displayEntityName, textX, textY, entityNameForegroundColor, true) - drawContext.matrices.pop() + drawContext.pose().popMatrix() } if (candidateAimAssistEntities.size != previousCandidateEntities) { @@ -1641,27 +1543,27 @@ object MatrixHud { } val candidateCountAlpha = min(descriptionAlpha, (displayCandidateCountOpacityAnimation.animatedValue * 255).toInt()) - val candidateCountColor = ColorHelper.Argb.getArgb(candidateCountAlpha, 255, 255, 255) + val candidateCountColor = ARGB.color(candidateCountAlpha, 255, 255, 255) if (candidateCountAlpha > 3) { - candidateCountPadding.value = (textRenderer.getWidth(displayEntityName) + textRenderer.getWidth(" ")).toDouble() + candidateCountPadding.value = (textRenderer.width(displayEntityName) + textRenderer.width(" ")).toDouble() val padding = candidateCountPadding.animatedValue - val textX = drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt() + padding - val textY = drawContext.scaledWindowHeight / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() + val textX = drawContext.guiWidth() - 190 - magicShownAnimation.animatedValue.toInt() + padding + val textY = drawContext.guiHeight() / 2 - 90 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() val text = "+$displayCandidateEntities" - val textWidth = textRenderer.getWidth(text) + val textWidth = textRenderer.width(text) val textCenterX = textX + textWidth / 2.0 - val textCenterY = textY + textRenderer.fontHeight / 2.0 + val textCenterY = textY + textRenderer.lineHeight / 2.0 - drawContext.matrices.push() + drawContext.pose().pushMatrix() - drawContext.matrices.translate(textCenterX, textCenterY, 0.0) - drawContext.matrices.scale(fontSizeReduced, fontSizeReduced, fontSizeReduced) - drawContext.matrices.translate(-textCenterX, -textCenterY, 0.0) + drawContext.pose().translate(textCenterX.toFloat(), textCenterY.toFloat()) + drawContext.pose().scale(fontSizeReduced, fontSizeReduced) + drawContext.pose().translate(-textCenterX.toFloat(), -textCenterY.toFloat()) - drawContext.drawText(textRenderer, text, round(textX).toInt(), textY, candidateCountColor, true) + drawContext.text(textRenderer, text, round(textX).toInt(), textY, candidateCountColor, true) - drawContext.matrices.pop() + drawContext.pose().popMatrix() } } @@ -1670,10 +1572,10 @@ object MatrixHud { } drawContext.enableScissor( - drawContext.scaledWindowWidth - 200 - magicShownAnimation.animatedValue.toInt(), - drawContext.scaledWindowHeight / 2 - 100 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt(), - drawContext.scaledWindowWidth - 25 - magicShownAnimation.animatedValue.toInt(), - drawContext.scaledWindowHeight / 2 + 100 + (descriptionExtraHeightAnimation.animatedValue / 2).toInt() + drawContext.guiWidth() - 200 - magicShownAnimation.animatedValue.toInt(), + drawContext.guiHeight() / 2 - 100 - (descriptionExtraHeightAnimation.animatedValue / 2).toInt(), + drawContext.guiWidth() - 25 - magicShownAnimation.animatedValue.toInt(), + drawContext.guiHeight() / 2 + 100 + (descriptionExtraHeightAnimation.animatedValue / 2).toInt() ) val currentMagic = MatrixClient.getPlayerMagics()[selectedIndex - 1] @@ -1686,25 +1588,37 @@ object MatrixHud { displayDescription = currentDescription } - val descriptionY = drawContext.scaledWindowHeight / 2 - 55 + descriptionYOffsetAnimation.animatedValue.toInt() - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() // + magicSwitchAnimation.animatedValue + val descriptionY = drawContext.guiHeight() / 2 - 55 + descriptionYOffsetAnimation.animatedValue.toInt() - (descriptionExtraHeightAnimation.animatedValue / 2).toInt() // + magicSwitchAnimation.animatedValue - val lines = textRenderer.wrapLines(currentDescription, 150) - val extraHeight = textRenderer.fontHeight * lines.size - 180.0 + val lines = textRenderer.split(currentDescription, 150) + val extraHeight = textRenderer.lineHeight * lines.size - 180.0 descriptionExtraHeightAnimation.value = extraHeight.coerceAtLeast(.0) val magicDescriptionAlpha = (min(magicShownOpacityAnimation.animatedValue, magicDescriptionChangedAnimation.animatedValue) * 255).toInt() if (magicDescriptionAlpha > 3) { - drawContext.drawTextWrapped(textRenderer, displayDescription, drawContext.scaledWindowWidth - 190 - magicShownAnimation.animatedValue.toInt(), descriptionY, 150, ColorHelper.Argb.getArgb(magicDescriptionAlpha, 255, 255, 255)) + drawContext.textWithWordWrap(textRenderer, displayDescription, drawContext.guiWidth() - 190 - magicShownAnimation.animatedValue.toInt(), descriptionY, 150, ARGB.color(magicDescriptionAlpha, 255, 255, 255)) } drawContext.disableScissor() } + /** + * 26.2 replacement for the removed ColorHelper.Argb.lerp: per-channel ARGB interpolation. + */ + private fun lerpColor(delta: Float, from: Int, to: Int): Int { + return ARGB.color( + Mth.lerpInt(delta, ARGB.alpha(from), ARGB.alpha(to)), + Mth.lerpInt(delta, ARGB.red(from), ARGB.red(to)), + Mth.lerpInt(delta, ARGB.green(from), ARGB.green(to)), + Mth.lerpInt(delta, ARGB.blue(from), ARGB.blue(to)), + ) + } + private fun getTargetedEntity(tickDelta: Float): Entity? { val candidateEntities = getAssistTargetEntity(tickDelta)//.filter { entity -> // val rotationVector = player.getRotationVec(tickDelta) // val from = player.getCameraPosVec(tickDelta) // val to = player.getCameraPosVec(tickDelta).add(rotationVector.multiply(aimAssistMaxDistance)) - // val blockHit = player.world.raycast(RaycastContext(from, to, RaycastContext.ShapeType.VISUAL, RaycastContext.FluidHandling.ANY, player)) + // val blockHit = player.world.raycast(ClipContext(from, to, ClipContext.ShapeType.VISUAL, ClipContext.FluidHandling.ANY, player)) // val blockHitDistance = player.squaredDistanceTo(blockHit.pos) // blockHitDistance >= entity.squaredDistanceTo(player) //} @@ -1734,41 +1648,35 @@ object MatrixHud { .map { it as LivingEntity } .filter { val calculationContext = MagicCalculationContext.fromEntity(player, it) - selectedMagic.availableStatus(calculationContext) == LMagicAvailableStatus.AVAILABLE + selectedMagic.availableStatus(calculationContext).isAvailable } + .toList() } private fun getRayCastTargetEntity(tickDelta: Float): Entity? { val range = 10000.0 - val minecraftClient = MinecraftClient.getInstance()!! + val minecraftClient = Minecraft.getInstance()!! val camera = minecraftClient.cameraEntity!! - val location = camera.getCameraPosVec(tickDelta) - val rotation = camera.getRotationVec(tickDelta) + val location = camera.getEyePosition(tickDelta) + val rotation = camera.getViewVector(tickDelta) val min = location.add(rotation) - val max = location.add(rotation.multiply(range)) - val box = Box(min, max) + val max = location.add(rotation.scale(range)) + val box = AABB(min, max) // Wrap Dancer: Select entities through walls if (player.wizardHelmetStack.item is WizardHelmet5) { - val result = ProjectileUtil.raycast(camera, min, max, box, { entity -> - if (entity.isSpectator) { - return@raycast false - } - true + val result = ProjectileUtil.getEntityHitResult(camera, min, max, box, { entity -> + !entity.isSpectator }, range) return result?.entity } - val blockHit = player.world.raycast(RaycastContext(min, max, RaycastContext.ShapeType.VISUAL, RaycastContext.FluidHandling.ANY, player)) - val blockHitDistance = player.squaredDistanceTo(blockHit.pos) - val result = ProjectileUtil.raycast(camera, min, max, box, { entity -> - if (entity.isSpectator) { - return@raycast false - } - - blockHitDistance > entity.squaredDistanceTo(player) + val blockHit = player.level().clip(ClipContext(min, max, ClipContext.Block.VISUAL, ClipContext.Fluid.ANY, player)) + val blockHitDistance = player.distanceToSqr(blockHit.location) + val result = ProjectileUtil.getEntityHitResult(camera, min, max, box, { entity -> + !entity.isSpectator && blockHitDistance > entity.distanceToSqr(player) }, range) return result?.entity @@ -1794,13 +1702,19 @@ object MatrixHud { crosshairX.value = x.toDouble() crosshairY.value = y.toDouble() } else { - val tickDelta = minecraft.renderTickCounter.getTickDelta(true) - val lerpedPosition = targetedEntity.getLerpedPos(tickDelta).add( + val tickDelta = minecraft.deltaTracker.getGameTimeDeltaPartialTick(true) + val lerpedPosition = targetedEntity.getPosition(tickDelta).add( .0, - targetedEntity.boundingBox.lengthY / 2, + targetedEntity.boundingBox.ysize / 2, .0 ) - val screenPosition = worldToScreen(lerpedPosition) + // The blitSprite coordinates this feeds are GUI-scaled, so project into the + // gui-scaled viewport (the physical-pixel default lands scale-factor off-center). + val screenPosition = worldToScreen( + lerpedPosition, + viewportWidth = minecraft.window.guiScaledWidth, + viewportHeight = minecraft.window.guiScaledHeight, + ) if (screenPosition != null) { crosshairX.value = screenPosition.x crosshairY.value = screenPosition.y @@ -1848,19 +1762,27 @@ object MatrixHud { @JvmStatic fun onKey(window: Long, key: Int, scancode: Int, action: Int, mods: Int): Boolean { - if (window != minecraft.window.handle) { + if (window != minecraft.window.handle()) { return false } - if (isPressingTab && InputUtil.isKeyPressed(minecraft.window.handle, GLFW.GLFW_KEY_E) && - player.getEquippedStack(EquipmentSlot.CHEST).item is LightningChestplate1 + // Only the E key's own PRESS event may be consumed: these branches used to match any + // key event while E was physically held (old-jar parity), which swallowed the TAB + // RELEASE when E was still down — vanilla never saw the release, keyPlayerList.isDown + // stayed true and the slow-time stuck on ("state not controlled" bug). + val isEKeyPress = key == GLFW.GLFW_KEY_E && action == GLFW.GLFW_PRESS + if (isEKeyPress && isPressingTab && + player.getItemBySlot(EquipmentSlot.CHEST).item is LightningChestplate1 ) { - ClientPlayNetworking.send(BorrowedTimePayload()) + // 26.2: `BorrowedTimePayload()` was an unresolved reference even in the 1.21 baseline + // (70b7cff); the registered serverbound payload is the ServerboundBorrowedTimePayload + // data object. + ClientPlayNetworking.send(ServerboundBorrowedTimePayload) return true } - if (InputUtil.isKeyPressed(minecraft.window.handle, GLFW.GLFW_KEY_E) && shouldRenderHud()) { - ClientPlayNetworking.send(ServerboundActivateBloodPactPayload()) + if (isEKeyPress && shouldRenderHud()) { + ClientPlayNetworking.send(ServerboundActivateBloodPactPayload) return true } @@ -1874,7 +1796,7 @@ object MatrixHud { @JvmStatic fun onMouseButton(window: Long, button: Int, action: Int, mods: Int): Boolean { - if (window != minecraft.window.handle) { + if (window != minecraft.window.handle()) { return false } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt index 2d9221c8..6bcaff3c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/MatrixKeyBindings.kt @@ -5,51 +5,55 @@ package heckerpowered.matrix.client -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper -import net.minecraft.client.option.KeyBinding -import net.minecraft.client.util.InputUtil +import heckerpowered.matrix.Matrix +import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper +import net.minecraft.client.KeyMapping +import com.mojang.blaze3d.platform.InputConstants import org.lwjgl.glfw.GLFW object MatrixKeyBindings { - val useMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + // 26.2: KeyMapping categories are registered KeyMapping.Category records instead of translation-key strings. + private val category = KeyMapping.Category.register(Matrix.identifier("matrix")) + + val useMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.use_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_F, - "key.categories.matrix" + category ) ) - val nextMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + val nextMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.next_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_DOWN, - "key.categories.matrix" + category ) ) - val previousMagic: KeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( + val previousMagic: KeyMapping = KeyMappingHelper.registerKeyMapping( + KeyMapping( "key.matrix.previous_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UP, - "key.categories.matrix" + category ) ) - val overclockMagic = KeyBinding( + val overclockMagic = KeyMapping( "key.matrix.overclock_magic", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_N, - "key.categories.matrix" + category ) - val overclockMana = KeyBinding( + val overclockMana = KeyMapping( "key.matrix.overclock_mana", - InputUtil.Type.KEYSYM, + InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_M, - "key.categories.matrix" + category ) fun onInitialize() { diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt b/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt index 890bc01c..7f512b3d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/TimeController.kt @@ -7,10 +7,12 @@ package heckerpowered.matrix.client import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.network.ServerboundWarpPayload +import heckerpowered.matrix.mixin.TickRateManagerAccessor import it.unimi.dsi.fastutil.floats.FloatUnaryOperator import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking -import net.minecraft.client.MinecraftClient -import net.minecraft.client.render.RenderTickCounter +import net.minecraft.client.Camera +import net.minecraft.client.Minecraft +import net.minecraft.client.DeltaTracker import net.minecraft.util.Util import kotlin.time.Duration import kotlin.time.Duration.Companion.nanoseconds @@ -33,11 +35,43 @@ object TimeController { } @JvmField - var standaloneRenderTickCounter: RenderTickCounter.Dynamic = - RenderTickCounter.Dynamic(20.0f, 0L, FloatUnaryOperator.identity()) + var standaloneRenderTickCounter: DeltaTracker.Timer = + DeltaTracker.Timer(20.0f, 0L, FloatUnaryOperator.identity()) + + // 26.2: Camera.tickFov (was GameRenderer.updateFovMultiplier) and Minecraft.handleKeybinds (was + // handleInputEvents) are private with no public equivalent (former access widener entries), so + // they are accessed via reflection. + // Fail soft: a lookup failure only degrades the standalone tick's FOV/keybind updates + // instead of killing TimeController's static init (and with it the whole time system). + private val tickFovMethod = runCatching { + Camera::class.java.getDeclaredMethod("tickFov").apply { isAccessible = true } + }.onFailure { heckerpowered.matrix.Matrix.LOGGER.error("Camera.tickFov reflection failed", it) }.getOrNull() + private val handleKeybindsMethod = runCatching { + Minecraft::class.java.getDeclaredMethod("handleKeybinds").apply { isAccessible = true } + }.onFailure { heckerpowered.matrix.Matrix.LOGGER.error("Minecraft.handleKeybinds reflection failed", it) }.getOrNull() + + private const val VANILLA_NANOS_PER_TICK = 50_000_000L val isTimeScaled: Boolean - get() = MinecraftClient.getInstance().renderTickCounter.tickTime - 50.0F > 0.001F + get() { + val tickRateManager = Minecraft.getInstance().level?.tickRateManager() ?: return false + return (tickRateManager as TickRateManagerAccessor).`matrix$getNanosecondsPerTick`() > VANILLA_NANOS_PER_TICK + } + + /** + * 26.2: DeltaTracker.Timer.msPerTick is final and the effective client pace is + * `max(msPerTick, level.tickRateManager().millisecondsPerTick())` (Minecraft.getTickTargetMillis), + * so the pace is driven through the client level's TickRateManager. nanosecondsPerTick is + * written directly (via the mixin accessor — the class-tweaker field widening does not + * apply in production) because setTickRate clamps to >= 1 tps and the 0.01x slow-time + * needs 0.2 tps; slow-time only ever slows below 20 tps, which the max() in + * getTickTargetMillis passes through. + */ + private fun setClientPace(timeScale: Double) { + val level = Minecraft.getInstance().level ?: return + (level.tickRateManager() as TickRateManagerAccessor) + .`matrix$setNanosecondsPerTick`((VANILLA_NANOS_PER_TICK / timeScale).toLong()) + } @JvmStatic var playerImmuneTimeScale: Boolean = false @@ -51,16 +85,16 @@ object TimeController { private var previousPlayerStandaloneTickState = false private fun setTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + setClientPace(timeScale) ClientPlayNetworking.send(ServerboundWarpPayload(timeScale, playerStandaloneRenderTick)) } private fun setClientTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + setClientPace(timeScale) } fun setPlayerStandaloneTimeScale(timeScale: Double) { - MinecraftClient.getInstance().renderTickCounter.tickTime = (50.0 / timeScale).toFloat() + setClientPace(timeScale) } @JvmStatic @@ -69,18 +103,20 @@ object TimeController { deltaTime = System.nanoTime().nanoseconds - lastFrameTime } lastFrameTime = System.nanoTime().nanoseconds - val ticks = standaloneRenderTickCounter.beginRenderTick(Util.getMeasuringTimeMs(), tick) - if (minecraft.world == null || minecraft.player == null) { + // 26.2: beginRenderTick(ms, tick) became advanceGameTime(ms); vanilla now applies the tick flag + // outside the call (see Minecraft.runTick), which is mirrored here. + val ticks = if (tick) standaloneRenderTickCounter.advanceGameTime(Util.getMillis()) else 0 + if (minecraft.level == null || minecraft.player == null) { return } if (!playerStandaloneRenderTick) { return } for (i in 0.. + // 26.2: HudRenderCallback was replaced by HudElementRegistry; still invoked once per rendered frame. + HudElementRegistry.addLast(Matrix.identifier("aim_assist")) { drawContext, tickCounter -> if (autoApplyRotation && isAiming) { applyRotation() } @@ -47,22 +49,22 @@ object AimAssist { @JvmStatic fun onMouseUpdate(timeDelta: Double): Boolean { - lockedPitch.from = player.getPitch(timeDelta.toFloat()).toDouble() - lockedYaw.from = player.getYaw(timeDelta.toFloat()).toDouble() + lockedPitch.from = player.getViewXRot(timeDelta.toFloat()).toDouble() + lockedYaw.from = player.getViewYRot(timeDelta.toFloat()).toDouble() return isMouseLocked && isAiming } fun applyRotation() { - player.pitch = lockedPitch.animatedValue.toFloat() - player.yaw = lockedYaw.animatedValue.toFloat() + player.xRot = lockedPitch.animatedValue.toFloat() + player.yRot = lockedYaw.animatedValue.toFloat() } - fun lookAt(position: Vec3d, tickDelta: Double) { - val x = lerp(tickDelta, player.prevX, player.x) - val y = lerp(tickDelta, player.prevY, player.y) - val z = lerp(tickDelta, player.prevZ, player.z) + fun lookAt(position: Vec3, tickDelta: Double) { + val x = lerp(tickDelta, player.xo, player.x) + val y = lerp(tickDelta, player.yo, player.y) + val z = lerp(tickDelta, player.zo, player.z) - val playerPosition = Vec3d(x, y, z) + val playerPosition = Vec3(x, y, z) val direction = position.subtract(playerPosition) val distance2D = sqrt(direction.x * direction.x + direction.z * direction.z) @@ -74,12 +76,12 @@ object AimAssist { lockedPitch.value = wrapDegrees(pitch) } - fun rotationDifference(position: Vec3d, tickDelta: Double): Double { - val x = lerp(tickDelta, player.prevX, player.x) - val y = lerp(tickDelta, player.prevY, player.y) - val z = lerp(tickDelta, player.prevZ, player.z) + fun rotationDifference(position: Vec3, tickDelta: Double): Double { + val x = lerp(tickDelta, player.xo, player.x) + val y = lerp(tickDelta, player.yo, player.y) + val z = lerp(tickDelta, player.zo, player.z) - val playerPosition = Vec3d(x, y, z) + val playerPosition = Vec3(x, y, z) val direction = position.subtract(playerPosition) val distance2D = sqrt(direction.x * direction.x + direction.z * direction.z) @@ -87,8 +89,8 @@ object AimAssist { val pitch = -toDegrees(atan2(direction.y, distance2D)) val yaw = toDegrees(atan2(direction.z, direction.x)) - 90 - val pitchDifference = wrapDegrees(pitch) - wrapDegrees(player.pitch.toDouble()) - val yawDifference = wrapDegrees(yaw) - wrapDegrees(player.yaw.toDouble()) + val pitchDifference = wrapDegrees(pitch) - wrapDegrees(player.xRot.toDouble()) + val yawDifference = wrapDegrees(yaw) - wrapDegrees(player.yRot.toDouble()) return sqrt(pitchDifference * pitchDifference + yawDifference * yawDifference) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/core/FramebufferSpoof.kt b/common/src/main/kotlin/heckerpowered/matrix/client/core/FramebufferSpoof.kt index 7e8d4ad3..7337d958 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/core/FramebufferSpoof.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/core/FramebufferSpoof.kt @@ -5,38 +5,49 @@ package heckerpowered.matrix.client.core -import net.minecraft.client.gl.Framebuffer +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.systems.RenderSystem object FramebufferSpoof { - private val stack = mutableListOf() + private val stack = mutableListOf() - private var spoofedFramebuffer: Framebuffer? = null + private var spoofedFramebuffer: RenderTarget? = null @JvmStatic - fun getSpoofedFramebuffer(): Framebuffer? { + fun getSpoofedFramebuffer(): RenderTarget? { return spoofedFramebuffer } - fun push(spoofedFramebuffer: Framebuffer) { + fun push(spoofedFramebuffer: RenderTarget) { FramebufferSpoof.spoofedFramebuffer?.let { stack.addLast(it) } FramebufferSpoof.spoofedFramebuffer = spoofedFramebuffer - spoofedFramebuffer.beginWrite(false) + applyOutputOverride(spoofedFramebuffer) } fun pop() { if (stack.isEmpty()) { spoofedFramebuffer = null + applyOutputOverride(null) return } - spoofedFramebuffer = stack.last() + spoofedFramebuffer = stack.removeLast() + applyOutputOverride(spoofedFramebuffer) } fun clear() { stack.clear() spoofedFramebuffer = null + applyOutputOverride(null) + } + + // 26.2: there is no global framebuffer binding anymore; the vanilla-supported + // equivalent of beginWrite is redirecting RenderType draws via the output overrides. + private fun applyOutputOverride(target: RenderTarget?) { + RenderSystem.outputColorTextureOverride = target?.colorTextureView + RenderSystem.outputDepthTextureOverride = target?.depthTextureView } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/event/InitAttachmentCallback.kt b/common/src/main/kotlin/heckerpowered/matrix/client/event/InitAttachmentCallback.kt index 51bcfb17..230113bf 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/event/InitAttachmentCallback.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/event/InitAttachmentCallback.kt @@ -7,7 +7,7 @@ package heckerpowered.matrix.client.event import net.fabricmc.fabric.api.event.Event import net.fabricmc.fabric.api.event.EventFactory -import net.minecraft.client.gl.Framebuffer +import com.mojang.blaze3d.pipeline.RenderTarget fun interface InitAttachmentCallback { companion object { @@ -36,5 +36,5 @@ fun interface InitAttachmentCallback { * Implementers can use this hook to perform additional setup on the attachment, * such as configuring mipmap levels, setting texture parameters, or clearing initial data. */ - fun onInitAttachment(framebuffer: Framebuffer) + fun onInitAttachment(framebuffer: RenderTarget) } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt b/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt index 5c4f8fd9..d77f0631 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/gameplay/ImminentDanger.kt @@ -5,19 +5,21 @@ package heckerpowered.matrix.client.gameplay +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.TimeController import heckerpowered.matrix.client.player -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.entity.Entity +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.world.entity.Entity object ImminentDanger { private val timeController = TimeController.allocateTimeController() var trackedEntity: Entity? = null init { - HudRenderCallback.EVENT.register { drawContext, tickCounter -> + // 26.2: HudRenderCallback was replaced by HudElementRegistry; still invoked once per rendered frame. + HudElementRegistry.addLast(Matrix.identifier("imminent_danger")) { drawContext, tickCounter -> val trackedEntity = this.trackedEntity - if (trackedEntity != null && trackedEntity.isAlive && trackedEntity.squaredDistanceTo(player) < 9) { + if (trackedEntity != null && trackedEntity.isAlive && trackedEntity.distanceToSqr(player) < 9) { timeController.value = 0.05 } else { timeController.value = 1.0 diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt b/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt index 8ac40922..923de347 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/network/MatrixClientPlayNetworking.kt @@ -10,15 +10,16 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking object MatrixClientPlayNetworking { fun onInitialize() { - ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncManaPayload.id, ClientboundSyncManaPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundSystemCrashPayload.id, ClientboundSystemCrashPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundChannelMagicPayload.id, ClientboundChannelMagicPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundBorrowedTimePayload.id, ClientboundBorrowedTimePayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncHealthPayload.id, ClientboundSyncHealthPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundWitherArmorTriggerPayload.id, ClientboundWitherArmorTriggerPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ImminentDangerPayload.id, ImminentDangerPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncManaPayload.type, ClientboundSyncManaPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundSystemCrashPayload.type) { _, context -> ClientboundSystemCrashPayload.handle(context) } + ClientPlayNetworking.registerGlobalReceiver(ClientboundChannelMagicPayload.type, ClientboundChannelMagicPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundBorrowedTimePayload.type, ClientboundBorrowedTimePayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundSyncHealthPayload.type, ClientboundSyncHealthPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundWitherArmorTriggerPayload.type) { _, context -> ClientboundWitherArmorTriggerPayload.handle(context) } + // ImminentDangerPayload does not exist in the codebase (pre-migration dangling reference): + // ClientPlayNetworking.registerGlobalReceiver(ImminentDangerPayload.id, ImminentDangerPayload::handle) ClientPlayNetworking.registerGlobalReceiver(ClientboundTeleportPayload.type, ClientboundTeleportPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundExplosionPayload.id, ClientboundExplosionPayload::handle) - ClientPlayNetworking.registerGlobalReceiver(ClientboundDamageNumberPayload.id, ClientboundDamageNumberPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundExplosionPayload.type, ClientboundExplosionPayload::handle) + ClientPlayNetworking.registerGlobalReceiver(ClientboundDamageNumberPayload.type, ClientboundDamageNumberPayload::handle) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt index bcd36db4..ad8fb36f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelAnimation.kt @@ -10,7 +10,7 @@ import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.common.magic.core.Magic -import net.minecraft.entity.LivingEntity +import net.minecraft.world.entity.LivingEntity import java.time.Duration class ChannelAnimation( diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt index ed78484f..d55d17b9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ChannelSequenceRenderer.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.systems.RenderSystem +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.render.effect.SculkCatalystEffectRenderer import heckerpowered.matrix.client.render.post.CollapseEffectRenderer import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock @@ -13,252 +13,98 @@ import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.common.magic.spell.SculkCatalystMagic +import heckerpowered.matrix.core.getLerpedPos import heckerpowered.matrix.core.worldToScreen -import heckerpowered.matrix.extension.MatrixLivingEntity -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.render.entity.feature.FeatureRenderer -import net.minecraft.client.render.entity.feature.FeatureRendererContext -import net.minecraft.client.render.entity.model.EntityModel -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.entity.EntityAttachmentType -import net.minecraft.util.math.MathHelper +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor import net.minecraft.world.entity.LivingEntity -import org.joml.Matrix4f import java.time.Duration -import java.util.* - -class ChannelSequenceRenderer( - context: FeatureRendererContext>, -) : FeatureRenderer>(context) { - - private val disabled = false - - companion object { - private val easingFunction = ElasticEase().also { - it.easingMode = EasingMode.OUT - it.oscillations = 0 - } - - class OffsetAnimation { - val xOffsetAnimationClock = AnimationClock(Duration.ofMillis(300), .0, -24.0) - var xOffsetAnimation = DoubleAnimation(xOffsetAnimationClock, easingFunction) - } - - val channelSequenceAnimationMap = WeakHashMap>() - val offsetAnimationMap = WeakHashMap() - - init { - EntityTickCallback.EVENT.register(::onEntityTick) - // HudRenderCallback.EVENT.register(::onHudRender) - // ClientTickEvents.START_WORLD_TICK.register { world -> - // for (entry in channelSequenceAnimationMap) { - // if (entry.key.world != world) { - // continue - // } - // for (channelAnimation in entry.value) { - // if (channelAnimation.currentChannelTime <= channelAnimation.channelTime) { - // channelAnimation.tick(entry.key) - // break - // } - // } - // } +import java.util.WeakHashMap + +/** + * Renders per-entity channel-sequence progress bars above an entity's head. + * + * 26.2 note (structural decision): in 1.21 this was a [net.minecraft.client.render.entity.feature.FeatureRenderer] + * (yarn) / [net.minecraft.client.renderer.entity.layers.RenderLayer] (mojmap) billboarding 3D quads + * in the entity's local space via [heckerpowered.matrix.client.MatrixClient]'s + * `LivingEntityFeatureRendererRegistrationCallback` registration. On 26.2 that registration + * point (`LivingEntityRenderLayerRegistrationCallback`) only ever hands a + * [net.minecraft.client.renderer.entity.state.LivingEntityRenderState], which carries no + * reference back to the source [LivingEntity] (nor a stable id) and there is no Fabric API + * extraction hook to stamp one on via [net.fabricmc.fabric.api.client.rendering.v1.FabricRenderState] + * for arbitrary (including vanilla) living entities without a Mixin into + * `LivingEntityRenderer.extractRenderState` — Mixins are out of scope for this port pass. + * + * `channelSequenceAnimationMap`/`offsetAnimationMap` are keyed by the live [LivingEntity] + * already (see [heckerpowered.matrix.client.render.ChannelAnimation]), so this renderer is + * rewritten as a screen-space HUD overlay (`HudElementRegistry`) that iterates those maps + * directly instead of going through the entity-render-state pipeline. [worldToScreen] performs + * the same perspective projection the old 3D billboard implicitly did, so the on-screen result + * (position, size, animation) is unchanged; only the rendering mechanism moved from a 3D quad + * (positioned via the entity attachment + camera-facing rotation matrix) to an equivalent 2D + * screen-space rectangle. No visual feature was dropped. + */ +object ChannelSequenceRenderer { + private val easingFunction = ElasticEase().also { + it.easingMode = EasingMode.OUT + it.oscillations = 0 + } - // for (entry in channelSequenceAnimationMap.entries) { - // if (entry.key.world != world) { - // continue - // } - // val entity = entry.key - // val list = entry.value - // val iterator = list.iterator() - // while (iterator.hasNext()) { - // val channelAnimation = iterator.next() - // if (channelAnimation.currentChannelTime > channelAnimation.channelTime && channelAnimation.opacityAnimation.animatedValue == 0.0) { - // offsetAnimationMap[entity]?.let { - // it.xOffsetAnimationClock.from = .0 - // it.xOffsetAnimationClock.to = .0 - // } - // iterator.remove() - // } - // } - // } - // } - } + class OffsetAnimation { + val xOffsetAnimationClock = AnimationClock(Duration.ofMillis(300), .0, -24.0) + var xOffsetAnimation = DoubleAnimation(xOffsetAnimationClock, easingFunction) + } - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - for (entry in channelSequenceAnimationMap) { - val entity = entry.key - val animation = entry.value - renderEntityChannelSequence(drawContext, tickCounter, entity, animation) - } - } + val channelSequenceAnimationMap = WeakHashMap>() + val offsetAnimationMap = WeakHashMap() - private fun renderRectangle( - buffer: BufferBuilder, - positionMatrix: Matrix4f, - rectangle: Rectangle, - color: Color, - z: Float = 0F, - ) { - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) + fun onInitialize() { + ClientTickEvents.END_CLIENT_TICK.register { + channelSequenceAnimationMap.keys.toList().forEach(::onEntityTick) } - - private fun renderEntityChannelSequence(drawContext: DrawContext, tickCounter: RenderTickCounter, entity: LivingEntity, animation: List) { - val tickDelta = tickCounter.getTickDelta(false) - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - - val lerpedPosition = entity.getLerpedPos(tickDelta).add( - .0, - entity.boundingBox.lengthY, - .0 - ) - val entityScreenPosition = worldToScreen(lerpedPosition) ?: return - - animation.forEachIndexed { index, channelAnimation -> - val color = Color(128, 0, 0, (128 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val progressColor = Color(255, 0, 0, (255 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val animatedX = if (channelAnimation.opacityAnimation.animatedValue != 1.0 && channelAnimation.opacityAnimationClock.to == 0.0) { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } else { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } - - val isChanneling = if (index == 0) { - true - } else { - animation[index - 1].let { it.currentChannelTime >= it.channelTime } - } - val partialProgress = if (isChanneling) { - tickDelta - } else { - .0f - } - val channelProgress = ((channelAnimation.currentChannelTime + partialProgress - channelAnimation.initialProgressOffset) / channelAnimation.channelTime.toDouble()).coerceAtMost(1.0) - - val progressRectangle = Rectangle( - Point( - entityScreenPosition.x + -8.0 + index * 24 + animatedX, - entityScreenPosition.y + 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - entityScreenPosition.x + 8.0 + index * 24 + animatedX, - entityScreenPosition.y + (1 - channelProgress) * 16.0 + channelAnimation.shownAnimation.animatedValue - ) - ) - val rectangle = Rectangle( - Point( - entityScreenPosition.x + -8.0 + index * 24 + animatedX, - entityScreenPosition.y + (1 - channelProgress).coerceIn(.0..1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - entityScreenPosition.x + 8.0 + index * 24 + animatedX, - entityScreenPosition.y + .0 + channelAnimation.shownAnimation.animatedValue - ) - ) - renderRectangle(buffer, transformationMatrix, rectangle, color, 0F) - renderRectangle(buffer, transformationMatrix, progressRectangle, progressColor, 0F) - } - - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - buffer.endNullable()?.let { BufferRenderer.draw(it) } - - RenderSystem.disableBlend() + HudElementRegistry.addLast(Matrix.identifier("channel_sequence")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) } + } - private fun onEntityTick(entity: LivingEntity) { - if (!entity.world.isClient) { - return - } - val channelAnimation = channelSequenceAnimationMap[entity] ?: return - val removed = channelAnimation.removeIf { it.currentChannelTime > it.channelTime && it.opacityAnimation.animatedValue == 0.0 } - if (removed) { - offsetAnimationMap[entity]?.xOffsetAnimationClock?.apply { - from = .0 - to = .0 - } - } - channelAnimation - .firstOrNull { it.currentChannelTime <= it.channelTime } - ?.tick(entity) + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + for (entry in channelSequenceAnimationMap) { + val entity = entry.key + val animation = entry.value + renderEntityChannelSequence(drawContext, tickCounter, entity, animation) } } - override fun render( - matrices: MatrixStack, - vertexConsumers: VertexConsumerProvider, - light: Int, + private fun renderEntityChannelSequence( + drawContext: GuiGraphicsExtractor, + tickCounter: DeltaTracker, entity: LivingEntity, - limbAngle: Float, - limbDistance: Float, - tickDelta: Float, - animationProgress: Float, - headYaw: Float, - headPitch: Float, + animation: List, ) { - if (entity !is MatrixLivingEntity || disabled) { - return - } - - val channelAnimations = channelSequenceAnimationMap[entity] ?: return - - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - - val minecraftClient = MinecraftClient.getInstance() - val camera = minecraftClient.gameRenderer.camera - val entityRenderer = minecraftClient.entityRenderDispatcher.getRenderer(entity) - val positionOffset = entityRenderer.getPositionOffset(entity, tickDelta) - - val entityPartialX = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderX, entity.x) - val entityPartialY = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderY, entity.y) - val entityPartialZ = MathHelper.lerp(tickDelta.toDouble(), entity.lastRenderZ, entity.z) - - val entityRelativeX = entityPartialX - camera.pos.x - val entityRelativeY = entityPartialY - camera.pos.y - val entityRelativeZ = entityPartialZ - camera.pos.z - - val offsetX = entityRelativeX + positionOffset.x - val offsetY = entityRelativeY + positionOffset.y - val offsetZ = entityRelativeZ + positionOffset.z - - val matrixStack = MatrixStack() - matrixStack.push() - matrixStack.translate(offsetX, offsetY, offsetZ) - - val position = entity.attachments.getPointNullable(EntityAttachmentType.NAME_TAG, 0, entity.getYaw(tickDelta))!! - - matrixStack.push() - matrixStack.translate(position.x, position.y + 0.5, position.z) - matrixStack.multiply(minecraftClient.entityRenderDispatcher.rotation) - matrixStack.scale(0.025f, -0.025f, 0.025f) - - val positionMatrix = matrixStack.peek().positionMatrix - - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - RenderSystem.enableBlend() - val layer = RenderLayer.getGui() - val buffer = vertexConsumers.getBuffer(layer) - - channelAnimations.forEachIndexed { index, channelAnimation -> + val tickDelta = tickCounter.getGameTimeDeltaPartialTick(false) + + val lerpedPosition = entity.getLerpedPos(tickDelta).add( + .0, + entity.boundingBox.ysize, + .0 + ) + val entityScreenPosition = worldToScreen( + lerpedPosition, + viewportWidth = drawContext.guiWidth(), + viewportHeight = drawContext.guiHeight(), + ) ?: return + + animation.forEachIndexed { index, channelAnimation -> val color = Color(128, 0, 0, (128 * channelAnimation.opacityAnimation.animatedValue).toInt()) val progressColor = Color(255, 0, 0, (255 * channelAnimation.opacityAnimation.animatedValue).toInt()) - val animatedX = if (channelAnimation.opacityAnimation.animatedValue != 1.0 && channelAnimation.opacityAnimationClock.to == 0.0) { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } else { - offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 - } + val animatedX = offsetAnimationMap[entity]?.xOffsetAnimation?.animatedValue ?: 0.0 val isChanneling = if (index == 0) { true } else { - channelAnimations[index - 1].let { it.currentChannelTime >= it.channelTime } + animation[index - 1].let { it.currentChannelTime >= it.channelTime } } val partialProgress = if (isChanneling) { tickDelta @@ -266,59 +112,42 @@ class ChannelSequenceRenderer( .0f } val channelProgress = ((channelAnimation.currentChannelTime + partialProgress - channelAnimation.initialProgressOffset) / channelAnimation.channelTime.toDouble()).coerceAtMost(1.0) - val progressRectangle = Rectangle( - Point( - -8.0 + index * 24 + animatedX, 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - 8.0 + index * 24 + animatedX, (1 - channelProgress) * 16.0 + channelAnimation.shownAnimation.animatedValue - ) - ) - val rectangle = Rectangle( - Point( - -8.0 + index * 24 + animatedX, (1 - channelProgress).coerceIn(.0..1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue - ), Point( - 8.0 + index * 24 + animatedX, .0 + channelAnimation.shownAnimation.animatedValue - ) - ) - renderRectangle( - buffer, positionMatrix, rectangle, color, light, if (isChanneling) { - 0.01f - } else { - -0.01f - } - ) - renderRectangle( - buffer, positionMatrix, progressRectangle, progressColor, light, if (isChanneling) { - 0f - } else { - -0.01f - } - ) - if (channelAnimations[index].magic == SculkCatalystMagic && - channelAnimations[index].currentChannelTime < channelAnimations[index].channelTime + + val minX = (entityScreenPosition.x + -8.0 + index * 24 + animatedX).toInt() + val maxX = (entityScreenPosition.x + 8.0 + index * 24 + animatedX).toInt() + val topY = (entityScreenPosition.y + 16.0 + channelAnimation.shownAnimation.animatedValue).toInt() + val progressY = (entityScreenPosition.y + (1 - channelProgress) * 16.0 + channelAnimation.shownAnimation.animatedValue).toInt() + val bottomY = (entityScreenPosition.y + (1 - channelProgress).coerceIn(.0, 1.0) * 16.0 + channelAnimation.shownAnimation.animatedValue).toInt() + val topOfBar = (entityScreenPosition.y + .0 + channelAnimation.shownAnimation.animatedValue).toInt() + + // Background (unfilled) bar: from the animated top down to the progress line. + drawContext.fill(minX, bottomY, maxX, topOfBar, color.toInt()) + // Progress (filled) bar: from the fixed bottom up to the progress line. + drawContext.fill(minX, topY, maxX, progressY, progressColor.toInt()) + + if (channelAnimation.magic == SculkCatalystMagic && + channelAnimation.currentChannelTime < channelAnimation.channelTime ) { SculkCatalystEffectRenderer.entity = entity CollapseEffectRenderer.dissolveFactor.value = channelProgress / 4.0 } } - - RenderSystem.disableBlend() - matrixStack.pop() - matrixStack.pop() - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) } - private fun renderRectangle( - buffer: VertexConsumer, - positionMatrix: Matrix4f?, - rectangle: Rectangle, - color: Color, - light: Int, - z: Float = 0.01f, - ) { - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.min.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.max.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) - buffer.vertex(positionMatrix, rectangle.min.x.toFloat(), rectangle.max.y.toFloat(), z).color(color.toInt()) + private fun onEntityTick(entity: LivingEntity) { + if (!entity.level().isClientSide) { + return + } + val channelAnimation = channelSequenceAnimationMap[entity] ?: return + val removed = channelAnimation.removeIf { it.currentChannelTime > it.channelTime && it.opacityAnimation.animatedValue == 0.0 } + if (removed) { + offsetAnimationMap[entity]?.xOffsetAnimationClock?.apply { + from = .0 + to = .0 + } + } + channelAnimation + .firstOrNull { it.currentChannelTime <= it.channelTime } + ?.tick(entity) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/GuideLineRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/GuideLineRenderer.kt new file mode 100644 index 00000000..68b9c950 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/GuideLineRenderer.kt @@ -0,0 +1,337 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client.render + +import com.mojang.blaze3d.GpuFormat +import com.mojang.blaze3d.PrimitiveTopology +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.buffers.GpuBufferSlice +import com.mojang.blaze3d.buffers.Std140Builder +import com.mojang.blaze3d.pipeline.BindGroupLayout +import com.mojang.blaze3d.pipeline.ColorTargetState +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.pipeline.TextureTarget +import com.mojang.blaze3d.shaders.UniformType +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.projectionMatrix +import heckerpowered.matrix.core.FramebufferExtension +import net.minecraft.util.ARGB +import net.minecraft.world.phys.Vec3 +import org.joml.Matrix4f +import org.joml.Quaternionf +import org.joml.Vector3f +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.Optional +import java.util.OptionalDouble + +/** + * The aim-assist guide lines restored from 1.21's MatrixHud.renderCandidateEntities: world-space + * lines from the player's chest to the targeted entity (green), then chained through the + * aim-assist candidates (red), submitted in view space (camera-built matrix, CPU near-clip) + * under the captured projectionMatrix, and drawn with depth test off so they stay visible + * through walls. + * + * Mechanism mirrors the 1.21 original exactly (baseline renderCandidateEntities): DEBUG_LINES + * with POSITION_COLOR — plain hardware 1px line rasterization, no width-quad expansion. The + * expansion variant's screen-direction sign-flip degenerated view-dependently (segments + * vanished/kinked at near-vertical angles), which hardware lines are immune to. + * + * The 1.21 pass drew with RenderSystem.setShaderColor(8,8,8,1) into the (then HDR) + * hudFramebuffer, whose composite showed the lines over the backdrop blur and whose HDR copy + * fed the HUD bloom. On 26.2 the same list is drawn twice: into the captured HUD framebuffer + * at capture time ([renderToCapturedHud], where the 8x clamps exactly like the 1.21 HDR values + * did on their way to the screen) and into an RGBA16F overlay whose unclamped 8x energy + * [heckerpowered.matrix.client.render.post.BloomEffect] adds into the HUD brightness pass. + */ +object GuideLineRenderer { + /** Vanilla near plane is 0.05; clip a hair beyond it so rasterization stays well-conditioned. */ + private const val NEAR_CLIP = 0.06F + + /** POSITION_COLOR: 3 floats + 4 unsigned bytes. */ + private const val VERTEX_SIZE = 16 + + /** The 1.21 RenderSystem.setShaderColor(8,8,8,1) overbright multiplier. */ + private const val INTENSITY = 8.0F + + private class Segment( + val x1: Float, val y1: Float, val z1: Float, + val x2: Float, val y2: Float, val z2: Float, + val color: Int, + ) + + private val segments = mutableListOf() + + /** + * True while the overlay target holds this frame's 8x line draw; gates the bloom feed so a + * stale overlay is never composited (the overlay is neither cleared nor drawn on line-free + * frames). + */ + var overlayActive = false + private set + + /** HDR bloom feed: the 8x overbright copy of the lines, added into BloomEffect's bright pass. */ + val overlayFramebuffer: RenderTarget by lazy { + TextureTarget( + "matrix guide line overlay", + minecraft.window.width, + minecraft.window.height, + false, + FramebufferExtension.framebufferColorFormat + ).also(PostProcessRenderer::manageFramebuffer) + } + + /** + * Compiles both target-format pipeline variants against the ShaderManager sources; used + * by the load-test probe so the shader cross-compilation is exercised on both backends + * without needing an in-game aim target. + */ + fun precompile() { + val device = RenderSystem.getDevice() + for (format in arrayOf(GpuFormat.RGBA8_UNORM, FramebufferExtension.framebufferColorFormat)) { + device.precompilePipeline(pipeline(format)) { id, type -> + minecraft.shaderManager.getShader(id, type) + } + } + } + + fun clear() { + segments.clear() + } + + /** Records a segment during HUD extraction; positions are extraction-time lerped world coordinates. */ + fun addLine(from: Vec3, to: Vec3, color: Int) { + segments.add( + Segment( + from.x.toFloat(), from.y.toFloat(), from.z.toFloat(), + to.x.toFloat(), to.y.toFloat(), to.z.toFloat(), + color + ) + ) + } + + private val pipelines = mutableMapOf() + + private fun pipeline(format: GpuFormat): RenderPipeline = pipelines.getOrPut(format) { + RenderPipeline.builder() + .withLocation(Matrix.identifier("pipeline/guide_line_${format.name.lowercase()}")) + .withVertexShader(Matrix.identifier("core/guide_line")) + .withFragmentShader(Matrix.identifier("core/guide_line")) + .withVertexBinding(0, DefaultVertexFormat.POSITION_COLOR) + // DEBUG_LINES = real GPU line-list rasterization (the 1.21 mechanism); LINES is + // vanilla's width-quad expansion variant whose GPU primitives are TRIANGLES — + // a non-indexed 2-vertex-per-segment draw renders nothing under it. + .withPrimitiveTopology(PrimitiveTopology.DEBUG_LINES) + .withCull(false) + // 1.21 state: depth test off (lines visible through walls), blend off — no + // depth-stencil state and no blend function baked into the pipeline. + .withDepthStencilState(Optional.empty()) + .withColorTargetState(ColorTargetState(Optional.empty(), format, ColorTargetState.WRITE_ALL)) + .withBindGroupLayout( + BindGroupLayout.builder() + .withUniform("GuideLineTransform", UniformType.UNIFORM_BUFFER) + .build() + ) + .build() + } + + private var vertexBuffer: GpuBuffer? = null + + private fun uploadVertices(data: ByteBuffer): GpuBufferSlice { + val size = data.remaining().toLong() + var buffer = vertexBuffer + if (buffer == null || buffer.size() < size) { + // Growth only ever replaces a buffer whose last GPU use was a previous frame. + buffer?.close() + buffer = RenderSystem.getDevice().createBuffer( + { "matrix guide line vertices" }, + GpuBuffer.USAGE_VERTEX or GpuBuffer.USAGE_COPY_DST, + size + ) + vertexBuffer = buffer + } + val slice = buffer.slice(0, size) + RenderSystem.getDevice().createCommandEncoder().writeToBuffer(slice, data) + return slice + } + + /** Ring of UBO slots — the block is written twice per frame (main + overlay draw). */ + private val uniformBuffer: GpuBuffer by lazy { + RenderSystem.getDevice().createBuffer( + { "matrix guide line uniforms" }, + GpuBuffer.USAGE_UNIFORM or GpuBuffer.USAGE_COPY_DST, + UNIFORM_SLOT_SIZE * UNIFORM_SLOTS + ) + } + private var uniformCursor = 0 + + private const val UNIFORM_SLOT_SIZE = 256L + private const val UNIFORM_SLOTS = 16 + + private fun writeUniform(target: RenderTarget, intensity: Float): GpuBufferSlice { + // Vertices are submitted in VIEW space (camera-relative, near-clipped on the CPU in + // render()), so the shader's ViewProjMat is the projection alone. + val data = ByteBuffer.allocateDirect(UNIFORM_SLOT_SIZE.toInt()).order(ByteOrder.nativeOrder()) + val written = Std140Builder.intoBuffer(data) + .putMat4f(projectionMatrix) + .putVec4(target.width.toFloat(), target.height.toFloat(), intensity, 0.0F) + .get() + val slice = uniformBuffer.slice(UNIFORM_SLOT_SIZE * uniformCursor, UNIFORM_SLOT_SIZE) + uniformCursor = (uniformCursor + 1) % UNIFORM_SLOTS + RenderSystem.getDevice().createCommandEncoder().writeToBuffer(slice, written) + return slice + } + + /** + * Draws the extracted line list. Called from GameRendererMixin.beginRender right AFTER + * PostProcessRenderer.renderToMinecraftFramebuffer(), matching 1.21's InGameHud-time draw: + * the lines stay fully colored while the slow-time grayscale desaturates the world. + */ + @JvmStatic + fun render() { + overlayActive = false + pendingVertices = null + // Hud.isHidden (F1) suppressed the whole 1.21 HUD callback, lines included; the extracted + // list can be stale on hidden-HUD frames because extraction is skipped, so gate here too. + if (segments.isEmpty() || minecraft.gui.hud.isHidden) { + return + } + + // Vertices go through the pipeline in VIEW space, near-clipped here on the CPU. The + // 1.21 draw was plain GL_LINES whose hardware clip handled the chest-anchored start + // vertex sitting AT the camera plane; the 26.2 width-quad expansion divides by w in + // the vertex shader instead, so an unclipped w≈0 endpoint turns into NaN/flipped NDC + // (invisible segments at best, the full-screen tangle at worst). Clipping against the + // near plane before submission restores the hardware-clip visuals — and camera- + // relative coordinates dodge the float precision loss of far-from-origin worlds. + val camera = minecraft.gameRenderer.mainCamera() + val view = Matrix4f() + .rotate(camera.rotation().conjugate(Quaternionf())) + .translate( + -camera.position().x.toFloat(), + -camera.position().y.toFloat(), + -camera.position().z.toFloat(), + ) + val p1 = Vector3f() + val p2 = Vector3f() + + // Plain POSITION_COLOR line-list vertices (two per segment, no duplication): the + // 1.21 draw was DEBUG_LINES through Tessellator — hardware line rasterization. + val data = stagingBuffer(VERTEX_SIZE * segments.size * 2) + for (segment in segments) { + view.transformPosition(segment.x1, segment.y1, segment.z1, p1) + view.transformPosition(segment.x2, segment.y2, segment.z2, p2) + // View space looks down -z; keep only the part beyond the near plane. The clip + // parameter is clamped and the results finite-checked: during fast camera turns + // a segment can sweep THROUGH the camera plane within one frame, and a near-zero + // denominator would fling a vertex toward infinity — one giant 8x streak through + // the bloom chain reads as a full-screen white flash. + if (p1.z > -NEAR_CLIP && p2.z > -NEAR_CLIP) { + continue + } + if (p1.z > -NEAR_CLIP) { + p1.lerp(p2, ((-NEAR_CLIP - p1.z) / (p2.z - p1.z)).coerceIn(0F, 1F)) + } else if (p2.z > -NEAR_CLIP) { + p2.lerp(p1, ((-NEAR_CLIP - p2.z) / (p1.z - p2.z)).coerceIn(0F, 1F)) + } + if (!p1.isFinite || !p2.isFinite) { + continue + } + putVertex(data, p1, segment.color) + putVertex(data, p2, segment.color) + } + data.flip() + if (!data.hasRemaining()) { + return + } + + val vertices = uploadVertices(data) + val vertexCount = data.limit() / VERTEX_SIZE + + // Only the HDR bloom feed is drawn here. The VISIBLE lines were 1.21 HUD content + // (drawn while hudFramebuffer was bound, composited OVER the list's backdrop blur), + // so they join the capture in renderToCapturedHud instead — a main-target draw at + // this point would sit UNDER the backdrop blur and come out dark and smeared + // whenever the magic list is open. + PostProcessRenderer.clear(overlayFramebuffer) + drawTo(overlayFramebuffer, vertices, vertexCount) + overlayActive = true + + pendingVertices = vertices + pendingVertexCount = vertexCount + } + + private fun putVertex(data: ByteBuffer, position: Vector3f, color: Int) { + data.putFloat(position.x).putFloat(position.y).putFloat(position.z) + // POSITION_COLOR stores RGBA unsigned bytes; the segment color is ARGB. + data.put(ARGB.red(color).toByte()) + .put(ARGB.green(color).toByte()) + .put(ARGB.blue(color).toByte()) + .put(ARGB.alpha(color).toByte()) + } + + /** CPU staging for the per-frame vertex pack; grown on demand, reused across frames. */ + private var staging: ByteBuffer? = null + + private fun stagingBuffer(capacity: Int): ByteBuffer { + val buffer = staging?.takeIf { it.capacity() >= capacity } + ?: ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder()).also { staging = it } + return buffer.clear() + } + + private var pendingVertices: GpuBufferSlice? = null + private var pendingVertexCount = 0 + + /** + * Draws this frame's line list into the captured HUD framebuffer — called from + * MatrixHud.onHudCaptureBegin (after the capture clear, before the HUD stratum renders), + * restoring the 1.21 layer order: lines above the backdrop blur, below the list panels. + * Like 1.21 (where the lines lived in hudFramebuffer), they are only visible on frames + * where the HUD composite actually runs. + */ + @JvmStatic + fun renderToCapturedHud(target: RenderTarget) { + val vertices = pendingVertices ?: return + drawTo(target, vertices, pendingVertexCount) + } + + private fun drawTo( + target: RenderTarget, + vertices: GpuBufferSlice, + vertexCount: Int, + ) { + val colorView = target.colorTextureView ?: return + val device = RenderSystem.getDevice() + val pipeline = pipeline(target.colorTexture?.format ?: GpuFormat.RGBA8_UNORM) + // Same lazy compile as BlitProgram: mod pipelines are unknown to the device's default + // shader source, so compile against the ShaderManager-loaded sources (cached lookup). + device.precompilePipeline(pipeline) { id, type -> + minecraft.shaderManager.getShader(id, type) + } + + // The captured HUD target's 8x clamps to the same values the 1.21 HDR draw showed on + // screen; the overlay keeps them unclamped for the bloom feed. + val uniformSlice = writeUniform(target, INTENSITY) + + device.createCommandEncoder().createRenderPass( + { "matrix guide lines" }, + colorView, + Optional.empty(), + null, + OptionalDouble.empty() + ).use { pass -> + pass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(pass) + pass.setUniform("GuideLineTransform", uniformSlice) + pass.setVertexBuffer(0, vertices) + pass.draw(vertexCount, 1, 0, 0) + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt index 387682e8..e69ca840 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/LegacyMatrixUIRenderer.kt @@ -5,91 +5,58 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.systems.RenderSystem -import net.minecraft.client.MinecraftClient -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.text.Text +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component import kotlin.math.max import kotlin.math.min - -@Deprecated("Deprecated") -class MatrixHUDRenderer(val drawContext: DrawContext, val tickCounter: RenderTickCounter) { - fun enableScissor(rectangle: Rectangle) { - drawContext.enableScissor( - rectangle.min.x.toInt(), - rectangle.min.y.toInt(), - rectangle.max.x.toInt(), - rectangle.max.y.toInt() - ) - } - - fun disableScissor() { - drawContext.disableScissor() - } - - fun renderRectangle(rectangle: Rectangle, color: Color) { - drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - - tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - } -} - +import kotlin.math.roundToInt + +// 26.2 note: this file's `MatrixHUDRenderer` companion class is dropped — it was unreferenced +// anywhere else in the codebase (only its own definition), and its only real method +// (renderRectangle) never issued a draw call even in the pre-port version (it built a +// BufferBuilder and discarded it without calling BufferRenderer.draw), so it was already dead +// code before this port. `enableScissor`/`disableScissor` are one-line GuiGraphicsExtractor +// passthroughs with no logic of their own to preserve; if a future caller needs them they can +// be called on GuiGraphicsExtractor directly (`drawContext.enableScissor(...)`). +// +// `LegacyMatrixUIRenderer` itself IS referenced (ManaBar.kt, AvailableStatusTooltip.kt, +// MatrixHud.kt — all out of scope for this render-port pass) for `renderRectangle`, +// `render` (text), `scaledWindowWidth`/`scaledWindowHeight`. Its old +// `VertexConsumerProvider.Immediate`-based implementation (build a quad into a buffer, then +// `vertexConsumers.draw()`) has no equivalent: immediate-mode VertexConsumerProvider is gone in +// 26.2. It is rewritten to draw directly via `GuiGraphicsExtractor.fill()`/`text()` (which +// SystemCrashBar.kt's own port already established as the replacement pattern for this exact +// situation — see the comment above `SystemCrashBar.renderRectangle`), preserving the same +// rectangles/text/colors. +// +// The constructor changes from `LegacyMatrixUIRenderer(vertexConsumers)` to +// `LegacyMatrixUIRenderer(drawContext)` since there is no standalone VertexConsumerProvider to +// hold onto anymore — every draw needs the GuiGraphicsExtractor. Call sites in MatrixHud.kt +// (`LegacyMatrixUIRenderer(drawContext.vertexConsumers)`, 3 occurrences) need to change to +// `LegacyMatrixUIRenderer(drawContext)` to match; left as-is here since MatrixHud.kt is out of +// scope for this pass. @Deprecated("Deprecated") -class LegacyMatrixUIRenderer(private val vertexConsumers: VertexConsumerProvider.Immediate) { - private val minecraft = MinecraftClient.getInstance() - private val matrixStack = MatrixStack() - private val textRenderer = minecraft.textRenderer +class LegacyMatrixUIRenderer(private val drawContext: GuiGraphicsExtractor) { + private val minecraft = Minecraft.getInstance() + private val textRenderer = minecraft.font val scaledWindowWidth: Int - get() = minecraft.window.scaledWidth + get() = drawContext.guiWidth() val scaledWindowHeight: Int - get() = minecraft.window.scaledHeight - - private fun renderOnLayer(layer: RenderLayer, rectangle: Rectangle, color: Color) { - val maxX = max(rectangle.min.x, rectangle.max.x) - val maxY = max(rectangle.min.y, rectangle.max.y) - - val minX = min(rectangle.min.x, rectangle.max.x) - val minY = min(rectangle.min.y, rectangle.max.y) - - val vertexConsumer = vertexConsumers.getBuffer(layer) - val matrix = matrixStack.peek().positionMatrix - vertexConsumer.vertex(matrix, maxX.toFloat(), maxY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, maxX.toFloat(), minY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, minX.toFloat(), minY.toFloat(), 0f).color(color.toInt()) - vertexConsumer.vertex(matrix, minX.toFloat(), maxY.toFloat(), 0f).color(color.toInt()) - - render() - } - - private fun render() { - RenderSystem.disableDepthTest() - vertexConsumers.draw() - RenderSystem.enableDepthTest() - } + get() = drawContext.guiHeight() fun renderRectangle(rectangle: Rectangle, color: Color) { - renderOnLayer(RenderLayer.getGui(), rectangle, color) + val maxX = max(rectangle.min.x, rectangle.max.x).roundToInt() + val maxY = max(rectangle.min.y, rectangle.max.y).roundToInt() + val minX = min(rectangle.min.x, rectangle.max.x).roundToInt() + val minY = min(rectangle.min.y, rectangle.max.y).roundToInt() + + drawContext.fill(minX, minY, maxX, maxY, color.toInt()) } - fun render(text: Text, point: Point, color: Color, shadow: Boolean = false) { - textRenderer.draw( - text, - point.x.toFloat(), - point.y.toFloat(), - color.toInt(), - shadow, - matrixStack.peek().positionMatrix, - vertexConsumers, - TextRenderer.TextLayerType.NORMAL, - 0, - 0xF000F0 - ) - render() + fun render(text: Component, point: Point, color: Color, shadow: Boolean = false) { + drawContext.text(textRenderer, text, point.x.roundToInt(), point.y.roundToInt(), color.toInt(), shadow) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt index 6feeb58e..8c5b7e87 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MatrixRenderSystem.kt @@ -6,13 +6,11 @@ package heckerpowered.matrix.client.render import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.render.OpenGLExtensions.getErrorName -import heckerpowered.matrix.core.math.Vector3fExtensions.unaryMinus -import net.minecraft.client.render.Camera +import heckerpowered.matrix.core.math.unaryMinus +import net.minecraft.client.Camera import org.joml.Matrix4f import org.joml.Matrix4fc import org.joml.Quaternionf -import org.lwjgl.opengl.GL46.* object MatrixRenderSystem { var projectionMatrix = Matrix4f() @@ -26,8 +24,8 @@ object MatrixRenderSystem { fun setupMatrix(camera: Camera, projectionMatrix: Matrix4fc) { this.projectionMatrix = Matrix4f(projectionMatrix) - val rotation = camera.rotation.conjugate(Quaternionf()) - val translation = -camera.pos.toVector3f() + val rotation = camera.rotation().conjugate(Quaternionf()) + val translation = -camera.position().toVector3f() viewMatrix.identity() .rotate(rotation) @@ -36,27 +34,12 @@ object MatrixRenderSystem { viewProjectionMatrix.identity().mul(projectionMatrix).mul(viewMatrix) projectionMatrix.invert(inverseProjectionMatrix) inverseViewMatrix.identity() - .translate(camera.pos.toVector3f()) - .rotate(camera.rotation) + .translate(camera.position().toVector3f()) + .rotate(camera.rotation()) viewProjectionMatrix.invert(inverseViewProjectionMatrix) } fun assertOnRenderThread() { RenderSystem.assertOnRenderThread() } - - fun createShader(type: Int): Int { - assertOnRenderThread() - val shader = glCreateShader(type) - if (shader != 0) { - return shader - } - - val error = glGetError() - if (error == GL_INVALID_ENUM) { - error("GL_INVALID_ENUM: shaderType $type is not an accepted value.") - } - val errorName = getErrorName(error) - error("$errorName: shaderType: $type") - } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt index f7f9e822..09d9746b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/MipmapsFramebuffer.kt @@ -5,21 +5,145 @@ package heckerpowered.matrix.client.render -import net.minecraft.client.gl.SimpleFramebuffer -import org.lwjgl.opengl.GL46.* +import com.mojang.blaze3d.GpuFormat +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTexture +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.core.FramebufferExtension +import org.joml.Vector4f +import org.joml.Vector4fc +import java.util.Optional +import java.util.OptionalDouble + +/** + * A [RenderTarget] whose color attachment owns a full mipmap chain, and which can be pointed + * at an individual level via [levelOfDetail] for both rendering and sampling. + * + * 26.2 note: [RenderTarget.createBuffers] normally allocates a single-level `RGBA8_UNORM` + * color texture (and a `D32_FLOAT` depth texture) via [com.mojang.blaze3d.systems.GpuDevice]. + * There is no `initFbo`/`glTexImage2D`/`glGenerateMipmap` left to intercept, so this class + * overrides [createBuffers] directly: it allocates the color texture with + * [recommendMipLevel] levels and [FramebufferExtension.framebufferColorFormat], then creates + * one single-level [GpuTextureView] per mip so [levelOfDetail] can retarget + * [colorTextureView] (the field every draw/sample path in the wrapper API reads). + * + * GPU-side mip regeneration (the old `glGenerateMipmap`) has no wrapper equivalent — see the + * `TODO(26.2)` below. Levels above 0 stay whatever a caller last rendered into them. + */ +open class MipmapsFramebuffer(label: String, width: Int, height: Int, useDepth: Boolean) : + RenderTarget(label, useDepth, FramebufferExtension.framebufferColorFormat) { + /** One single-level view per mip, index = mip level. Rebuilt in [createBuffers]. */ + private var mipViews: Array = emptyArray() -class MipmapsFramebuffer(width: Int, height: Int, useDepth: Boolean = false, getError: Boolean = true) : SimpleFramebuffer(width, height, useDepth, getError) { init { - glGenerateMipmap(fbo) + resize(width, height) + } + + @Suppress("NAME_SHADOWING") + override fun createBuffers(width: Int, height: Int) { + RenderSystem.assertOnRenderThread() + + // Callers may resize before the window dimensions are known (e.g. static init); + // the wrapper API rejects 0-sized textures, so clamp like the vanilla targets do. + val width = width.coerceAtLeast(1) + val height = height.coerceAtLeast(1) + + val device = RenderSystem.getDevice() + // recommendMipLevel's bit trick yields 0 for a 1x1 texture; the wrapper requires >= 1. + val mipLevels = recommendMipLevel(width, height).coerceAtLeast(1) + + if (useDepth) { + val depth = device.createTexture( + { "$label depth texture" }, + GpuTexture.USAGE_RENDER_ATTACHMENT or GpuTexture.USAGE_TEXTURE_BINDING + or GpuTexture.USAGE_COPY_DST or GpuTexture.USAGE_COPY_SRC, + GpuFormat.D32_FLOAT, width, height, 1, 1 + ) + depthTexture = depth + depthTextureView = device.createTextureView(depth) + } + + val color = device.createTexture( + { "$label color texture" }, + GpuTexture.USAGE_COPY_DST or GpuTexture.USAGE_COPY_SRC or GpuTexture.USAGE_TEXTURE_BINDING or GpuTexture.USAGE_RENDER_ATTACHMENT, + FramebufferExtension.framebufferColorFormat, width, height, 1, mipLevels + ) + colorTexture = color + + mipViews = Array(mipLevels) { level -> device.createTextureView(color, level, 1) } + colorTextureView = mipViews[0] + levelOfDetail = 0 } + /** + * The mip level currently exposed through [colorTextureView] (and therefore through every + * draw-to/sample-from path that reads it, matching the old begin/end-write/read-lod pair + * which repointed the same GL attachment). + */ var levelOfDetail: Int = 0 set(value) { - field = value - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorAttachment, value) + val clamped = value.coerceIn(0, mipViews.lastIndex.coerceAtLeast(0)) + field = clamped + if (mipViews.isNotEmpty()) { + colorTextureView = mipViews[clamped] + } + } + + /** + * The single-level [GpuTextureView] for [level], independent of [levelOfDetail]. + * + * Needed by callers (e.g. [heckerpowered.matrix.client.render.post.BloomEffect]'s upsample + * pass) that must read one mip level while [levelOfDetail] (and therefore [colorTextureView]) + * is pointed at a *different* level for writing — the old GL implementation aliased + * independent `GL_READ_FRAMEBUFFER`/`GL_DRAW_FRAMEBUFFER` attachment points onto the same + * texture object to achieve this; this is the wrapper-API equivalent for read-only sampling. + */ + fun viewAt(level: Int): GpuTextureView { + return mipViews[level.coerceIn(0, mipViews.lastIndex.coerceAtLeast(0))] + } + + /** + * Clears every mip level (and the depth attachment) to transparent black, restoring the + * baseline's per-level attach-then-clear loop: the 26.2 encoder clear calls only ever + * target mip 0 (GlTexture.fboMipLevel() is hardwired to 0), so levels >= 1 must be cleared + * through a load-op clear render pass on their single-level views instead. + */ + fun clearAllLevels() { + RenderSystem.assertOnRenderThread() + // Level 0 + depth take the same encoder path as every other target. + PostProcessRenderer.clear(this) + val encoder = RenderSystem.getDevice().createCommandEncoder() + for (level in 1 until mipViews.size) { + encoder.createRenderPass( + { "$label clear mip $level" }, + mipViews[level], + TRANSPARENT_CLEAR, + null, + OptionalDouble.empty() + ).close() + } + } + + private companion object { + val TRANSPARENT_CLEAR: Optional = Optional.of(Vector4f(0F, 0F, 0F, 0F)) + } - viewportWidth = textureWidth shr value - viewportHeight = textureHeight shr value - glViewport(0, 0, viewportWidth, viewportHeight) + override fun destroyBuffers() { + // Vanilla destroyBuffers only closes colorTexture/colorTextureView/depth*; without + // this the per-mip views (all but the one aliased by colorTextureView) leak on every + // resize. GlTextureView.close() is idempotent, so the aliased view closing again in + // super is harmless. + for (view in mipViews) { + view.close() } -} \ No newline at end of file + mipViews = emptyArray() + super.destroyBuffers() + } + + // TODO(26.2): there is no GpuDevice/CommandEncoder call that regenerates a mip chain from + // level 0 (the old `glGenerateMipmap(fbo)` in this class's init, and the box-filter downsample + // callers used to do manually via BloomEffect's per-level render passes still works exactly + // as before since it renders explicitly into each mip's GpuTextureView -- only *automatic* + // GPU-side mipmap generation from a single base-level write has no wrapper equivalent). +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt index 31473a04..f1862623 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/PostProcessRenderer.kt @@ -5,24 +5,20 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.GpuFormat +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.pipeline.TextureTarget import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.event.PostProcessCallback import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gl.Framebuffer -import net.minecraft.client.gl.SimpleFramebuffer -import org.lwjgl.opengl.GL31 -import org.lwjgl.opengl.GL46 +import heckerpowered.matrix.core.FramebufferExtension +import org.joml.Vector4f -val framebufferProvider: UniformProvider +val framebufferProvider: TextureProvider get() = PostProcessRenderer.framebufferProvider object PostProcessRenderer { @@ -30,64 +26,95 @@ object PostProcessRenderer { /** * The source framebuffer to render the post process effects from. + * Defaults to the main render target; resolved lazily because the game renderer + * does not exist yet while mods are being initialized. */ - var sourceFramebuffer = minecraft.framebuffer - private var boundFramebuffer = minecraft.framebuffer + var sourceFramebuffer: RenderTarget + get() = sourceFramebufferOverride ?: minecraft.mainRenderTarget + set(value) { + sourceFramebufferOverride = value + } + private var sourceFramebufferOverride: RenderTarget? = null + + private var boundFramebuffer: RenderTarget + get() = boundFramebufferOverride ?: minecraft.mainRenderTarget + set(value) { + boundFramebufferOverride = value + } + private var boundFramebufferOverride: RenderTarget? = null - val framebufferProvider = UniformProvider("framebuffer") { pointer -> - GL31.glActiveTexture(GlConst.GL_TEXTURE0) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, boundFramebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 0) + /** + * The previous pass' output, exposed to every post shader through the `framebuffer` sampler. + * Replaces the former glActiveTexture/glBindTexture uniform provider. + */ + val framebufferProvider = TextureProvider("framebuffer", bilinear = false, mipmap = false) { + boundFramebuffer.colorTextureView } var useDepthAttachment = false - private val depthAttachmentProvider = UniformProvider("depthAttachment") { pointer -> - if (pointer == -1 || !boundFramebuffer.useDepthAttachment || !useDepthAttachment) { - return@UniformProvider - } - - GL31.glActiveTexture(GlConst.GL_TEXTURE0 + 1) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, boundFramebuffer.depthAttachment) - RenderSystem.glUniform1i(pointer, 1) + private val depthAttachmentProvider = TextureProvider("depthAttachment") { + if (boundFramebuffer.useDepth && useDepthAttachment) boundFramebuffer.depthTextureView else null } var levelOfDetail = .0F - private val levelOfDetailProvider = UniformProvider("lod") { pointer -> - if (pointer == -1) { - return@UniformProvider - } - - GL46.glUniform1f(pointer, levelOfDetail) + private val levelOfDetailProvider = UniformProvider("BlitConfig") { + putFloat(levelOfDetail) } private val blitShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL46.GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blit/blit.fsh", GL46.GL_FRAGMENT_SHADER), - uniforms = arrayOf(framebufferProvider, depthAttachmentProvider, levelOfDetailProvider) + "blit/blit.fsh", + uniforms = arrayOf(levelOfDetailProvider), + textures = arrayOf(framebufferProvider, depthAttachmentProvider), + writesDepth = true ) } private val blitNoDepthShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL46.GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blit/blit_no_depth.fsh", GL46.GL_FRAGMENT_SHADER), - uniforms = arrayOf(framebufferProvider, levelOfDetailProvider) + "blit/blit_no_depth.fsh", + uniforms = arrayOf(levelOfDetailProvider), + textures = arrayOf(framebufferProvider) + ) + } + + /** + * The 1.21 vanilla `Framebuffer.draw` equivalent: samples and blends every pixel, black + * included — no discard. The HUD composite steps that used vanilla draw pre-migration + * (hud-over-backdrop, blur-layer-to-main) must NOT go through the discarding blit, or + * pure-black panel fills and shadow rgb silently vanish from the composite. + */ + private val blitDrawShader by lazy { + BlitProgram( + "blit/blit_replace.fsh", + uniforms = arrayOf(levelOfDetailProvider), + textures = arrayOf(framebufferProvider) ) } - private val managedFramebuffers = mutableListOf() - private val framebuffers = mutableListOf(createFramebuffer(), createFramebuffer()) + /** Draws [from] over [to] like 1.21's vanilla Framebuffer.draw: blended, never discarding. */ + @JvmStatic + fun drawFramebuffer(from: RenderTarget, to: RenderTarget, blend: BlendFunction?) { + val previousBound = boundFramebuffer + boundFramebuffer = from + blitDrawShader.drawTo(to, blend) + boundFramebuffer = previousBound + } + + private val managedFramebuffers = mutableListOf() + private val framebuffers by lazy { + mutableListOf(createFramebuffer("matrix post ping"), createFramebuffer("matrix post pong")) + } private var currentFramebufferIndex = 0 - fun currentFramebuffer(): Framebuffer { + fun currentFramebuffer(): RenderTarget { return framebuffers[currentFramebufferIndex] } - val ping: Framebuffer + val ping: RenderTarget get() = framebuffers[0] - val pong: Framebuffer + val pong: RenderTarget get() = framebuffers[1] fun nextFramebuffer() { @@ -97,40 +124,45 @@ object PostProcessRenderer { } } - private fun createFramebuffer(): Framebuffer { - val framebuffer = SimpleFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, + private fun createFramebuffer(label: String): RenderTarget { + // 26.2 release: the color format moved into the constructor; the pre-migration + // buffers were HDR through the framebuffer mixin's format override, so pass the + // same format explicitly here. + return TextureTarget( + label, + minecraft.window.width, + minecraft.window.height, true, - MinecraftClient.IS_SYSTEM_MAC + FramebufferExtension.framebufferColorFormat ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) - return framebuffer } - fun createManagedFramebuffer(): Framebuffer { - val framebuffer = SimpleFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, + fun createManagedFramebuffer(): RenderTarget { + // Managed framebuffers capture VANILLA rendering (entities/GUI via the output + // overrides); 26.2 release validates attachment formats against the vanilla + // pipelines' declared RGBA8 output, so these cannot be HDR. + val framebuffer = TextureTarget( + "matrix post managed", + minecraft.window.width, + minecraft.window.height, true, - MinecraftClient.IS_SYSTEM_MAC + GpuFormat.RGBA8_UNORM ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) managedFramebuffers.add(framebuffer) return framebuffer } - fun manageFramebuffer(framebuffer: Framebuffer) { + fun manageFramebuffer(framebuffer: RenderTarget) { managedFramebuffers.add(framebuffer) } @JvmStatic fun onResize(width: Int, height: Int) { for (framebuffer in framebuffers) { - framebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) + framebuffer.resize(width, height) } for (framebuffer in managedFramebuffers) { - framebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) + framebuffer.resize(width, height) } } @@ -144,21 +176,31 @@ object PostProcessRenderer { renderFramebufferToScreen(renderedFramebuffer) } - fun resetFramebuffers() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - currentFramebufferIndex = 0 - framebuffers.forEach { it.clear(MinecraftClient.IS_SYSTEM_MAC) } + /** Clears a framebuffer to transparent black (the previous setClearColor(0,0,0,0) semantics). */ + @JvmStatic + fun clear(framebuffer: RenderTarget) { + val encoder = RenderSystem.getDevice().createCommandEncoder() + val color = framebuffer.colorTexture ?: return + val depth = framebuffer.depthTexture + val transparentBlack = Vector4f(0F, 0F, 0F, 0F) + if (framebuffer.useDepth && depth != null) { + encoder.clearColorAndDepthTextures(color, transparentBlack, depth, 1.0) + } else { + encoder.clearColorTexture(color, transparentBlack) } } + fun resetFramebuffers() { + currentFramebufferIndex = 0 + framebuffers.forEach(::clear) + } + fun clearFramebuffers() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - framebuffers.forEach { it.clear(MinecraftClient.IS_SYSTEM_MAC) } - } + framebuffers.forEach(::clear) } @JvmStatic - fun renderToFramebuffer(framebuffer: Framebuffer) { + fun renderToFramebuffer(framebuffer: RenderTarget) { if (postProcessShaders.isEmpty()) { return } @@ -168,47 +210,34 @@ object PostProcessRenderer { } @JvmStatic - fun renderPostProcessEffects(): Framebuffer { + fun renderPostProcessEffects(): RenderTarget { return renderShaders(postProcessShaders) } @JvmStatic fun renderToMinecraftFramebuffer() { - renderToFramebuffer(minecraft.framebuffer) + renderToFramebuffer(minecraft.mainRenderTarget) PostProcessCallback.EVENT.invoker().onPostProcess() } @JvmStatic - fun renderFramebufferToScreen(framebuffer: Framebuffer, disableBlend: Boolean = false) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - - framebuffer.endWrite() - framebuffer.draw(minecraft.window.framebufferWidth, minecraft.window.framebufferHeight, disableBlend) - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) + @JvmOverloads + fun renderFramebufferToScreen(framebuffer: RenderTarget, disableBlend: Boolean = false) { + boundFramebuffer = framebuffer + blitNoDepthShader.drawTo( + minecraft.mainRenderTarget, + blend = if (disableBlend) null else BlendFunction.TRANSLUCENT + ) } @JvmStatic - fun renderShaderToFramebuffer(shader: BlitProgram, framebuffer: Framebuffer, disableBlend: Boolean = true) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - - framebuffer.beginWrite(true) - if (disableBlend) { - shader.blit() - } else { - shader.enableShader() - BlitProgram.blit() - shader.disableShader() - } - framebuffer.endWrite() - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) + @JvmOverloads + fun renderShaderToFramebuffer(shader: BlitProgram, framebuffer: RenderTarget, blend: BlendFunction? = null) { + shader.drawTo(framebuffer, blend) } @JvmStatic - fun renderShaders(shaders: Collection): Framebuffer { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - + fun renderShaders(shaders: Collection): RenderTarget { resetFramebuffers() copyFramebuffer(sourceFramebuffer, currentFramebuffer()) boundFramebuffer = currentFramebuffer() @@ -217,42 +246,47 @@ object PostProcessRenderer { for (shader in shaders) { // Render shader to next framebuffer nextFramebuffer() - currentFramebuffer().beginWrite(false) - shader.blit() + shader.drawTo(currentFramebuffer()) // Bind the rendered framebuffer boundFramebuffer = currentFramebuffer() } - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) return boundFramebuffer } @JvmStatic - fun renderShadersToFramebuffer(shaders: Collection, framebuffer: Framebuffer) { + fun renderShadersToFramebuffer(shaders: Collection, framebuffer: RenderTarget) { val renderedFramebuffer = renderShaders(shaders) copyFramebuffer(renderedFramebuffer, framebuffer) } + /** + * Copies [from] into [to] with a fullscreen blit. + * + * @param blend `null` copies with blending disabled (the previous `disableBlend = true` + * default); pass [BlendFunction.ADDITIVE] for the former GL_ONE/GL_ONE + * additive composition call sites (NOT LIGHTNING, which is SRC_ALPHA/ONE). + */ @JvmStatic - fun copyFramebuffer(from: Framebuffer, to: Framebuffer, disableBlend: Boolean = true, copyDepth: Boolean = false) { + @JvmOverloads + fun copyFramebuffer(from: RenderTarget, to: RenderTarget, blend: BlendFunction? = null, copyDepth: Boolean = false) { + val previousBound = boundFramebuffer boundFramebuffer = from val shader = if (copyDepth) blitShader else blitNoDepthShader - renderShaderToFramebuffer(shader, to, disableBlend) + shader.drawTo(to, blend) + boundFramebuffer = previousBound } - fun useFramebuffer(framebuffer: Framebuffer, action: () -> Unit) { + fun useFramebuffer(framebuffer: RenderTarget, action: () -> Unit) { val previousFramebuffer = sourceFramebuffer sourceFramebuffer = framebuffer - val previousBoundFramebuffer = GlStateManager.getBoundFramebuffer() - currentFramebuffer().clear(false) - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousBoundFramebuffer) - + clear(currentFramebuffer()) copyFramebuffer(sourceFramebuffer, currentFramebuffer()) boundFramebuffer = currentFramebuffer() action() sourceFramebuffer = previousFramebuffer } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt index efbb5d56..861f70f9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/RenderExtensions.kt @@ -5,122 +5,136 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.platform.GlStateManager.Viewport +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.platform.NativeImage import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.gl.Framebuffer -import net.minecraft.client.texture.NativeImage +import net.minecraft.client.Minecraft import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* import java.io.File -fun Framebuffer.blit(target: Framebuffer, mask: Int, filter: Int) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo) - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target.fbo) - glBlitFramebuffer( - 0, 0, textureWidth, textureHeight, - 0, 0, target.textureWidth, target.textureHeight, - mask, filter - ) -} +/** + * The window-sized framebuffer everything is composed into; replaces the former + * `minecraft.framebuffer` accessor from the pre-26.2 mappings. + */ +val Minecraft.mainRenderTarget: RenderTarget + get() = gameRenderer.mainRenderTarget() + +/** Compatibility accessors matching the pre-26.2 Framebuffer field names. */ +val RenderTarget.textureWidth: Int + get() = width -private var primaryFramebuffer: Framebuffer? = null -private var secondaryFramebuffer: Framebuffer? = null +val RenderTarget.textureHeight: Int + get() = height + +private var primaryFramebuffer: RenderTarget? = null +private var secondaryFramebuffer: RenderTarget? = null var colorMultiplier = Vector4f(1.0F, 1.0F, 1.0F, 1.0F) + private val colorFusionShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/color_fusion.fsh", GL_FRAGMENT_SHADER), + "post/color_fusion.fsh", uniforms = arrayOf( - UniformProvider("primaryFramebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("secondaryFramebuffer") { pointer -> - val framebuffer = secondaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 1) - }, - UniformProvider("colorMultiplier") { pointer -> - glUniform4f(pointer, colorMultiplier.x, colorMultiplier.y, colorMultiplier.z, colorMultiplier.w) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = colorMultiplier + putVec4(colorMultiplier) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("primaryFramebuffer") { primaryFramebuffer?.colorTextureView }, + TextureProvider("secondaryFramebuffer") { secondaryFramebuffer?.colorTextureView } ) ) } private val blendScreenShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blend_screen.fsh", GL_FRAGMENT_SHADER), + "post/blend_screen.fsh", + textures = arrayOf( + TextureProvider("primaryFramebuffer") { primaryFramebuffer?.colorTextureView }, + TextureProvider("secondaryFramebuffer") { secondaryFramebuffer?.colorTextureView } + ) + ) +} + +val tentBlurShader by lazy { + BlitProgram( + "post/blur/tent.fsh", uniforms = arrayOf( - UniformProvider("primaryFramebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("secondaryFramebuffer") { pointer -> - val framebuffer = secondaryFramebuffer ?: return@UniformProvider - - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 1) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = lod + putVec4(PostProcessRenderer.levelOfDetail, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("framebuffer", bilinear = true, mipmap = true) { primaryFramebuffer?.colorTextureView } ) ) } -val tentBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("framebuffer") { pointer -> - val framebuffer = primaryFramebuffer ?: return@UniformProvider +// 1.21 semantics: linearCopyTo/nearestCopyTo were raw glBlitFramebuffer calls — a full +// REPLACE of every destination pixel, black/transparent included. blit_replace.fsh has no +// black-pixel discard (that discard in blit_no_depth.fsh is a compositing behavior); routing +// these copies through the discarding shader left stale destination content behind wherever +// the source was transparent — the source of the fullscreen acrylic-wash leak. +private val linearCopyShader by lazy { + BlitProgram( + "blit/blit_replace.fsh", + uniforms = arrayOf(UniformProvider("BlitConfig") { putFloat(0F) }), + textures = arrayOf(TextureProvider("framebuffer", bilinear = true) { primaryFramebuffer?.colorTextureView }) + ) +} - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 0) - }) -) +private val nearestCopyShader by lazy { + BlitProgram( + "blit/blit_replace.fsh", + uniforms = arrayOf(UniformProvider("BlitConfig") { putFloat(0F) }), + textures = arrayOf(TextureProvider("framebuffer", bilinear = false) { primaryFramebuffer?.colorTextureView }) + ) +} /** - * + * Blends this framebuffer with [other] through the color fusion shader into the current + * post-process target. Renders into the current framebuffer of [PostProcessRenderer]. */ -infix fun Framebuffer.blend(other: Framebuffer) { +infix fun RenderTarget.blend(other: RenderTarget) { primaryFramebuffer = this secondaryFramebuffer = other - colorFusionShader.blit() + colorFusionShader.drawTo(PostProcessRenderer.currentFramebuffer()) } -infix fun Framebuffer.blendScreen(other: Framebuffer) { +infix fun RenderTarget.blendScreen(other: RenderTarget) { primaryFramebuffer = this secondaryFramebuffer = other - blendScreenShader.blit() + blendScreenShader.drawTo(PostProcessRenderer.currentFramebuffer()) } -infix fun Framebuffer.copyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_LINEAR) +infix fun RenderTarget.copyTo(other: RenderTarget) { + primaryFramebuffer = this + linearCopyShader.drawTo(other) } -infix fun Framebuffer.copyDepthTo(other: Framebuffer) { - blit(other, GL_DEPTH_BUFFER_BIT, GL_LINEAR) +infix fun RenderTarget.copyDepthTo(other: RenderTarget) { + other.copyDepthFrom(this) } -infix fun Framebuffer.linearCopyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_LINEAR) +infix fun RenderTarget.linearCopyTo(other: RenderTarget) { + primaryFramebuffer = this + linearCopyShader.drawTo(other) } -infix fun Framebuffer.nearestCopyTo(other: Framebuffer) { - blit(other, GL_COLOR_BUFFER_BIT, GL_NEAREST) +infix fun RenderTarget.nearestCopyTo(other: RenderTarget) { + primaryFramebuffer = this + nearestCopyShader.drawTo(other) } /** @@ -176,73 +190,65 @@ fun recommendMipLevel(width: Int, height: Int): Int { * @return the number of mipmap levels needed. * @author heckerpowered */ -fun Framebuffer.recommendMipLevel(): Int { - return recommendMipLevel(textureWidth, textureHeight) +fun RenderTarget.recommendMipLevel(): Int { + return recommendMipLevel(width, height) } -fun Framebuffer.dump(levelOfDetail: Int = 0, generateMipmap: Boolean = true) { +fun RenderTarget.dump(levelOfDetail: Int = 0, generateMipmap: Boolean = true) { dump(hashCode().toString(), levelOfDetail, generateMipmap) } -fun Framebuffer.dump(name: String, levelOfDetail: Int = 0, generateMipmap: Boolean = true) { - RenderSystem.bindTexture(colorAttachment) - - if (generateMipmap) { - glGenerateMipmap(GL_TEXTURE_2D) - } - val width = glGetTexLevelParameteri(GL_TEXTURE_2D, levelOfDetail, GL_TEXTURE_WIDTH) - val height = glGetTexLevelParameteri(GL_TEXTURE_2D, levelOfDetail, GL_TEXTURE_HEIGHT) - +/** + * Writes the color attachment (at [levelOfDetail]) to `screenshots/framebuffer_dump_.png`. + * Debug utility; reads back through the GpuDevice wrapper so it works on both backends. + */ +fun RenderTarget.dump(name: String, levelOfDetail: Int = 0, @Suppress("UNUSED_PARAMETER") generateMipmap: Boolean = true) { + val texture = colorTexture ?: return + val width = texture.getWidth(levelOfDetail) + val height = texture.getHeight(levelOfDetail) if (width <= 0 || height <= 0) { - OpenGLExtensions.fastCheck("Framebuffer dump: invalid texture size") return } - NativeImage(width, height, false).use { nativeImage -> - nativeImage.loadFromTextureImage(levelOfDetail, false) - nativeImage.mirrorVertically() - - val file = File("screenshots") - file.mkdir() - - val filename = "framebuffer_dump_${name}.png" - nativeImage.writeTo(File(file, filename)) - } + val device = RenderSystem.getDevice() + val encoder = device.createCommandEncoder() + val bytesPerPixel = texture.format.blockSize() + val readback = device.createBuffer( + { "matrix framebuffer dump" }, + GpuBuffer.USAGE_MAP_READ or GpuBuffer.USAGE_COPY_DST, + (width * height * bytesPerPixel).toLong() + ) + encoder.copyTextureToBuffer(texture, readback, 0L, { + readback.map(true, false).use { mapped -> + NativeImage(width, height, false).use { nativeImage -> + for (y in 0 until height) { + for (x in 0 until width) { + val color = mapped.data().getInt((y * width + x) * bytesPerPixel) + nativeImage.setPixelABGR(x, y, color) + } + } + // 26.2: NativeImage has no mirror helper anymore; wrapper readback is + // top-down already, so no flip is needed (debug utility only). + + val file = File("screenshots") + file.mkdir() + + val filename = "framebuffer_dump_${name}.png" + nativeImage.writeToFile(File(file, filename)) + } + } + readback.close() + }, levelOfDetail) } /** - * Executes the given [action] while preserving the currently bound framebuffer and viewport state. - * - * This function backs up the current framebuffer binding and viewport dimensions, - * then invokes the specified [action]. After the action completes, the original framebuffer - * and viewport state are restored. This ensures that temporary framebuffer or viewport changes - * inside [action] do not leak outside the function scope. - * - * This is especially useful when performing off-screen rendering or rendering to custom framebuffers, - * as it guarantees rendering state isolation. + * Executes the given [action]. * - * Example usage: - * ``` - * framebufferGuard { - * glBindFramebuffer(GL_FRAMEBUFFER, customFramebuffer) - * GlStateManager._viewport(0, 0, width, height) - * renderSomething() - * } - * // Original framebuffer and viewport are now restored - * ``` - * - * @param action The block of code to execute within the guarded framebuffer and viewport state. + * Under the 26.2 wrapper API render passes are self-contained: there is no longer any global + * framebuffer/viewport binding to guard, so this is a plain invocation kept for source + * compatibility. */ -@Deprecated("Use StateIsolation.isolate(FramebufferState(this)) { action() } instead") +@Deprecated("Render passes are self-contained on the 26.2 wrapper API; the guard is no longer needed") fun framebufferGuard(action: () -> Unit) { - val previousBindingFramebuffer = glGetInteger(GL_FRAMEBUFFER_BINDING) - val previousViewportX = Viewport.getX() - val previousViewportY = Viewport.getY() - val previousViewportWidth = Viewport.getWidth() - val previousViewportHeight = Viewport.getHeight() - action() - - glBindFramebuffer(GL_FRAMEBUFFER, previousBindingFramebuffer) - GlStateManager._viewport(previousViewportX, previousViewportY, previousViewportWidth, previousViewportHeight) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt index 8ce5a9de..d0bc6646 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/ScreenEffectRenderer.kt @@ -5,47 +5,43 @@ package heckerpowered.matrix.client.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.pipeline.BlendFunction import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.event.PostProcessCallback import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.player import heckerpowered.matrix.client.render.effect.SculkCatalystEffectRenderer -import heckerpowered.matrix.client.render.particle.ParticleSystem -import heckerpowered.matrix.client.render.particle.memory.MemoryLayout -import heckerpowered.matrix.client.render.particle.module.particle_render.ParticleSpriteRendererModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomLifetimeModule -import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomVelocityModule -import heckerpowered.matrix.client.render.particle.module.particle_update.DragModule -import heckerpowered.matrix.client.render.particle.module.particle_update.KillParticleModule -import heckerpowered.matrix.client.render.particle.module.particle_update.ParticleStateModule -import heckerpowered.matrix.client.render.particle.module.particle_update.ScaleSpriteSizeBySpeedModule -import heckerpowered.matrix.client.render.particle.system.ExplosionParticle +// GPU particle system retired (see common/attic) +// import heckerpowered.matrix.client.render.particle.ParticleSystem +// import heckerpowered.matrix.client.render.particle.memory.MemoryLayout +// import heckerpowered.matrix.client.render.particle.module.particle_render.ParticleSpriteRendererModule +// import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule +// import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomLifetimeModule +// import heckerpowered.matrix.client.render.particle.module.particle_spawn.RandomVelocityModule +// import heckerpowered.matrix.client.render.particle.module.particle_update.DragModule +// import heckerpowered.matrix.client.render.particle.module.particle_update.KillParticleModule +// import heckerpowered.matrix.client.render.particle.module.particle_update.ParticleStateModule +// import heckerpowered.matrix.client.render.particle.module.particle_update.ScaleSpriteSizeBySpeedModule +// import heckerpowered.matrix.client.render.particle.system.ExplosionParticle import heckerpowered.matrix.client.render.post.BloomEffect import heckerpowered.matrix.client.render.post.CollapseEffectRenderer import heckerpowered.matrix.client.render.post.ShockwaveRenderer import heckerpowered.matrix.client.render.shader.RadialBlurRenderer.samples import heckerpowered.matrix.client.render.shader.VortexRenderer -import heckerpowered.matrix.client.render.state.* -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.DissolveShader -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.effect.ModMobEffects.ANGERED_EFFECT -import heckerpowered.matrix.common.effect.ModMobEffects.WITHER_ARMOR_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.Angered +import heckerpowered.matrix.common.effect.ModMobEffects.WitherArmor import heckerpowered.matrix.common.effect.isBloodPactActive import heckerpowered.matrix.common.magic.spell.SculkCatalystMagic import heckerpowered.matrix.core.approximatelyEqual import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents -import net.minecraft.client.MinecraftClient -import net.minecraft.util.math.Vec3d -import org.lwjgl.opengl.GL46.* +import net.minecraft.client.Minecraft +import net.minecraft.world.phys.Vec3 import java.time.Duration object ScreenEffectRenderer { @@ -65,53 +61,30 @@ object ScreenEffectRenderer { private val auraShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/aura.fsh", GL_FRAGMENT_SHADER), + "post/aura.fsh", uniforms = arrayOf( - UniformProvider("entityDepthAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, sceneFramebuffer.depthAttachment) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("entityColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 1) - glBindTexture(GlConst.GL_TEXTURE_2D, sceneFramebuffer.colorAttachment) - RenderSystem.glUniform1i(pointer, 1) - }, - UniformProvider("sceneDepthAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 2) - glBindTexture(GlConst.GL_TEXTURE_2D, minecraft.framebuffer.depthAttachment) - glUniform1i(pointer, 2) - }, - UniformProvider("sceneColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 3) - glBindTexture(GlConst.GL_TEXTURE_2D, minecraft.framebuffer.colorAttachment) - glUniform1i(pointer, 3) - }, - UniformProvider("noiseColorAttachment") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0 + 4) - glBindTexture(GlConst.GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - glUniform1i(pointer, 4) - }, - UniformProvider("time") { pointer -> - val age = minecraft.player?.age?.toFloat() ?: 0F - val deltaTime = minecraft.renderTickCounter.tickDelta + UniformProvider("MatrixPostUniforms") { + // auraParams: x = time, y = alpha + val age = minecraft.player?.tickCount?.toFloat() ?: 0F + val deltaTime = minecraft.deltaTracker.getGameTimeDeltaPartialTick(true) val time = age + deltaTime - glUniform1f(pointer, time / 1000.0F) - }, - UniformProvider("alpha") { pointer -> - glUniform1f(pointer, auraAlphaAnimation.animatedValue.toFloat()) - }, - UniformProvider("auraColor") { pointer -> + putVec4(time / 1000.0F, auraAlphaAnimation.animatedValue.toFloat(), 0F, 0F) + // auraColor: preserves original behavior of using color.red for all 4 components val color = colorAnimation - glUniform4f( - pointer, + putVec4( color.red.animatedValue.toFloat() / color.red.to.toFloat(), color.red.animatedValue.toFloat() / color.red.to.toFloat(), color.red.animatedValue.toFloat() / color.red.to.toFloat(), color.red.animatedValue.toFloat() / color.red.to.toFloat() ) } + ), + textures = arrayOf( + TextureProvider("entityDepthAttachment") { sceneFramebuffer.depthTextureView }, + TextureProvider("entityColorAttachment") { sceneFramebuffer.colorTextureView }, + TextureProvider("sceneDepthAttachment") { minecraft.mainRenderTarget.depthTextureView }, + TextureProvider("sceneColorAttachment") { minecraft.mainRenderTarget.colorTextureView }, + TextureProvider("noiseColorAttachment") { DissolveShader.perlinNoiseTextureView } ) ) } @@ -123,52 +96,55 @@ object ScreenEffectRenderer { private val colorFilterShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/color_filter.fsh", GL_FRAGMENT_SHADER), + "post/color_filter.fsh", uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("color") { pointer -> - glUniform4f( - pointer, + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = color + putVec4( colorAnimation.red.animatedValue.toFloat(), colorAnimation.green.animatedValue.toFloat(), colorAnimation.blue.animatedValue.toFloat(), 1.0F ) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } - ) + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) } private val edgeHighlightShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/edge_highlight.fsh", GL_FRAGMENT_SHADER), + "post/edge_highlight.fsh", uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("edgeThreshold") { pointer -> - glUniform1f(pointer, edgeThresholdAnimation.animatedValue.toFloat()) - }, - UniformProvider("edgeColor") { pointer -> - glUniform4f(pointer, 0.7F, 0.1F, 0.1F, 1.0F) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = edgeThreshold + putVec4(edgeThresholdAnimation.animatedValue.toFloat(), 0F, 0F, 0F) + // MatrixPostData1 = edgeColor + putVec4(0.7F, 0.1F, 0.1F, 1.0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } - ) + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) } private val radialBlurShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/radial_blur.fsh", GL_FRAGMENT_SHADER), + "post/blur/radial_blur.fsh", uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("strength") { pointer -> - glUniform1f(pointer, ghostStrengthAnimation.animatedValue.toFloat()) - }, - UniformProvider("samples") { pointer -> - glUniform1i(pointer, samples) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = strength, .y = samples + putVec4(ghostStrengthAnimation.animatedValue.toFloat(), samples.toFloat(), 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } - ) + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) } @@ -193,27 +169,18 @@ object ScreenEffectRenderer { } private fun onPostProcess() { - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState(true), BlendFuncSeparateState(GL_ONE, GL_ONE) - ) { - VortexRenderer.render() - } + VortexRenderer.render() + bloomThresholdAnimation.animatedValue = 1.0 if (!shouldRenderBloom()) { return } BloomEffect.brightnessThreshold = bloomThresholdAnimation.animatedValue.toFloat() + 0.1F - BloomEffect.brightnessPassFramebuffer = minecraft.framebuffer + BloomEffect.brightnessPassFramebuffer = minecraft.mainRenderTarget BloomEffect.renderBloom() - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncSeparateState(GL_ONE, GL_ONE) - ) { - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) - } + PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.mainRenderTarget, BlendFunction.ADDITIVE) // ToneMapping.exposureLinear = 1.0f // ToneMapping.exposureEv = 0.0f @@ -226,65 +193,68 @@ object ScreenEffectRenderer { // } } - val particleSystem by lazy { - ParticleSystem( - 10000, - particleSpawnModules = arrayOf( - InitializeParticleModule(), - RandomVelocityModule(), - RandomLifetimeModule(), - ), - particleUpdateModules = arrayOf( - KillParticleModule(), - ParticleStateModule(), - DragModule(), - ScaleSpriteSizeBySpeedModule() - ), - particleRenderModules = arrayOf( - ParticleSpriteRendererModule() - ), - MemoryLayout.DEFAULT_LAYOUT - ) - } - - fun spawnParticleAt(position: Vec3d, count: Int = 1) { - val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState - particleState.x = position.x.toFloat() - particleState.y = position.y.toFloat() - particleState.z = position.z.toFloat() - - val multiplier = 4F - - particleState.colorR = 1.0F * multiplier - particleState.colorG = 0.5F * multiplier - particleState.colorB = 1.0F * multiplier - particleState.colorA = 1.0F - - particleState.spriteSize = 80.0F - particleState.scale = 1F - - index += count - if (index > particleSystem.particleCount) { - index = 0 - } - particleSystem.spawnPartialParticles(index, count) + // GPU particle system retired (see common/attic) + // val particleSystem by lazy { + // ParticleSystem( + // 10000, + // particleSpawnModules = arrayOf( + // InitializeParticleModule(), + // RandomVelocityModule(), + // RandomLifetimeModule(), + // ), + // particleUpdateModules = arrayOf( + // KillParticleModule(), + // ParticleStateModule(), + // DragModule(), + // ScaleSpriteSizeBySpeedModule() + // ), + // particleRenderModules = arrayOf( + // ParticleSpriteRendererModule() + // ), + // MemoryLayout.DEFAULT_LAYOUT + // ) + // } + + @Suppress("UNUSED_PARAMETER") + fun spawnParticleAt(position: Vec3, count: Int = 1) { + // GPU particle system retired (see common/attic) + // val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState + // particleState.x = position.x.toFloat() + // particleState.y = position.y.toFloat() + // particleState.z = position.z.toFloat() + // + // val multiplier = 4F + // + // particleState.colorR = 1.0F * multiplier + // particleState.colorG = 0.5F * multiplier + // particleState.colorB = 1.0F * multiplier + // particleState.colorA = 1.0F + // + // particleState.spriteSize = 80.0F + // particleState.scale = 1F + // + // index += count + // if (index > particleSystem.particleCount) { + // index = 0 + // } + // particleSystem.spawnPartialParticles(index, count) } var index: Int = 0 - fun onTick(minecraftClient: MinecraftClient) { + fun onTick(minecraftClient: Minecraft) { if (minecraftClient.player == null) { return } - if (player.getStatusEffect(ANGERED_EFFECT) == null && previousAngryState) { + if (player.getEffect(Angered) == null && previousAngryState) { onAngeredEffectRemoved() previousAngryState = false - } else if (player.getStatusEffect(ANGERED_EFFECT) != null && !previousAngryState) { + } else if (player.getEffect(Angered) != null && !previousAngryState) { onAngeredEffectApplied() previousAngryState = true } - val witherArmorStatusEffect = player.getStatusEffect(WITHER_ARMOR_EFFECT) + val witherArmorStatusEffect = player.getEffect(WitherArmor) if (witherArmorStatusEffect == null && previousWitherArmorState) { previousWitherArmorState = false } else if (witherArmorStatusEffect != null && !previousWitherArmorState || @@ -349,7 +319,7 @@ object ScreenEffectRenderer { fun onWitherArmorEffectApplied() { previousWitherArmorState = true - val witherArmorStatusEffect = player.getStatusEffect(WITHER_ARMOR_EFFECT) + val witherArmorStatusEffect = player.getEffect(WitherArmor) previousWitherArmorDuration = witherArmorStatusEffect?.duration?.toLong() ?: 0L PostProcessRenderer.postProcessShaders.add(colorFilterShader) @@ -386,7 +356,7 @@ object ScreenEffectRenderer { CollapseEffectRenderer.dissolveFactor.duration = Duration.ofMillis(1000) CollapseEffectRenderer.dissolveFactor.start() - ShockwaveRenderer.wavePosition = player.pos.toVector3f() + ShockwaveRenderer.wavePosition = player.position().toVector3f() ShockwaveRenderer.waveRadius.from = .0 ShockwaveRenderer.waveRadius.to = 128.0 @@ -433,7 +403,6 @@ object ScreenEffectRenderer { } private val sceneFramebuffer by lazy { PostProcessRenderer.createManagedFramebuffer() } - private var previousFramebuffer = -1 private var useAuraShader = false private var useBloom = false @@ -449,17 +418,20 @@ object ScreenEffectRenderer { return } - previousFramebuffer = GlStateManager.getBoundFramebuffer() - sceneFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - sceneFramebuffer.beginWrite(false) + PostProcessRenderer.clear(sceneFramebuffer) + RenderSystem.outputColorTextureOverride = sceneFramebuffer.colorTextureView + RenderSystem.outputDepthTextureOverride = sceneFramebuffer.depthTextureView } @JvmStatic fun endRenderEntity() { - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { + // Closes the capture redirect opened in beginRenderEntity; the old code implicitly + // ended capture once the caller resumed writing to the main framebuffer, but under + // the wrapper API the override must be cleared explicitly. + RenderSystem.outputColorTextureOverride = null + RenderSystem.outputDepthTextureOverride = null + + run { val sculkCatalystIsAlreadyActive = SculkCatalystMagic.isSculkCatalystActive(player) if (!sculkCatalystIsAlreadyActive && CollapseEffectRenderer.dissolveFactor.to != .0) { CollapseEffectRenderer.dissolveFactor.value = .0 @@ -468,25 +440,30 @@ object ScreenEffectRenderer { if (CollapseEffectRenderer.dissolveFactor.animatedValue != .0) { PostProcessRenderer.clearFramebuffers() - CollapseEffectRenderer.depthAttachment = minecraft.framebuffer.depthAttachment + CollapseEffectRenderer.depthAttachment = minecraft.mainRenderTarget.depthTextureView PostProcessRenderer.renderShaderToFramebuffer(CollapseEffectRenderer.shader, PostProcessRenderer.ping) - PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.framebuffer, false) + // Uncertain: old disableBlend=false with only a captured (snapshot) blend-func + // state active; no explicit blend func was set right before this call, so + // blending is treated as disabled here. Revisit if this looks wrong in-game. + PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.mainRenderTarget, null) } if (ShockwaveRenderer.waveRadius.animatedValue != .0) { PostProcessRenderer.clearFramebuffers() - ShockwaveRenderer.depthAttachment = minecraft.framebuffer.depthAttachment + ShockwaveRenderer.depthAttachment = minecraft.mainRenderTarget.depthTextureView PostProcessRenderer.renderShaderToFramebuffer(ShockwaveRenderer.shockwaveShader, PostProcessRenderer.ping) - PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.framebuffer, false) + // Uncertain: see note above for the CollapseEffectRenderer copy. + PostProcessRenderer.copyFramebuffer(PostProcessRenderer.ping, minecraft.mainRenderTarget, null) } } - particleSystem.updateParticles() - ExplosionParticle.particleSystem.updateParticles() - StateIsolation.isolate(DepthTestState(true), BlendState(false)) { - particleSystem.renderParticles() - ExplosionParticle.particleSystem.renderParticles() - } + // GPU particle system retired (see common/attic) + // particleSystem.updateParticles() + // ExplosionParticle.particleSystem.updateParticles() + // StateIsolation.isolate(DepthTestState(true), BlendState(false)) { + // particleSystem.renderParticles() + // ExplosionParticle.particleSystem.renderParticles() + // } SculkCatalystEffectRenderer.render() @@ -498,19 +475,11 @@ object ScreenEffectRenderer { BloomEffect.brightnessPassFramebuffer = sceneFramebuffer BloomEffect.renderBloom() - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncState(GL_ONE, GL_ONE) - ) { - PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.framebuffer, false) - } + PostProcessRenderer.copyFramebuffer(BloomEffect.bloomUpFramebuffer, minecraft.mainRenderTarget, BlendFunction.ADDITIVE) - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState(true), BlendFuncSeparateState(), - ) { - PostProcessRenderer.copyFramebuffer(sceneFramebuffer, minecraft.framebuffer, false) - } + // Uncertain: old wrapper was a no-arg BlendFuncSeparateState() (default GL_ONE/GL_ZERO + // reset => effectively opaque copy), so blending is treated as disabled here. + PostProcessRenderer.copyFramebuffer(sceneFramebuffer, minecraft.mainRenderTarget, null) useBloom = false } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt index 278cf7e0..832909ec 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/effect/SculkCatalystEffectRenderer.kt @@ -6,14 +6,11 @@ package heckerpowered.matrix.client.render.effect import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.render.PostProcessRenderer +import heckerpowered.matrix.client.render.mainRenderTarget import heckerpowered.matrix.client.render.shader.VolumeDistortion -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import net.minecraft.entity.LivingEntity +import net.minecraft.world.entity.LivingEntity object SculkCatalystEffectRenderer { var entity: LivingEntity? = null @@ -42,20 +39,21 @@ object SculkCatalystEffectRenderer { } VolumeDistortion.grayscaleIntensity = 1.0F - VolumeDistortion.depthAttachment = minecraft.framebuffer.depthAttachment - VolumeDistortion.sceneColorTexture = minecraft.framebuffer.colorAttachment + // 1.21 sampled the main framebuffer's own color attachment while drawing back into + // it, which Vulkan forbids (same-texture read/write); snapshot the scene into the + // post-process ping target and sample the copy instead. Main's depth stays bound + // directly: this pass writes color only (writesDepth = false), so the depth view is + // never attached to the pass and reading it is safe on both backends. + PostProcessRenderer.copyFramebuffer(minecraft.mainRenderTarget, PostProcessRenderer.ping) + VolumeDistortion.depthAttachment = minecraft.mainRenderTarget.depthTextureView + VolumeDistortion.sceneColorTexture = PostProcessRenderer.ping.colorTextureView VolumeDistortion.volumeRadius = volumeRadius.animatedValue.toFloat() VolumeDistortion.emissiveStrength = emissiveStrength.animatedValue.toFloat() - val tickDelta = minecraft.renderTickCounter.getTickDelta(false) - VolumeDistortion.volumePosition = entity.getLerpedPos(tickDelta).toVector3f() + val tickDelta = minecraft.deltaTracker.getGameTimeDeltaPartialTick(false) + VolumeDistortion.volumePosition = entity.getPosition(tickDelta).toVector3f() - StateIsolation.isolate( - FramebufferState(minecraft.framebuffer), ViewportState(minecraft.framebuffer), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - VolumeDistortion.Shader.blit() - } + VolumeDistortion.Shader.drawTo(minecraft.mainRenderTarget) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt index 024c4f21..4089bb83 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/DevEntityRenderer.kt @@ -8,18 +8,53 @@ package heckerpowered.matrix.client.render.entity import heckerpowered.matrix.common.entity.DevEntity import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.render.entity.MobEntityRenderer -import net.minecraft.client.render.entity.model.EntityModelLayers -import net.minecraft.client.render.entity.model.PlayerEntityModel -import net.minecraft.client.util.DefaultSkinHelper -import net.minecraft.util.Identifier +import net.minecraft.client.model.geom.ModelLayers +import net.minecraft.client.model.player.PlayerModel +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.MobRenderer +import net.minecraft.client.renderer.entity.state.ArmedEntityRenderState +import net.minecraft.client.renderer.entity.state.AvatarRenderState +import net.minecraft.client.resources.DefaultPlayerSkin +import net.minecraft.resources.Identifier +/** + * [DevEntity] is a [net.minecraft.world.entity.PathfinderMob], not a player, but it renders + * with the default player skin/model (1.21 behavior: `PlayerModel` + + * `DefaultPlayerSkin.getTexture()`). + * + * 26.2 note: [PlayerModel] is no longer generic — it hard-codes its render-state type to + * [AvatarRenderState] (`class PlayerModel : HumanoidModel`), and + * [AvatarRenderState] extraction is normally only done by the player-specific renderer from an + * `AbstractClientPlayer`. Since [MobRenderer] only requires `S : LivingEntityRenderState` + * (which [AvatarRenderState] satisfies), we use [AvatarRenderState] directly as this renderer's + * state and populate it ourselves in [extractRenderState]: base living-entity fields come from + * `super.extractRenderState`, arm pose / held-item fields come from the same + * [ArmedEntityRenderState.extractArmedEntityRenderState] helper the vanilla humanoid renderers + * use (entity-agnostic), and the player-only fields (skin, cape/sleeve/pants visibility) are + * filled with fixed "plain default skin, fully clothed, no cape" values since [DevEntity] has + * no real player profile to derive them from. + */ @Environment(EnvType.CLIENT) -class DevEntityRenderer(context: EntityRendererFactory.Context) : MobEntityRenderer>( - context, PlayerEntityModel(context.getPart(EntityModelLayers.PLAYER), false), 0.5F +class DevEntityRenderer(context: EntityRendererProvider.Context) : MobRenderer( + context, PlayerModel(context.bakeLayer(ModelLayers.PLAYER), false), 0.5F ) { - override fun getTexture(entity: DevEntity): Identifier { - return DefaultSkinHelper.getTexture() + override fun createRenderState(): AvatarRenderState = AvatarRenderState() + + override fun extractRenderState(entity: DevEntity, state: AvatarRenderState, partialTick: Float) { + super.extractRenderState(entity, state, partialTick) + ArmedEntityRenderState.extractArmedEntityRenderState(entity, state, itemModelResolver, partialTick) + + state.skin = DefaultPlayerSkin.getDefaultSkin() + state.showHat = true + state.showJacket = true + state.showLeftPants = true + state.showRightPants = true + state.showLeftSleeve = true + state.showRightSleeve = true + state.showCape = false + } + + override fun getTextureLocation(state: AvatarRenderState): Identifier { + return DefaultPlayerSkin.getDefaultTexture() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt index 816dea80..a394a5c3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/EmptyRenderer.kt @@ -7,18 +7,17 @@ package heckerpowered.matrix.client.render.entity import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.Frustum -import net.minecraft.client.render.entity.EntityRenderer -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.entity.Entity -import net.minecraft.screen.PlayerScreenHandler -import net.minecraft.util.Identifier +import net.minecraft.client.renderer.culling.Frustum +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.EntityRenderState +import net.minecraft.world.entity.Entity @Environment(EnvType.CLIENT) -class EmptyRenderer(context: EntityRendererFactory.Context) : EntityRenderer(context) { +class EmptyRenderer(context: EntityRendererProvider.Context) : EntityRenderer(context) { override fun shouldRender(entity: Entity, frustum: Frustum, x: Double, y: Double, z: Double): Boolean { return false } - override fun getTexture(entity: Entity): Identifier = PlayerScreenHandler.BLOCK_ATLAS_TEXTURE -} \ No newline at end of file + override fun createRenderState(): EntityRenderState = EntityRenderState() +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt index 2b183a21..16604651 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/FinderArrowEntityRenderer.kt @@ -6,33 +6,39 @@ package heckerpowered.matrix.client.render.entity import heckerpowered.matrix.client.render.ScreenEffectRenderer -import heckerpowered.matrix.client.render.ScreenEffectRenderer.particleSystem -import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule +// GPU particle system retired (see common/attic) +// import heckerpowered.matrix.client.render.ScreenEffectRenderer.particleSystem +// import heckerpowered.matrix.client.render.particle.module.particle_spawn.InitializeParticleModule import heckerpowered.matrix.common.entity.FinderArrowEntity +import heckerpowered.matrix.core.getLerpedPos import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.render.entity.ProjectileEntityRenderer -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.util.Identifier +import net.minecraft.client.renderer.entity.ArrowRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.ArrowRenderState +import net.minecraft.resources.Identifier @Environment(EnvType.CLIENT) -class FinderArrowEntityRenderer(context: EntityRendererFactory.Context) : ProjectileEntityRenderer(context) { - override fun getTexture(spectralArrowEntity: FinderArrowEntity): Identifier { - return TEXTURE +class FinderArrowEntityRenderer(context: EntityRendererProvider.Context) : ArrowRenderer(context) { + override fun createRenderState(): ArrowRenderState { + return ArrowRenderState() } - override fun render(persistentProjectileEntity: FinderArrowEntity, f: Float, g: Float, matrixStack: MatrixStack?, vertexConsumerProvider: VertexConsumerProvider?, i: Int) { - val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState + override fun getTextureLocation(state: ArrowRenderState): Identifier { + return TEXTURE + } - particleState.age = 0F - ScreenEffectRenderer.spawnParticleAt(persistentProjectileEntity.getLerpedPos(g), 10) + override fun extractRenderState(entity: FinderArrowEntity, state: ArrowRenderState, partialTick: Float) { + super.extractRenderState(entity, state, partialTick) - super.render(persistentProjectileEntity, f, g, matrixStack, vertexConsumerProvider, i) + // GPU particle system retired (see common/attic) + // val particleState = (particleSystem.particleSpawnModules.first { it is InitializeParticleModule } as InitializeParticleModule).particleState + // + // particleState.age = 0F + ScreenEffectRenderer.spawnParticleAt(entity.getLerpedPos(partialTick), 10) } companion object { - val TEXTURE: Identifier = Identifier.ofVanilla("textures/entity/projectiles/spectral_arrow.png") + val TEXTURE: Identifier = Identifier.withDefaultNamespace("textures/entity/projectiles/spectral_arrow.png") } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt index 3ec1acfb..a071fe4e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/entity/MagicLightningEntityRenderer.kt @@ -5,32 +5,71 @@ package heckerpowered.matrix.client.render.entity -import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.PoseStack +import com.mojang.blaze3d.vertex.VertexConsumer +import heckerpowered.matrix.client.render.Color import heckerpowered.matrix.common.entity.MagicLightningBolt import net.fabricmc.api.EnvType import net.fabricmc.api.Environment -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.entity.EntityRenderer -import net.minecraft.client.render.entity.EntityRendererFactory -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.screen.PlayerScreenHandler -import net.minecraft.util.Identifier -import net.minecraft.util.math.random.Random +import net.minecraft.client.renderer.SubmitNodeCollector +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.entity.state.EntityRenderState +import net.minecraft.client.renderer.rendertype.RenderTypes +import net.minecraft.client.renderer.state.level.CameraRenderState +import net.minecraft.util.RandomSource import org.joml.Matrix4f +/** + * Render state for [MagicLightningBolt]: mirrors vanilla's + * `net.minecraft.client.renderer.entity.state.LightningBoltRenderState` (which only carries + * `seed`) but also captures [color], since unlike vanilla lightning, ours renders in one of + * several [MagicLightningBolt.LightningType] colors. + */ +@Environment(EnvType.CLIENT) +class MagicLightningRenderState : EntityRenderState() { + var seed: Long = 0L + var color: Color = MagicLightningBolt.LightningType.NORMAL.color +} + @Environment(EnvType.CLIENT) -class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : EntityRenderer(context) { - override fun render(lightningEntity: MagicLightningBolt, f: Float, g: Float, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, i: Int) { - val multiplier = 5.825f - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) - RenderSystem.disableBlend() +class MagicLightningEntityRenderer(context: EntityRendererProvider.Context) : + EntityRenderer(context) { + + override fun createRenderState(): MagicLightningRenderState = MagicLightningRenderState() + + override fun extractRenderState(entity: MagicLightningBolt, state: MagicLightningRenderState, partialTick: Float) { + super.extractRenderState(entity, state, partialTick) + state.seed = entity.seed + state.color = entity.lightningType.color + } + + override fun submit( + state: MagicLightningRenderState, + matrixStack: PoseStack, + submitNodeCollector: SubmitNodeCollector, + cameraRenderState: CameraRenderState, + ) { + submitNodeCollector.submitCustomGeometry(matrixStack, RenderTypes.lightning()) { pose, vertexConsumer -> + renderLightning(state, pose.pose(), vertexConsumer) + } + } + + private fun renderLightning(state: MagicLightningRenderState, matrix4f: Matrix4f, vertexConsumer: VertexConsumer) { + // 26.2 note: RenderSystem.setShaderColor no longer applies a global tint to + // submitCustomGeometry draws (pipeline-based rendering has no equivalent hook), so the + // brightness multiplier that used to be applied via setShaderColor is baked directly + // into the per-vertex color instead. Vertex color is 8-bit (no HDR headroom like the + // old shader uniform had), so the multiplied result is clamped to 1.0 rather than + // wrapping; visually this reads as "fully bright" for channels the multiplier pushes + // past white, matching the old glow's intent on an additive RenderTypes.lightning() + // blend even though the exact float value differs from the unclamped GL uniform. + val brightnessMultiplier = 5.825f val fs = FloatArray(8) val gs = FloatArray(8) var h = 0.0f var j = 0.0f - val random = Random.create(lightningEntity.seed) + val random = RandomSource.create(state.seed) for (k in 7 downTo 0) { fs[k] = h @@ -39,11 +78,8 @@ class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : Ent j += (random.nextInt(11) - 5).toFloat() } - val vertexConsumer = vertexConsumerProvider.getBuffer(RenderLayer.getLightning()) - val matrix4f = matrixStack.peek().positionMatrix - for (l in 0..3) { - val random2 = Random.create(lightningEntity.seed) + val random2 = RandomSource.create(state.seed) for (m in 0..2) { var n = 7 @@ -80,10 +116,10 @@ class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : Ent z *= (r.toFloat() - 1.0f) * 0.1f + 1.0f } - val color = lightningEntity.lightningType.color - val red = color.red.toFloat() / 255F - val green = color.green.toFloat() / 255F - val blue = color.blue.toFloat() / 255F + val color = state.color + val red = (color.red.toFloat() / 255F * brightnessMultiplier).coerceIn(0f, 1f) + val green = (color.green.toFloat() / 255F * brightnessMultiplier).coerceIn(0f, 1f) + val blue = (color.blue.toFloat() / 255F * brightnessMultiplier).coerceIn(0f, 1f) drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = false, shiftSouth1 = false, shiftEast2 = true, shiftSouth2 = false) drawBranch(matrix4f, vertexConsumer, p, q, r, s, t, red, green, blue, y, z, shiftEast1 = true, shiftSouth1 = false, shiftEast2 = true, shiftSouth2 = true) @@ -92,7 +128,6 @@ class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : Ent } } } - // RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) } private fun drawBranch( @@ -113,11 +148,9 @@ class MagicLightningEntityRenderer(context: EntityRendererFactory.Context) : Ent shiftEast2: Boolean, shiftSouth2: Boolean, ) { - buffer.vertex(matrix, x1 + (if (shiftEast1) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth1) offset1 else -offset1)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x2 + (if (shiftEast1) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth1) offset2 else -offset2)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x2 + (if (shiftEast2) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth2) offset2 else -offset2)).color(red, green, blue, 0.3f) - buffer.vertex(matrix, x1 + (if (shiftEast2) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth2) offset1 else -offset1)).color(red, green, blue, 0.3f) + buffer.addVertex(matrix, x1 + (if (shiftEast1) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth1) offset1 else -offset1)).setColor(red, green, blue, 0.3f) + buffer.addVertex(matrix, x2 + (if (shiftEast1) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth1) offset2 else -offset2)).setColor(red, green, blue, 0.3f) + buffer.addVertex(matrix, x2 + (if (shiftEast2) offset2 else -offset2), ((y + 1) * 16).toFloat(), z2 + (if (shiftSouth2) offset2 else -offset2)).setColor(red, green, blue, 0.3f) + buffer.addVertex(matrix, x1 + (if (shiftEast2) offset1 else -offset1), (y * 16).toFloat(), z1 + (if (shiftSouth2) offset1 else -offset1)).setColor(red, green, blue, 0.3f) } - - override fun getTexture(entity: MagicLightningBolt): Identifier = PlayerScreenHandler.BLOCK_ATLAS_TEXTURE -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/gui/DissolveRect.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/gui/DissolveRect.kt new file mode 100644 index 00000000..b240f063 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/gui/DissolveRect.kt @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.client.render.gui + +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.FilterMode +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import com.mojang.blaze3d.vertex.VertexConsumer +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.client.minecraft +import net.minecraft.client.gui.navigation.ScreenRectangle +import net.minecraft.client.gui.render.TextureSetup +import net.minecraft.client.renderer.RenderPipelines +import net.minecraft.client.renderer.state.gui.GuiElementRenderState + +/** + * 26.2 GUI-pipeline port of the 1.21 mesh-attached dissolve program (DissolveShader: + * position_texture_color.vsh + noise_mask.fsh): a screen-space quad burned in/out by the + * perlin-noise mask, with the emissive border glow. The per-draw uniforms (dissolveFactor, + * resolution ratio, time) travel packed into the Normal attribute (gui/dissolve_rect.vsh + * unpacks them), because vanilla GUI elements have no per-element uniform slot. + */ +class DissolveRectRenderState( + private val x0: Float, + private val y0: Float, + private val x1: Float, + private val y1: Float, + private val color: Int, + dissolveFactor: Float, + resolutionRatio: Float, + timeSeconds: Float, + private val scissor: ScreenRectangle?, +) : GuiElementRenderState { + // Normal-channel packing (shader unpacks with * 0.5 + 0.5, then the fragment stage + // rescales): factor is already 0..1; the height/width ratio is stored /4 (supports + // ratios up to 4); time wraps over the shader's 10-second drift window. + private val packedFactor = (dissolveFactor.coerceIn(0F, 1F)) * 2F - 1F + private val packedRatio = (resolutionRatio / 4F).coerceIn(0F, 1F) * 2F - 1F + private val packedTime = (timeSeconds % 10F / 10F) * 2F - 1F + + override fun buildVertices(consumer: VertexConsumer) { + // Baseline vertex order/texcoords (renderRightPart): x flipped so the burn sweep + // travels the same direction as 1.21. + consumer.addVertex(x1, y0, 0F).setUv(0F, 0F).setColor(color).setNormal(packedFactor, packedRatio, packedTime) + consumer.addVertex(x0, y0, 0F).setUv(1F, 0F).setColor(color).setNormal(packedFactor, packedRatio, packedTime) + consumer.addVertex(x0, y1, 0F).setUv(1F, 1F).setColor(color).setNormal(packedFactor, packedRatio, packedTime) + consumer.addVertex(x1, y1, 0F).setUv(0F, 1F).setColor(color).setNormal(packedFactor, packedRatio, packedTime) + } + + override fun pipeline(): RenderPipeline = DissolveRect.pipeline + + override fun textureSetup(): TextureSetup = DissolveRect.noiseTextureSetup() + + override fun scissorArea(): ScreenRectangle? = scissor + + override fun bounds(): ScreenRectangle = ScreenRectangle( + x0.toInt(), y0.toInt(), (x1 - x0).toInt().coerceAtLeast(1), (y1 - y0).toInt().coerceAtLeast(1) + ) +} + +object DissolveRect { + private val noiseTextureId = Matrix.identifier("textures/noise/perlin_noise.png") + + val pipeline: RenderPipeline = RenderPipeline.builder(RenderPipelines.GUI_TEXTURED_SNIPPET) + .withLocation(Matrix.identifier("pipeline/gui_dissolve_rect")) + .withVertexShader(Matrix.identifier("gui/dissolve_rect")) + .withFragmentShader(Matrix.identifier("gui/dissolve_rect")) + .withVertexBinding(0, DefaultVertexFormat.POSITION_TEX_COLOR_NORMAL) + .build() + + fun noiseTextureSetup(): TextureSetup { + // The noise drift samples beyond [0,1], so the sampler must repeat (the 1.21 GL + // texture defaulted to GL_REPEAT). + val view = minecraft.textureManager.getTexture(noiseTextureId).textureView + return TextureSetup.singleTexture(view, RenderSystem.getSamplerCache().getRepeat(FilterMode.LINEAR)) + } + + /** + * Mod pipelines are built after the reload that compiles the vanilla-registered ones, so + * compile explicitly against the ShaderManager sources (cached by the device afterwards). + */ + fun precompile() { + RenderSystem.getDevice().precompilePipeline(pipeline) { id, type -> + minecraft.shaderManager.getShader(id, type) + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt index fd19e54b..11f1f14b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/item/VortexItemRenderer.kt @@ -5,44 +5,31 @@ package heckerpowered.matrix.client.render.item -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry.DynamicItemRenderer -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.model.json.ModelTransformationMode -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.item.ItemStack - -object VortexItemRenderer : DynamicItemRenderer { - override fun render(itemStack: ItemStack, modelTransformationMode: ModelTransformationMode, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, light: Int, overlay: Int) { - // matrixStack.push() -// - // val model = minecraft.itemRenderer.getModel(ItemStack(Items.ITEM_FRAME), minecraft.world, minecraft.player, 0) -// - // // matrixStack.scale(0.5f, 0.5f, 0.5f) - // // model.transformation.getTransformation(modelTransformationMode).apply(false, matrixStack) - // // matrixStack.translate(0.5f, 0.5f, 0.5f) -// - // val matrices = MatrixStack() - // val matrix = matrices.peek().positionMatrix -// - // val builder = Tessellator.getInstance() - // val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) -// - // buffer.vertex(matrix, -1F, -1F, 0F).texture(0F, 0F) - // buffer.vertex(matrix, 1F, -1F, 0F).texture(1F, 0F) - // buffer.vertex(matrix, 1F, 1F, 0F).texture(1F, 1F) - // buffer.vertex(matrix, -1F, 1F, 0F).texture(0F, 1F) -// - // buffer.vertex(matrix, -1F, 1F, 0F).texture(0F, 1F) - // buffer.vertex(matrix, 1F, 1F, 0F).texture(1F, 1F) - // buffer.vertex(matrix, 1F, -1F, 0F).texture(1F, 0F) - // buffer.vertex(matrix, -1F, -1F, 0F).texture(0F, 0F) -// - // RenderSystem.disableBlend() - // RenderSystem.disableDepthTest() - // VortexRenderer.vortexShader.enableShader() - // BufferRenderer.draw(buffer.end()) - // VortexRenderer.vortexShader.disableShader() -// - // matrixStack.pop() - } -} \ No newline at end of file +// TODO(26.2): VortexItemRenderer had no live body even before this port (its `render()` was +// entirely commented out — see git history), so there is nothing to carry over behaviorally. +// It is left unported rather than stubbed with a fake API surface because the 26.2 replacement +// mechanism is structurally different, not just renamed: +// +// - `net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry` / +// `DynamicItemRenderer` (imperative "register a renderer object for this Item" hook) is +// gone entirely — not present anywhere under `net.fabricmc.fabric.api.client.rendering.v1` +// in the 26.2 Fabric API. +// - Custom per-item GPU rendering is now done via +// `net.minecraft.client.renderer.special.SpecialModelRenderer`, which is wired up +// *data-driven*: a `SpecialModelRenderer.Unbaked` implementation registered as a +// `MapCodec` in `SpecialModelRenderers.ID_MAPPER` (populated from +// `SpecialModelRenderers.bootstrap()`, a vanilla-internal static list — no Fabric API +// extension point for adding entries was found in the client.rendering.v1 dump), *plus* +// the item's JSON model (`assets/matrix/models/item/...json`) needs a +// `"type": "minecraft:special"` model referencing that registered id. +// +// Reintroducing the vortex item visual therefore needs a resources/datagen change (new item +// model JSON + registered Unbaked/codec type) in addition to Kotlin code, which is out of +// scope for this renderer-only port pass. See scratchpad render-port-pattern.md priority 6. +// +// If/when this is revisited: `MagicTalismanItem` (heckerpowered.matrix.common.item) is the +// item this used to decorate; `VortexRenderer.vortexShader` (heckerpowered.matrix.client.render.shader, +// not yet ported either) held the shader that painted the vortex effect into the quad this +// used to draw via Tessellator/BufferRenderer (also gone, see LegacyMatrixUIRenderer.kt notes). +// The MatrixClient.kt registration line (`BuiltinItemRendererRegistry.INSTANCE.register(...)`) +// has been removed to match. diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt index e755060f..a1a09cef 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/BloomEffect.kt @@ -5,96 +5,197 @@ package heckerpowered.matrix.client.render.post -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.pipeline.TextureTarget +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.event.InitAttachmentCallback import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.render.GuideLineRenderer +import heckerpowered.matrix.client.render.MipmapsFramebuffer import heckerpowered.matrix.client.render.PostProcessRenderer +import heckerpowered.matrix.client.render.mainRenderTarget import heckerpowered.matrix.client.render.recommendMipLevel -import heckerpowered.matrix.client.render.shader.TentShader -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider +import heckerpowered.matrix.core.FramebufferExtension import heckerpowered.matrix.core.FramebufferExtension.Companion.allocateMipmaps import heckerpowered.matrix.core.FramebufferExtension.Companion.beginReadLod import heckerpowered.matrix.core.FramebufferExtension.Companion.beginWriteLod -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* import org.slf4j.MarkerFactory object BloomEffect { private val MARKER = MarkerFactory.getMarker("BLOOM_RENDERER") - private val brightFramebuffer = PostProcessRenderer.createManagedFramebuffer() - val bloomDownFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() - val bloomUpFramebuffer: Framebuffer = PostProcessRenderer.createManagedFramebuffer() + // 1.21's bright pass was HDR (the framebuffer mixin made every mod FBO RGBA16F). This + // target only ever receives BlitProgram output (never vanilla RGBA8-declared pipelines), + // so unlike createManagedFramebuffer it can keep the HDR format on 26.2 — required for the + // guide-line overlay's 8x energy to survive into the (already HDR) mip chain below. + private val brightFramebuffer: RenderTarget = TextureTarget( + "matrix bloom bright", + minecraft.window.width, + minecraft.window.height, + true, + FramebufferExtension.framebufferColorFormat + ).also(PostProcessRenderer::manageFramebuffer) + + /** + * Source framebuffer + LOD for [bloomTentBlurShader]'s `framebuffer` sampler. + * + * The shared `tentBlurShader` in RenderExtensions.kt reads a module-private + * `primaryFramebuffer` that only the `blend`/`copyTo`-style infix helpers in that file can + * set, so bloom keeps its own tent-blur program instance (mirroring the old dedicated + * `TentShader` object) with locally settable source state instead. + */ + // Explicit per-level source view: the old GL chain attached READ (level n) and DRAW + // (level m) FBOs independently; MipmapsFramebuffer's shared levelOfDetail view can only + // point at one level, so the tent samples an explicit viewAt() while the shared view + // stays on the write level. + private var tentSourceView: GpuTextureView? = null + private var tentLevelOfDetail = 0F + + private val bloomTentBlurShader by lazy { + BlitProgram( + "post/blur/tent.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = lod + putVec4(tentLevelOfDetail, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + } + ), + textures = arrayOf( + TextureProvider("framebuffer", bilinear = true) { tentSourceView } + ) + ) + } + + // TODO(26.2): verify against final MipmapsFramebuffer API. Old code used a single managed + // RenderTarget plus manual per-level FBO attachment redirection (beginWriteLod/beginReadLod + // against raw GL). MipmapsFramebuffer owns a real per-level GpuTextureView chain and exposes + // a settable `levelOfDetail` that beginWriteLod/beginReadLod (see FramebufferExtension.kt) + // already redirect to when the target is a MipmapsFramebuffer, so those helper calls below + // are kept as-is and now have real per-level effect instead of being GL no-ops. + // Window dimensions, NOT mainRenderTarget's: this object initializes during mod init, + // when the main render target still reports 1x1 — and with no window-resize event ever + // firing afterwards on a fixed-size session, the whole bloom pyramid stayed 1x1 (the + // composite then painted a uniform fullscreen tint instead of a halo). brightFramebuffer + // above already used the window for exactly this reason. + val bloomDownFramebuffer = MipmapsFramebuffer( + "matrix bloom down", minecraft.window.width, minecraft.window.height, true + ) + val bloomUpFramebuffer = MipmapsFramebuffer( + "matrix bloom up", minecraft.window.width, minecraft.window.height, true + ) init { InitAttachmentCallback.EVENT.register(::onInitAttachment) + PostProcessRenderer.manageFramebuffer(bloomDownFramebuffer) + PostProcessRenderer.manageFramebuffer(bloomUpFramebuffer) - bloomDownFramebuffer.resize(bloomDownFramebuffer.textureWidth, bloomDownFramebuffer.textureHeight, true) - bloomUpFramebuffer.resize(bloomDownFramebuffer.textureWidth, bloomDownFramebuffer.textureHeight, true) + bloomDownFramebuffer.resize(bloomDownFramebuffer.width, bloomDownFramebuffer.height) + bloomUpFramebuffer.resize(bloomDownFramebuffer.width, bloomDownFramebuffer.height) } - private fun onInitAttachment(framebuffer: Framebuffer) { + private fun onInitAttachment(framebuffer: RenderTarget) { if (framebuffer != bloomDownFramebuffer && framebuffer != bloomUpFramebuffer) { return } + // TODO(26.2): FramebufferExtension.allocateMipmaps pending port — MipmapsFramebuffer + // always allocates its full mip chain in createBuffers(), so this flag is redundant for + // bloomDown/bloomUpFramebuffer specifically, but kept for source parity / Mixin callers. framebuffer.allocateMipmaps = true - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + + // TODO(26.2): texture filter mode (linear) no longer settable via direct GL call; + // TextureProvider(bilinear=true) on the SAMPLING side achieves the same visual effect + // for reads of this texture — verify all TextureProviders reading bloomDownFramebuffer/ + // bloomUpFramebuffer pass bilinear=true (done below: brightnessShader's own read is via + // the tentBlurShader/copyFramebuffer paths, both of which already sample bilinear=true + // per RenderExtensions.kt's shared tentBlurShader definition). } - var brightnessPassFramebuffer: Framebuffer = minecraft.framebuffer + var brightnessPassFramebuffer: RenderTarget = minecraft.mainRenderTarget var brightnessThreshold = 0F var bloomIntensity = 1.0F + /** + * True only around MatrixHud's end-of-HUD bloom pass. In 1.21 the 8x guide-line energy + * lived inside hudFramebuffer/blurFramebuffer (every mod FBO was RGBA16F) and therefore + * only ever entered THAT bloom (threshold 1) — never the world/screen-effect passes, + * which run before the HUD callback draws the lines. This flag keeps that scoping so the + * glow is neither double-added nor visible on passes that never saw it pre-migration. + */ + var includeGuideLineOverlay = false + + /** + * Copies an explicit mip level of [bloomUpFramebuffer] into whatever level + * [bloomUpFramebuffer]'s `levelOfDetail` currently points at. + * + * [MipmapsFramebuffer] exposes a single `colorTextureView` selected by [levelOfDetail], so + * [PostProcessRenderer.copyFramebuffer] cannot alias two different levels of the same + * framebuffer as source and destination (the write-side `beginWriteLod` call would repoint + * the read-side view too). This reads an explicit level via [MipmapsFramebuffer.viewAt] + * instead, replacing the old GL code's independent `GL_READ_FRAMEBUFFER`/ + * `GL_DRAW_FRAMEBUFFER` attachment aliasing trick. + */ + private var upsampleCopySourceLevel = 0 + private val upsampleCopyShader by lazy { + BlitProgram( + "blit/blit_no_depth.fsh", + uniforms = arrayOf(UniformProvider("BlitConfig") { putFloat(0F) }), + textures = arrayOf( + // bilinear: the old chain set GL_LINEAR min/mag on bloomUp, so the 2x + // level-to-level upscale interpolated — NEAREST here makes the halo blocky. + TextureProvider("framebuffer", bilinear = true) { bloomUpFramebuffer.viewAt(upsampleCopySourceLevel) } + ) + ) + } + private val brightnessShader by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh", GL_FRAGMENT_SHADER), + "post/bloom/bloom_brightness_pass.fsh", uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - val framebuffer = brightnessPassFramebuffer - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebuffer.colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("threshold") { pointer -> - glUniform1f(pointer, brightnessThreshold) - }, - UniformProvider("intensity") { pointer -> - glUniform1f(pointer, bloomIntensity) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = vec4(bloomThreshold, bloomIntensity, 0, 0) + putVec4(brightnessThreshold, bloomIntensity, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("framebuffer", bilinear = true) { brightnessPassFramebuffer.colorTextureView } ) ) } - private fun clearBloomPasses(mipLevel: Int) { - brightFramebuffer.clear(true) + private fun clearBloomPasses() { + PostProcessRenderer.clear(brightFramebuffer) - for (i in 0..= 1 would accumulate additive upsample energy + // frame over frame), so the per-level clears live in MipmapsFramebuffer.clearAllLevels. + bloomDownFramebuffer.clearAllLevels() + bloomUpFramebuffer.clearAllLevels() } private fun computeBloomPass() { PostProcessRenderer.renderShaderToFramebuffer(brightnessShader, brightFramebuffer) + // Guide lines: 1.21 fed bloom by drawing them 8x overbright into the (HDR) HUD + // framebuffer, whose blurFramebuffer copy this brightness pass reads during the HUD + // composite; on 26.2 that energy lives in the RGBA16F guide-line overlay instead, + // added on top of the brightness output (GL_ONE/GL_ONE, the old additive composite) + // so it enters the mip bloom chain — HUD pass only, see includeGuideLineOverlay. + if (includeGuideLineOverlay && GuideLineRenderer.overlayActive) { + PostProcessRenderer.copyFramebuffer(GuideLineRenderer.overlayFramebuffer, brightFramebuffer, BlendFunction.ADDITIVE) + } } private fun prepareDownsamplePass() { - TentShader.framebufferObject = brightFramebuffer.colorAttachment bloomDownFramebuffer.beginWriteLod(0) PostProcessRenderer.copyFramebuffer(brightFramebuffer, bloomDownFramebuffer) } @@ -102,57 +203,61 @@ object BloomEffect { private fun generateDownsamplePasses(mipLevel: Int) { prepareDownsamplePass() - TentShader.levelOfDetail = .0F for (i in 1..main composite and every + // later copy in the session samples its source at a stale deep LOD. + PostProcessRenderer.levelOfDetail = 0F } private fun generateMipmaps(mipLevel: Int) { @@ -161,16 +266,25 @@ object BloomEffect { } fun renderBloom() { - StateIsolation.isolate( - FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), - BlendState.captureSnapshot(), BlendFuncSeparateState.captureSnapshot() - ) { - val mipLevel = minecraft.framebuffer.recommendMipLevel() - clearBloomPasses(mipLevel) - computeBloomPass() - generateMipmaps(mipLevel) - resetBloomPasses() + val main = minecraft.mainRenderTarget + // Self-healing sizing: these targets are created during lazy class-init, whose timing + // relative to real window sizing differs per backend (on Vulkan they came up 1x1 and + // MISSED the startup resize event — the whole pyramid then composited one + // uninitialized texel fullscreen: no halo, and random white flashes). Never trust + // creation-time dimensions; align with the main target at use time. + if (brightFramebuffer.width != main.width || brightFramebuffer.height != main.height) { + brightFramebuffer.resize(main.width, main.height) + } + if (bloomDownFramebuffer.width != main.width || bloomDownFramebuffer.height != main.height) { + bloomDownFramebuffer.resize(main.width, main.height) + bloomUpFramebuffer.resize(main.width, main.height) } + + val mipLevel = main.recommendMipLevel() + clearBloomPasses() + computeBloomPass() + generateMipmaps(mipLevel) + resetBloomPasses() } var renderBloom = false diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/CollapseEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/CollapseEffectRenderer.kt index d85e5179..dab86593 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/CollapseEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/CollapseEffectRenderer.kt @@ -5,39 +5,49 @@ package heckerpowered.matrix.client.render.post -import heckerpowered.matrix.client.shader.* +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.client.minecraft +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.TextureProvider +import heckerpowered.matrix.client.shader.UniformProvider +import heckerpowered.matrix.client.shader.putInverseProjectionMatrix +import heckerpowered.matrix.client.shader.putInverseViewMatrix import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import org.lwjgl.opengl.GL11 -import org.lwjgl.opengl.GL13 -import org.lwjgl.opengl.GL20 -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER +// 26.2: post/collapse.fsh declares +// layout(std140) uniform MatrixPostUniforms { +// mat4 inverseProjectionMatrix; mat4 inverseViewMatrix; vec4 MatrixPostData0; vec4 MatrixPostData1; +// }; +// #define playerPosition MatrixPostData0.xyz +// #define dissolveFactor MatrixPostData0.w +// #define resolution MatrixPostData1.xy +// Note this shader has no `noiseTexture` sampler despite the old Kotlin wiring one up - the fragment +// shader synthesizes its own dissolve noise procedurally (valueNoise/hash13) and never samples a +// noise texture. The old `noiseTexture` UniformProvider was dead code; dropped here rather than +// carried forward as a TextureProvider with no matching sampler in the .fsh (BlitProgram only binds +// textures whose name matches a parsed sampler, so this would have been a silent no-op anyway). object CollapseEffectRenderer { - var depthAttachment: Int = -1 + var depthAttachment: GpuTextureView? = null val dissolveFactor = SimpleDoubleAnimation(initValue = 0.0) val shader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/collapse.fsh", GL_FRAGMENT_SHADER), + "post/collapse.fsh", uniforms = arrayOf( - UniformProvider("depthAttachment") { pointer -> - GL13.glActiveTexture(GL13.GL_TEXTURE0) - GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthAttachment) - GL20.glUniform1i(pointer, 0) - }, - inverseProjectionMatrixProvider, - inverseViewMatrixProvider, - resolutionProvider, - playerPositionProvider, - UniformProvider("dissolveFactor") { pointer -> - GL20.glUniform1f(pointer, dissolveFactor.animatedValue.toFloat()) - }, - UniformProvider("noiseTexture") { pointer -> - GL13.glActiveTexture(GL13.GL_TEXTURE0 + 1) - GL11.glBindTexture(GL11.GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - GL20.glUniform1i(pointer, 1) + UniformProvider("MatrixPostUniforms") { + putInverseProjectionMatrix() + putInverseViewMatrix() + val playerPosition = minecraft.player?.position() + putVec4( + playerPosition?.x?.toFloat() ?: 0F, + playerPosition?.y?.toFloat() ?: 0F, + playerPosition?.z?.toFloat() ?: 0F, + dissolveFactor.animatedValue.toFloat() + ) + putVec4(minecraft.window.width.toFloat(), minecraft.window.height.toFloat(), 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("depthAttachment") { depthAttachment } ) ) } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/EntityPostProcessEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/EntityPostProcessEffectRenderer.kt index 98c0ae8d..b5530224 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/EntityPostProcessEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/EntityPostProcessEffectRenderer.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.client.render.post -import net.minecraft.entity.Entity +import net.minecraft.world.entity.Entity object EntityPostProcessEffectRenderer { @JvmStatic diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/OverlayPostProcessEffectRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/OverlayPostProcessEffectRenderer.kt index c698b69b..cae0edf7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/OverlayPostProcessEffectRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/OverlayPostProcessEffectRenderer.kt @@ -8,10 +8,10 @@ package heckerpowered.matrix.client.render.post import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.render.mainRenderTarget import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.client.DeltaTracker import java.time.Duration object OverlayPostProcessEffectRenderer { @@ -24,8 +24,8 @@ object OverlayPostProcessEffectRenderer { // HudRenderCallback.EVENT.register(::onHudRender) } - private fun onHudRender(drawContext: DrawContext, renderTickCounter: RenderTickCounter) { - if (minecraft.currentScreen == null) { + private fun onHudRender(drawContext: GuiGraphicsExtractor, renderTickCounter: DeltaTracker) { + if (minecraft.gui.screen() == null) { dissolveAnimation.value = 1.0 previousState = false } else if (!previousState) { @@ -34,19 +34,24 @@ object OverlayPostProcessEffectRenderer { } } + // 26.2: beginWrite(false) used to redirect subsequent vanilla-overlay draws into `framebuffer`; + // the vanilla-supported equivalent is the RenderSystem output-texture override (see + // heckerpowered.matrix.client.core.FramebufferSpoof for the established idiom). endRenderOverlay + // clears the override before compositing. @JvmStatic fun beginRenderOverlay() { - framebuffer.beginWrite(false) + PostProcessRenderer.clear(framebuffer) + RenderSystem.outputColorTextureOverride = framebuffer.colorTextureView + RenderSystem.outputDepthTextureOverride = framebuffer.depthTextureView } @JvmStatic fun endRenderOverlay() { - TextureDissolveShader.colorAttachment = framebuffer.colorAttachment + RenderSystem.outputColorTextureOverride = null + RenderSystem.outputDepthTextureOverride = null + + TextureDissolveShader.colorAttachment = framebuffer.colorTextureView TextureDissolveShader.dissolveFactor = dissolveAnimation.animatedValue.toFloat() - TextureDissolveShader.program.enableShader() - BlitProgram.blit() - TextureDissolveShader.program.disableShader() - RenderSystem.disableBlend() - minecraft.framebuffer.beginWrite(false) + TextureDissolveShader.program.drawTo(minecraft.mainRenderTarget) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScaleSampling.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScaleSampling.kt index 6a2cc443..6233e8af 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScaleSampling.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScaleSampling.kt @@ -5,20 +5,12 @@ package heckerpowered.matrix.client.render.post -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.platform.GlStateManager.Viewport -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL31 +import com.mojang.blaze3d.pipeline.RenderTarget object ScaleSampling { private val downScalingFramebuffers = mutableMapOf() @@ -27,13 +19,12 @@ object ScaleSampling { fun getDownScalingFramebuffer(scaling: Double): ScalingFramebuffer { return downScalingFramebuffers.computeIfAbsent(scaling) { val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, + "matrix downscale $scaling", + minecraft.window.width, + minecraft.window.height, true, - MinecraftClient.IS_SYSTEM_MAC, scaling ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) PostProcessRenderer.manageFramebuffer(framebuffer) framebuffer } @@ -42,13 +33,12 @@ object ScaleSampling { fun getUpScalingFramebuffer(scaling: Double): ScalingFramebuffer { return upScalingFramebuffers.computeIfAbsent(scaling) { val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, + "matrix upscale $scaling", + minecraft.window.width, + minecraft.window.height, true, - MinecraftClient.IS_SYSTEM_MAC, scaling ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) PostProcessRenderer.manageFramebuffer(framebuffer) framebuffer } @@ -56,87 +46,74 @@ object ScaleSampling { fun createManagedScalingFramebuffer(scaling: Double): ScalingFramebuffer { val framebuffer = ScalingFramebuffer( - minecraft.window.framebufferWidth, - minecraft.window.framebufferHeight, + "matrix managed scale $scaling", + minecraft.window.width, + minecraft.window.height, true, - MinecraftClient.IS_SYSTEM_MAC, scaling ) - framebuffer.setClearColor(.0F, .0F, .0F, .0F) PostProcessRenderer.manageFramebuffer(framebuffer) return framebuffer } fun clearAll() { - downScalingFramebuffers.values.forEach { it.clear(false) } - upScalingFramebuffers.values.forEach { it.clear(false) } + downScalingFramebuffers.values.forEach { PostProcessRenderer.clear(it) } + upScalingFramebuffers.values.forEach { PostProcessRenderer.clear(it) } } val framebuffer = PostProcessRenderer.createManagedFramebuffer() var levelOfDetail = 0F - private var sourceFramebuffer: Framebuffer? = null - private var targetFramebuffer: Framebuffer? = null + private var sourceFramebuffer: RenderTarget? = null + private var targetFramebuffer: RenderTarget? = null - private val sourceFramebufferProvider = UniformProvider("framebuffer") { pointer -> - val sourceFramebuffer = sourceFramebuffer ?: return@UniformProvider - - GL31.glActiveTexture(GlConst.GL_TEXTURE0) - GL31.glBindTexture(GlConst.GL_TEXTURE_2D, sourceFramebuffer.colorAttachment) - - RenderSystem.glUniform1i(pointer, 0) - } - - private val sourceResolutionProvider = UniformProvider("sourceResolution") { pointer -> - val framebuffer = sourceFramebuffer ?: return@UniformProvider - - GL31.glUniform2f(pointer, framebuffer.textureWidth.toFloat(), framebuffer.textureHeight.toFloat()) - } - - private val targetResolutionProvider = UniformProvider("targetResolution") { pointer -> - val framebuffer = targetFramebuffer ?: return@UniformProvider - - GL31.glUniform2f(pointer, framebuffer.textureWidth.toFloat(), framebuffer.textureHeight.toFloat()) + private val sourceFramebufferProvider = TextureProvider("framebuffer") { + sourceFramebuffer?.colorTextureView } // Bi-linear sampling method val bilinearSample by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sampling/bilinear.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(sourceFramebufferProvider, sourceResolutionProvider, targetResolutionProvider) + "post/sampling/bilinear.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = vec4(sourceResolution, targetResolution) + putVec4( + sourceFramebuffer?.width?.toFloat() ?: 0F, + sourceFramebuffer?.height?.toFloat() ?: 0F, + targetFramebuffer?.width?.toFloat() ?: 0F, + targetFramebuffer?.height?.toFloat() ?: 0F + ) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + } + ), + textures = arrayOf(sourceFramebufferProvider) ) } val textureLod by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/lower_sampling/lod.fsh", GL_FRAGMENT_SHADER), + "post/lower_sampling/lod.fsh", uniforms = arrayOf( - sourceFramebufferProvider, - UniformProvider("levelOfDetail") { pointer -> - GL31.glUniform1f(pointer, levelOfDetail) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = levelOfDetail + putVec4(levelOfDetail, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } - ) + ), + textures = arrayOf(sourceFramebufferProvider) ) } - fun sample(sourceFramebuffer: Framebuffer, targetFramebuffer: Framebuffer, sampler: BlitProgram) { - val previousFramebuffer = GlStateManager.getBoundFramebuffer() - val previousViewportX = Viewport.getX() - val previousViewportY = Viewport.getY() - val previousViewportWidth = Viewport.getWidth() - val previousViewportHeight = Viewport.getHeight() - + fun sample(sourceFramebuffer: RenderTarget, targetFramebuffer: RenderTarget, sampler: BlitProgram) { this.sourceFramebuffer = sourceFramebuffer this.targetFramebuffer = targetFramebuffer - targetFramebuffer.beginWrite(true) - sampler.blit() - targetFramebuffer.endWrite() - - GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, previousFramebuffer) - GlStateManager._viewport(previousViewportX, previousViewportY, previousViewportWidth, previousViewportHeight) + sampler.drawTo(targetFramebuffer) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt index 70f049f5..c13ca3e9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ScalingFramebuffer.kt @@ -5,12 +5,15 @@ package heckerpowered.matrix.client.render.post +import heckerpowered.matrix.client.render.textureHeight +import heckerpowered.matrix.client.render.textureWidth +import heckerpowered.matrix.core.FramebufferExtension import heckerpowered.matrix.core.approximatelyEqual -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gl.SimpleFramebuffer +import com.mojang.blaze3d.pipeline.TextureTarget import kotlin.math.floor -class ScalingFramebuffer(width: Int, height: Int, useDepth: Boolean, getError: Boolean = MinecraftClient.IS_SYSTEM_MAC, private val resolutionScaling: Double) : SimpleFramebuffer(width, height, useDepth, getError) { +class ScalingFramebuffer(label: String, width: Int, height: Int, useDepth: Boolean, private val resolutionScaling: Double) : + TextureTarget(label, width, height, useDepth, FramebufferExtension.framebufferColorFormat) { val actualWidth get() = floor(textureWidth * resolutionScaling).toInt() @@ -18,17 +21,17 @@ class ScalingFramebuffer(width: Int, height: Int, useDepth: Boolean, getError: B get() = floor(textureHeight * resolutionScaling).toInt() init { - resize(width, height, getError) + resize(width, height) } - override fun resize(width: Int, height: Int, getError: Boolean) { + override fun resize(width: Int, height: Int) { if (resolutionScaling.approximatelyEqual(.0)) { - super.resize(width, height, getError) + super.resize(width, height) return } val scaledWidth = floor(width * resolutionScaling).toInt().coerceAtLeast(1) val scaledHeight = floor(height * resolutionScaling).toInt().coerceAtLeast(1) - super.resize(scaledWidth, scaledHeight, getError) + super.resize(scaledWidth, scaledHeight) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt index 7aeb3b15..b82b5459 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ShockwaveRenderer.kt @@ -5,15 +5,16 @@ package heckerpowered.matrix.client.render.post +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.* import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.core.times import org.joml.Vector3f import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* object ShockwaveRenderer { - var depthAttachment: Int = -1 + var depthAttachment: GpuTextureView? = null var wavePosition: Vector3f = Vector3f() var waveColor = Vector4f(0.1F, 0.5F, 1.0F, 1.0F) * 4.0F @@ -21,28 +22,27 @@ object ShockwaveRenderer { var waveSize = SimpleDoubleAnimation() val shockwaveShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/shockwave.fsh", GL_FRAGMENT_SHADER), + "post/shockwave.fsh", uniforms = arrayOf( - UniformProvider("depthAttachment") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, depthAttachment) - glUniform1i(pointer, 0) - }, - inverseProjectionMatrixProvider, - inverseViewMatrixProvider, - UniformProvider("wavePosition") { pointer -> - glUniform3f(pointer, wavePosition.x, wavePosition.y, wavePosition.z) - }, - UniformProvider("waveColor") { pointer -> - glUniform4f(pointer, waveColor.x, waveColor.y, waveColor.z, waveColor.w) - }, - UniformProvider("waveRadius") { pointer -> - glUniform1f(pointer, waveRadius.animatedValue.toFloat()) - }, - UniformProvider("waveSize") { pointer -> - glUniform1f(pointer, waveSize.animatedValue.toFloat()) + UniformProvider("MatrixPostUniforms") { + putInverseProjectionMatrix() + putInverseViewMatrix() + // MatrixPostData0.xyz = wavePosition, MatrixPostData0.w = waveRadius + putVec4(wavePosition.x, wavePosition.y, wavePosition.z, waveRadius.animatedValue.toFloat()) + // MatrixPostData1 = waveColor + putVec4(waveColor.x, waveColor.y, waveColor.z, waveColor.w) + // MatrixPostData2.x = waveSize + putVec4(waveSize.animatedValue.toFloat(), 0F, 0F, 0F) } + ), + textures = arrayOf( + // Pre-existing bug fixed: the .fsh declares `uniform sampler2D framebuffer;` (the + // scene color it additively blends the wave color into) but the old Kotlin uniform + // array never wired it up. Every other post shader in this codebase sources its + // "previous pass output" sampler from PostProcessRenderer.framebufferProvider + // (see RenderExtensions.kt / PostProcessRenderer.kt); used here for the same role. + heckerpowered.matrix.client.render.framebufferProvider, + TextureProvider("depthAttachment") { depthAttachment } ) ) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/TextureDissolveShader.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/TextureDissolveShader.kt index e37831f4..d331488f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/TextureDissolveShader.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/TextureDissolveShader.kt @@ -5,33 +5,35 @@ package heckerpowered.matrix.client.render.post +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.client.shader.BlitProgram import heckerpowered.matrix.client.shader.DissolveShader -import heckerpowered.matrix.client.shader.Program -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import org.lwjgl.opengl.GL46.* +// 26.2: post/dissolve/texture_dissolve.fsh declares +// layout(std140) uniform MatrixPostUniforms { vec4 dissolveParams0; vec4 dissolveEmissiveColor; }; +// #define dissolveFactor dissolveParams0.x / emissiveRange .y / pixelStrength .z / detialStrength .w +// The old code never actually supplied emissiveRange/pixelStrength/detialStrength/emissiveColor as +// uniforms (they were presumably left at GLSL default-zero under the pre-std140 pipeline), so this +// port keeps the same effective values: dissolveFactor from state, the rest zeroed/white to preserve +// prior (likely degenerate/no-op) visuals bit-for-bit. See MatrixPostUniforms.kt@f25647a "post/dissolve/texture_dissolve" +// for the reference slot layout used here. object TextureDissolveShader { - var colorAttachment: Int = 0 + var colorAttachment: GpuTextureView? = null var dissolveFactor: Float = 0F - val program = Program( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/dissolve/texture_dissolve.fsh", GL_FRAGMENT_SHADER), + val program = BlitProgram( + "post/dissolve/texture_dissolve.fsh", uniforms = arrayOf( - UniformProvider("colorAttachment") { pointer -> - glActiveTexture(GL_TEXTURE1) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 1) - }, - UniformProvider("noiseTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - glUniform1i(pointer, 0) - }, - UniformProvider("dissolveFactor") { pointer -> - glUniform1f(pointer, dissolveFactor) + UniformProvider("MatrixPostUniforms") { + putVec4(dissolveFactor, 0.05F, 16.0F, 1.0F) + putVec4(0F, 0.5F, 1.0F, 1.0F) } + ), + textures = arrayOf( + TextureProvider("colorAttachment") { colorAttachment }, + TextureProvider("noiseTexture") { DissolveShader.perlinNoiseTextureView } ) ) } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt index 56a1ef4f..6b08c856 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/post/ToneMapping.kt @@ -5,18 +5,11 @@ package heckerpowered.matrix.client.render.post -import com.mojang.blaze3d.platform.GlConst import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* +import com.mojang.blaze3d.pipeline.RenderTarget object ToneMapping { var exposureLinear: Float = 1.0f @@ -24,36 +17,27 @@ object ToneMapping { private val toneMappingProgram by lazy { BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh", GL_FRAGMENT_SHADER), + "post/tone_mapping/aces_filmic.fsh", uniforms = arrayOf( - UniformProvider("hdrScene") { location -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, currentSource.colorAttachment) - glUniform1i(location, 0) - }, - UniformProvider("exposure") { location -> - glUniform1f(location, exposureLinear) - }, - UniformProvider("exposureEv") { location -> - glUniform1f(location, exposureEv) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = vec4(exposure, exposureEv, 0, 0) + putVec4(exposureLinear, exposureEv, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("hdrScene") { currentSource.colorTextureView } ) ) } - private lateinit var currentSource: Framebuffer + private lateinit var currentSource: RenderTarget val toneMapFramebuffer = PostProcessRenderer.createManagedFramebuffer() - fun render(sourceFramebuffer: Framebuffer, targetFramebuffer: Framebuffer) { + fun render(sourceFramebuffer: RenderTarget, targetFramebuffer: RenderTarget) { currentSource = sourceFramebuffer - StateIsolation.isolate( - FramebufferState(targetFramebuffer), - ViewportState(targetFramebuffer), - BlendState.captureSnapshot(), - BlendFuncSeparateState.captureSnapshot() - ) { - PostProcessRenderer.renderShaderToFramebuffer(toneMappingProgram, targetFramebuffer, false) - } + PostProcessRenderer.renderShaderToFramebuffer(toneMappingProgram, targetFramebuffer, null) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt index 7ea2d207..d38ebebe 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/GaussianBlurRenderer.kt @@ -5,16 +5,17 @@ package heckerpowered.matrix.client.render.shader +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.render.post.ScaleSampling import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider import org.joml.Vector2f -import org.lwjgl.opengl.GL46.* object GaussianBlurRenderer { - var colorAttachment: Int = 0 + /** Color attachment to blur, kept as `colorAttachment` for source compatibility with existing call sites. */ + var colorAttachment: GpuTextureView? = null var gaussianKernel: FloatArray = FloatArray(0) var direction: Vector2f = Vector2f(1F, 0F) @@ -25,23 +26,35 @@ object GaussianBlurRenderer { val fullPong = PostProcessRenderer.createManagedFramebuffer() val gaussianBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/gaussian_blur.fsh", GL_FRAGMENT_SHADER), + "post/blur/gaussian_blur.fsh", uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("kernel") { pointer -> - glUniform1fv(pointer, gaussianKernel) - }, - UniformProvider("kernelSize") { pointer -> - glUniform1i(pointer, (gaussianKernel.size - 1).coerceAtLeast(0)) - }, - UniformProvider("direction") { pointer -> - glUniform2f(pointer, direction.x, direction.y) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = vec4(direction.x, direction.y, kernelSize, 0) + val kernelSize = (gaussianKernel.size - 1).coerceIn(0, 48) + putVec4(direction.x, direction.y, kernelSize.toFloat(), 0F) + + // MatrixPostData1..13 = kernel[0..48] packed 4 floats per vec4. + if (gaussianKernel.isEmpty()) { + putVec4(1.0F, 0F, 0F, 0F) + repeat(12) { putVec4(0F, 0F, 0F, 0F) } + } else { + var i = 0 + while (i < 52) { + putVec4( + gaussianKernel.getOrElse(i) { 0F }, + gaussianKernel.getOrElse(i + 1) { 0F }, + gaussianKernel.getOrElse(i + 2) { 0F }, + gaussianKernel.getOrElse(i + 3) { 0F } + ) + i += 4 + } + } } + ), + textures = arrayOf( + // The pre-26.2 code forced GL_LINEAR on every blur-chain texture; filtering is + // per-sampler now, so bilinear here preserves the original sampling behavior. + TextureProvider("framebuffer", bilinear = true) { colorAttachment } ) ) @@ -143,4 +156,4 @@ object GaussianBlurRenderer { val (kernelSize, sigma) = computeBlurParameters(strength, maxKernelSize, maxSigma) return generateSymmetricGaussianKernel(kernelSize, sigma) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt index 4888d727..78354480 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/OpacityMaskRenderer.kt @@ -5,12 +5,12 @@ package heckerpowered.matrix.client.render.shader +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.Program -import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* +import heckerpowered.matrix.client.shader.TextureProvider /** * A renderer that applies an opacity mask to discard fully transparent or fully black pixels. @@ -26,82 +26,86 @@ import org.lwjgl.opengl.GL46.* * - `colorFramebuffer`: Contains the source color data to be masked. * * During rendering, the appropriate color attachments from each framebuffer are bound to shader uniforms, - * and a full-screen blit is performed with the mask applied. + * and a full-screen draw is performed with the mask applied into an explicit target. * - * @see Program - * @see Framebuffer - * @see UniformProvider + * @see BlitProgram + * @see RenderTarget */ object OpacityMaskRenderer { /** - * The OpenGL texture ID for the color attachment from the opacity mask framebuffer. + * The color attachment from the opacity mask framebuffer. */ - private var opacityMaskColorAttachment: Int = -1 + private var opacityMaskColorAttachmentView: GpuTextureView? = null /** - * The OpenGL texture ID for the color attachment from the color framebuffer. + * The color attachment from the color framebuffer. */ - private var colorAttachment: Int = -1 + private var colorAttachmentView: GpuTextureView? = null /** * The shader used to apply the opacity mask. * * It binds two texture inputs: - * - `opacityMask` bound to texture unit 0. - * - `colorAttachment` bound to texture unit 1. + * - `opacityMask` sampled from the mask framebuffer. + * - `colorAttachment` sampled from the color framebuffer. * - * The actual discard logic is implemented in the `opacity_mask.fsh` shader. + * The actual discard logic is implemented in the `opacity_mask.fsh` shader. No uniform + * block is declared by this shader. */ private val opacityMaskShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/opacity_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("colorAttachment") { pointer -> - glActiveTexture(GL_TEXTURE1) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 1) - }, - UniformProvider("opacityMask") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, opacityMaskColorAttachment) - glUniform1i(pointer, 0) - } + "post/opacity_mask.fsh", + textures = arrayOf( + TextureProvider("colorAttachment") { colorAttachmentView }, + TextureProvider("opacityMask") { opacityMaskColorAttachmentView } ) ) /** * Renders the opacity-masked result using the provided framebuffers. * - * This method sets up the shader with appropriate texture bindings from the given framebuffers, - * enables the shader, performs a full-screen blit, and then disables the shader. + * This method binds the color attachments from the given framebuffers to the shader's + * texture inputs and draws the masked result into [target]. * * @param opacityMaskFramebuffer The framebuffer containing the opacity mask texture. * @param colorFramebuffer The framebuffer containing the color texture to be masked. + * @param target The render target to draw the masked result into. Defaults to + * [PostProcessRenderer.currentFramebuffer] since the old GL-era `render()` drew into + * whichever FBO happened to be bound, and there were no external callers to pin down a + * more specific default (verified via grep across common/src/main/kotlin). */ - fun render(opacityMaskFramebuffer: Framebuffer, colorFramebuffer: Framebuffer) { - opacityMaskColorAttachment = opacityMaskFramebuffer.colorAttachment - colorAttachment = colorFramebuffer.colorAttachment - opacityMaskShader.enableShader() - BlitProgram.blit() - opacityMaskShader.disableShader() + fun render( + opacityMaskFramebuffer: RenderTarget, + colorFramebuffer: RenderTarget, + target: RenderTarget = PostProcessRenderer.currentFramebuffer(), + blend: BlendFunction? = null, + ) { + opacityMaskColorAttachmentView = opacityMaskFramebuffer.colorTextureView + colorAttachmentView = colorFramebuffer.colorTextureView + opacityMaskShader.drawTo(target, blend) } } /** - * Applies an opacity mask from this [Framebuffer] to the specified [colorFramebuffer], using [OpacityMaskRenderer]. + * Applies an opacity mask from [mask] to [color], using [OpacityMaskRenderer], drawing the + * masked result into [target]. * - * This infix extension function allows for expressive syntax like: - * ``` - * maskFramebuffer opacityMask colorFramebuffer - * ``` - * It renders the contents of [colorFramebuffer] with pixels masked out according to the rules defined - * in [OpacityMaskRenderer], using this framebuffer as the opacity mask source. + * Replaces the former `infix fun RenderTarget.opacityMask(colorFramebuffer: RenderTarget)`: + * an infix function cannot cleanly carry the third (explicit target) parameter the new + * drawTo-based API requires, so this was changed to a regular 3-arg function. There were no + * external callers of the old infix form (verified via grep across common/src/main/kotlin), + * so this is a clean rename rather than an in-place signature change. * - * @receiver The framebuffer providing the opacity mask (usually grayscale or alpha-based). - * @param colorFramebuffer The framebuffer whose contents are masked and rendered. + * @param mask The framebuffer providing the opacity mask (usually grayscale or alpha-based). + * @param color The framebuffer whose contents are masked and rendered. + * @param target The render target to draw the masked result into. Defaults to + * [PostProcessRenderer.currentFramebuffer]. * * @see OpacityMaskRenderer */ -infix fun Framebuffer.opacityMask(colorFramebuffer: Framebuffer) { - OpacityMaskRenderer.render(this, colorFramebuffer) -} \ No newline at end of file +fun applyOpacityMask( + mask: RenderTarget, + color: RenderTarget, + target: RenderTarget = PostProcessRenderer.currentFramebuffer(), +) { + OpacityMaskRenderer.render(mask, color, target) +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt index 407cae2f..8a9bc2d8 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/RadialBlurRenderer.kt @@ -5,10 +5,10 @@ package heckerpowered.matrix.client.render.shader +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import org.lwjgl.opengl.GL46.* /** * A singleton object responsible for applying a radial blur post-processing effect. @@ -17,17 +17,17 @@ import org.lwjgl.opengl.GL46.* * radial pattern centered on the screen. * * ## Usage: - * - Before calling `radialBlurShader.blit()`, set `colorAttachment`, `strength`, and `samples` as needed. + * - Before calling `radialBlurShader.drawTo(target)`, set `colorAttachmentView`, `strength`, and `samples` as needed. * * ## Shader Inputs: * - `framebuffer`: The input color texture to be blurred. * - `strength`: Controls the intensity of the radial blur effect. * - `samples`: Determines how many samples are taken along the blur path. */ -object RadialBlurRenderer : PostProcessEffect { +object RadialBlurRenderer { - /** The OpenGL texture ID of the framebuffer's color attachment to be blurred. */ - override var colorAttachment = 0 + /** The color attachment to be blurred. */ + var colorAttachmentView: GpuTextureView? = null /** Controls how strong the radial blur effect appears. */ var strength = 1.0F @@ -38,28 +38,28 @@ object RadialBlurRenderer : PostProcessEffect { /** * The shader responsible for executing the radial blur effect. * - * Uses a vertex shader (`sobel.vert`) and a fragment shader (`radial_blur.fsh`) to perform - * the blur in a post-processing step. + * Uses the standard fullscreen-triangle vertex stage and the `radial_blur.fsh` fragment + * shader to perform the blur in a post-processing step. This is a separate [BlitProgram] + * instance from the one `ScreenEffectRenderer` uses for the same shader path. */ val radialBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/radial_blur.fsh", GL_FRAGMENT_SHADER), + "post/blur/radial_blur.fsh", uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, colorAttachment) - glUniform1i(pointer, 0) - }, - UniformProvider("strength") { pointer -> - glUniform1f(pointer, strength) - }, - UniformProvider("samples") { pointer -> - glUniform1i(pointer, samples) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0 = vec4(strength, samples, 0, 0) + putVec4(strength, samples.toFloat(), 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("framebuffer") { colorAttachmentView } ) ) - override fun blit() { - radialBlurShader.blit() - } -} \ No newline at end of file + // TODO(26.2): `PostProcessEffect.blit()` (old enable-shader-then-blit-later pattern) had + // no external callers (verified via grep across common/src/main/kotlin), so it was dropped + // along with the `PostProcessEffect` interface implementation. Callers now draw explicitly + // via `RadialBlurRenderer.radialBlurShader.drawTo(target)`. +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt index f1879799..928fa0dd 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/StandardBloomRenderer.kt @@ -5,48 +5,24 @@ package heckerpowered.matrix.client.render.shader -import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.render.dump -import heckerpowered.matrix.client.render.recommendMipLevel -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* - +import com.mojang.blaze3d.pipeline.RenderTarget + +// 26.2: this renderer was already dead code before the port (every step below was commented out +// except raw GL mip-generation calls with no GpuDevice equivalent - manual glTexStorage2D / +// glFramebufferTexture2D mip binding has no 1:1 wrapper API surface; mip management now belongs to +// MipmapsFramebuffer). No callers exist anywhere in common/ (verified). Left as an inert stub rather +// than deleted, to preserve the public shape for whatever this was meant to become. +// TODO(26.2): reimplement on top of MipmapsFramebuffer if this renderer is revived. object StandardBloomRenderer { - private var brightnessPass: Int = -1 - private val framebuffer: Framebuffer by lazy { - val framebuffer = PostProcessRenderer.createManagedFramebuffer() - // (framebuffer as FramebufferExtension).useMipmaps = true - // glBindTexture(GL_TEXTURE_2D, framebuffer.colorAttachment) - // glGenerateMipmap(GL_TEXTURE_2D) - framebuffer + private val framebuffer: RenderTarget by lazy { + PostProcessRenderer.createManagedFramebuffer() } - fun render(brightnessPass: Framebuffer) { - // this.brightnessPass = brightnessPass.fbo - // val colorAttachment = this.brightnessPass -// - // glBindTexture(GL_TEXTURE_2D, colorAttachment) - // glGenerateMipmap(GL_TEXTURE_2D) -// - // val boundFramebuffer = glGetInteger(GL_FRAMEBUFFER_BINDING) - // val boundColorAttachment = glGetFramebufferParameteri(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0) -// - // glBindTexture(GL_TEXTURE_2D, boundColorAttachment) - - // Render to mipmaps - framebuffer.beginWrite(true) - glBindTexture(GL_TEXTURE_2D, framebuffer.colorAttachment) - glTexStorage2D(GL_TEXTURE_2D, framebuffer.recommendMipLevel(), GL_RGBA8, framebuffer.textureWidth, framebuffer.textureHeight) - - glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, framebuffer.colorAttachment, 1 - ) - - brightnessPass.draw(brightnessPass.textureWidth, brightnessPass.textureHeight) - framebuffer.dump(1, false) - - minecraft.framebuffer.beginWrite(false) + fun render(brightnessPass: RenderTarget) { + // TODO(26.2): mip-chain generation/binding previously done via raw GL calls + // (glTexStorage2D/glFramebufferTexture2D/glGenerateMipmap) has no wrapper-API + // equivalent here; this call is currently a no-op pending a MipmapsFramebuffer-based + // reimplementation. } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt index 4396d1e5..d2f1b28e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/TentShader.kt @@ -5,43 +5,38 @@ package heckerpowered.matrix.client.render.shader -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import org.lwjgl.opengl.GL11.glBindTexture -import org.lwjgl.opengl.GL13.glActiveTexture -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object TentShader { - var framebufferObject: Int = -1 + /** + * The color attachment to sample from. Kept as `framebufferObject` for source + * compatibility with existing call sites (e.g. BloomEffect.kt), retyped from the + * old GL texture id (`Int`) to a [GpuTextureView]. + */ + var framebufferObject: GpuTextureView? = null var levelOfDetail = .0F val tentBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), + "post/blur/tent.fsh", uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("lod") { pointer -> - GL46.glUniform1f(pointer, levelOfDetail) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = lod + putVec4(levelOfDetail, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("framebuffer") { framebufferObject } ) ) - fun enable(framebufferObject: Int, levelOfDetail: Float) { - this.framebufferObject = framebufferObject - this.levelOfDetail = levelOfDetail - tentBlurShader.enableShader() - } - - fun disable() { - tentBlurShader.disableShader() - } -} \ No newline at end of file + // TODO(26.2): enable(framebufferObject, levelOfDetail)/disable() removed — the old + // enable-shader-then-blit-later pattern has no equivalent under the wrapper API. + // Callers must now set `framebufferObject`/`levelOfDetail` directly and then call + // `tentBlurShader.drawTo(target)` themselves. +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt index 75bd6827..9e711cad 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VelocityMapRenderer.kt @@ -5,41 +5,39 @@ package heckerpowered.matrix.client.render.shader -import com.mojang.blaze3d.systems.RenderSystem +import heckerpowered.matrix.client.projectionMatrix import heckerpowered.matrix.client.render.PostProcessRenderer -import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader -import heckerpowered.matrix.client.shader.UniformProvider -import heckerpowered.matrix.core.times +import heckerpowered.matrix.client.viewMatrix import org.joml.Matrix4f -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object VelocityMapRenderer { private var previousModelViewProjectionMatrix = Matrix4f() private var currentModelViewProjectionMatrix = Matrix4f() - private val matrixBuffer = FloatArray(16) - val velocityMap = PostProcessRenderer.createManagedFramebuffer() - val velocityMapShader by lazy { - BlitProgram( - ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("previousModelViewProjectionMatrix") { pointer -> - previousModelViewProjectionMatrix.get(matrixBuffer) - GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) - }, - UniformProvider("currentModelViewProjectionMatrix") { pointer -> - currentModelViewProjectionMatrix.get(matrixBuffer) - GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) - } - ) - ) - } + // TODO(26.2): velocity_map.vsh is a real per-vertex shader (motion vectors from mesh + // geometry), incompatible with BlitProgram's fixed fullscreen-screenquad vertex stage. + // This effect has no port path under the current wrapper API without a custom + // RenderPipeline built outside BlitProgram. Feature disabled pending a dedicated + // velocity-buffer pipeline. + // + // val velocityMapShader by lazy { + // BlitProgram( + // ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.vsh", GL_VERTEX_SHADER), + // ResourceShader("/assets/matrix/shaders/post/velocity_map/velocity_map.fsh", GL_FRAGMENT_SHADER), + // uniforms = arrayOf( + // UniformProvider("previousModelViewProjectionMatrix") { pointer -> + // previousModelViewProjectionMatrix.get(matrixBuffer) + // GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) + // }, + // UniformProvider("currentModelViewProjectionMatrix") { pointer -> + // currentModelViewProjectionMatrix.get(matrixBuffer) + // GL46.glUniformMatrix4fv(pointer, false, matrixBuffer) + // } + // ) + // ) + // } init { // PostProcessCallback.event.register(::onPostProcess) @@ -48,10 +46,11 @@ object VelocityMapRenderer { private fun onPostProcess() { previousModelViewProjectionMatrix = currentModelViewProjectionMatrix - val modelViewMatrix = RenderSystem.getModelViewMatrix() - val projectionMatrix = RenderSystem.getProjectionMatrix() - - // MVP = P * M * V - currentModelViewProjectionMatrix = projectionMatrix * modelViewMatrix + // MVP = P * V; RenderSystem.getModelViewMatrix()/getProjectionMatrix() no longer exist + // on the 26.2 wrapper RenderSystem. Matches other converted call sites (e.g. + // UniformProvider.kt's putViewProjectionMatrix), which source the current frame's + // matrices from the top-level projectionMatrix/viewMatrix accessors + // (backed by MatrixRenderSystem, populated once per frame via setupMatrix). + currentModelViewProjectionMatrix = Matrix4f(projectionMatrix).mul(viewMatrix) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VolumeDistortion.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VolumeDistortion.kt index 4baebe25..d235fef3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VolumeDistortion.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VolumeDistortion.kt @@ -5,17 +5,17 @@ package heckerpowered.matrix.client.render.shader -import heckerpowered.matrix.client.shader.* +import com.mojang.blaze3d.textures.GpuTextureView +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.TextureProvider +import heckerpowered.matrix.client.shader.UniformProvider +import heckerpowered.matrix.client.shader.putInverseProjectionMatrix +import heckerpowered.matrix.client.shader.putInverseViewMatrix import org.joml.Vector3f -import org.lwjgl.opengl.GL11.GL_TEXTURE_2D -import org.lwjgl.opengl.GL11.glBindTexture -import org.lwjgl.opengl.GL13.GL_TEXTURE0 -import org.lwjgl.opengl.GL13.glActiveTexture -import org.lwjgl.opengl.GL20.* object VolumeDistortion { - var sceneColorTexture: Int = 0 - var depthAttachment: Int = 0 + var sceneColorTexture: GpuTextureView? = null + var depthAttachment: GpuTextureView? = null var volumePosition: Vector3f = Vector3f() var volumeRadius: Float = 0F @@ -24,35 +24,22 @@ object VolumeDistortion { var emissiveStrength: Float = 4.0F val Shader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/volume_distortion.frag", GL_FRAGMENT_SHADER), + "post/volume_distortion.fsh", uniforms = arrayOf( - UniformProvider("sceneColorTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, sceneColorTexture) - glUniform1i(pointer, 0) - }, - UniformProvider("depthAttachment") { pointer -> - glActiveTexture(GL_TEXTURE1) - glBindTexture(GL_TEXTURE_2D, depthAttachment) - glUniform1i(pointer, 1) - }, - // projectionMatrixProvider, - // viewProjectionMatrixProvider, - inverseViewMatrixProvider, - inverseProjectionMatrixProvider, - UniformProvider("volumePosition") { pointer -> - glUniform3f(pointer, volumePosition.x, volumePosition.y, volumePosition.z) - }, - UniformProvider("volumeRadius") { pointer -> - glUniform1f(pointer, volumeRadius) - }, - UniformProvider("grayscaleIntensity") { pointer -> - glUniform1f(pointer, grayscaleIntensity) - }, - UniformProvider("emissiveStrength") { pointer -> - glUniform1f(pointer, emissiveStrength) + UniformProvider("MatrixPostUniforms") { + // mat4 inverseViewMatrix + putInverseViewMatrix() + // mat4 inverseProjectionMatrix + putInverseProjectionMatrix() + // volumeParams0 = volumePosition.xyz, volumeRadius + putVec4(volumePosition.x, volumePosition.y, volumePosition.z, volumeRadius) + // volumeParams1.x = grayscaleIntensity, .y = emissiveStrength + putVec4(grayscaleIntensity, emissiveStrength, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("sceneColorTexture") { sceneColorTexture }, + TextureProvider("depthAttachment") { depthAttachment } ) ) } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VortexRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VortexRenderer.kt index a8c76cfb..a9b3a59f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VortexRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/VortexRenderer.kt @@ -5,52 +5,35 @@ package heckerpowered.matrix.client.render.shader -import heckerpowered.matrix.client.shader.* -import org.lwjgl.opengl.GL46.* +import heckerpowered.matrix.client.shader.BlitProgram +import heckerpowered.matrix.client.shader.DissolveShader +import heckerpowered.matrix.client.shader.TextureProvider +import heckerpowered.matrix.client.shader.UniformProvider object VortexRenderer { - val vortexShader = Program( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/vortex/vortex.fsh", GL_FRAGMENT_SHADER), + val vortexShader = BlitProgram( + "post/vortex/vortex.fsh", uniforms = arrayOf( - UniformProvider("noiseTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - glUniform1i(pointer, 0) - }, - UniformProvider("time") { pointer -> - glUniform1f(pointer, (System.currentTimeMillis().toDouble() / 1000.0 % 1000.0).toFloat()) - }, - UniformProvider("innerRadius") { pointer -> - glUniform1f(pointer, 0.4F) - }, - UniformProvider("outerRadius") { pointer -> - glUniform1f(pointer, 0.5F) + UniformProvider("MatrixPostUniforms") { + // vortexParams: x = time, y = innerRadius, z = outerRadius, w unused + putVec4((System.currentTimeMillis().toDouble() / 1000.0 % 1000.0).toFloat(), 0.4F, 0.5F, 0F) } + ), + textures = arrayOf( + TextureProvider("noiseTexture") { DissolveShader.perlinNoiseTextureView } ) ) val inverseVortexShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/vortex/inverse_vortex.fsh", GL_FRAGMENT_SHADER), + "post/vortex/inverse_vortex.fsh", uniforms = arrayOf( - UniformProvider("noiseTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, DissolveShader.perlinNoiseTextureId) - glUniform1i(pointer, 0) - }, - UniformProvider("time") { pointer -> - glUniform1f(pointer, (System.currentTimeMillis().toDouble() / 1000.0 % 1000.0).toFloat()) - }, - UniformProvider("innerRadius") { pointer -> - glUniform1f(pointer, 1.0F) - }, - UniformProvider("outerRadius") { pointer -> - glUniform1f(pointer, 1.0F) - }, - UniformProvider("feather") { pointer -> - glUniform1f(pointer, 0.1F) + UniformProvider("MatrixPostUniforms") { + // vortexParams: x = time, y = innerRadius, z = outerRadius, w = feather + putVec4((System.currentTimeMillis().toDouble() / 1000.0 % 1000.0).toFloat(), 1.0F, 1.0F, 0.1F) } + ), + textures = arrayOf( + TextureProvider("noiseTexture") { DissolveShader.perlinNoiseTextureView } ) ) diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt index 48956bb4..c605451e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/hud/ProgressRingRenderer.kt @@ -8,9 +8,6 @@ package heckerpowered.matrix.client.render.shader.hud import heckerpowered.matrix.client.shader.* import org.joml.Vector2f import org.joml.Vector4f -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object ProgressRingRenderer { /** @@ -41,27 +38,24 @@ object ProgressRingRenderer { */ var color: Vector4f = Vector4f(1.0F) + /** + * The aspect ratio (width / height) of the target the ring is drawn into; the fragment + * shader uses it to keep the ring circular in the anisotropic fullscreen texcoord space. + */ + var aspectRatio: Float = 1.0F + + // 26.2: the ring was a positioned POSITION_TEXTURE quad in 1.21; it is a fullscreen pass + // now, with placement carried by the center/radius/thickness uniforms (height-normalized, + // aspect-corrected in the fragment shader). val progressRingShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/position_texture.fsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/hud/progress_ring.fsh", GL_FRAGMENT_SHADER), + "post/hud/progress_ring.fsh", uniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("progress") { pointer -> - GL46.glUniform1f(pointer, progress) - }, - UniformProvider("radius") { pointer -> - GL46.glUniform1f(pointer, radius) - }, - UniformProvider("thickness") { pointer -> - GL46.glUniform1f(pointer, thickness) - }, - UniformProvider("center") { pointer -> - GL46.glUniform2f(pointer, center.x, center.y) - }, - UniformProvider("color") { pointer -> - GL46.glUniform4f(pointer, color.x, color.y, color.z, color.w) + UniformProvider("MatrixPostUniforms") { + putVec4(progress, radius, thickness, aspectRatio) + putVec4(center.x, center.y, 0F, 0F) + putVec4(color.x, color.y, color.z, color.w) + putVec4(0F, 0F, 0F, 0F) } ) ) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt index 098a8a9e..ee5015f5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/DropShadowRenderer.kt @@ -5,20 +5,19 @@ package heckerpowered.matrix.client.render.shader.sdf -import com.mojang.blaze3d.platform.GlConst +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.gl.Framebuffer import org.joml.Vector2f import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* object DropShadowRenderer { /** * The color attachment of the signed distance field. */ - var signedDistanceField: Int = -1 + var signedDistanceField: GpuTextureView? = null var shadowOffset = Vector2f() @@ -33,31 +32,37 @@ object DropShadowRenderer { var shadowColor = Vector4f() val dropShadowShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sdf/drop_shadow.fsh", GL_FRAGMENT_SHADER), + "post/sdf/drop_shadow.fsh", uniforms = arrayOf( - UniformProvider("signedDistanceField") { pointer -> - glActiveTexture(GlConst.GL_TEXTURE0) - glBindTexture(GlConst.GL_TEXTURE_2D, signedDistanceField) - glUniform1i(pointer, 0) - }, - UniformProvider("shadowOffset") { pointer -> - glUniform2f(pointer, shadowOffset.x, shadowOffset.y) - }, - UniformProvider("shadowSize") { pointer -> - glUniform1f(pointer, shadowSize) - }, - UniformProvider("shadowColor") { pointer -> - glUniform4f(pointer, shadowColor.x, shadowColor.y, shadowColor.z, shadowColor.w) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.xy = shadowOffset, MatrixPostData0.z = shadowSize + putVec4(shadowOffset.x, shadowOffset.y, shadowSize, 0F) + // MatrixPostData1 = shadowColor + putVec4(shadowColor.x, shadowColor.y, shadowColor.z, shadowColor.w) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("signedDistanceField") { signedDistanceField } ) ) - fun render(signedDistanceField: Framebuffer) { - this.signedDistanceField = signedDistanceField.colorAttachment - dropShadowShader.enableShader() - BlitProgram.blit() - dropShadowShader.disableShader() - this.signedDistanceField = -1 + /** + * Renders the drop shadow, sampling [signedDistanceField], into [target]. + * + * 26.2: the old implementation drew via a global-state `BlitProgram.blit()` call that + * submitted into whichever FBO happened to be bound at the call site; that pattern no + * longer exists under the wrapper API, and there were no existing callers of this method + * to infer an implicit target from (grepped `DropShadowRenderer.render(` across + * common/src/main/kotlin — no hits). [target] was added as an explicit required parameter + * so callers state their destination framebuffer directly, matching how every other + * renderer in this port (e.g. [heckerpowered.matrix.client.render.PostProcessRenderer]) + * is driven via `PostProcessRenderer.renderShaderToFramebuffer(shader, target)`. + */ + fun render(signedDistanceField: RenderTarget, target: RenderTarget) { + this.signedDistanceField = signedDistanceField.colorTextureView + dropShadowShader.drawTo(target) + this.signedDistanceField = null } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt index 08d0efbb..98020c8d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/render/shader/sdf/SignedDistanceField.kt @@ -5,22 +5,19 @@ package heckerpowered.matrix.client.render.shader.sdf -import com.mojang.blaze3d.platform.GlConst +import com.mojang.blaze3d.pipeline.RenderTarget import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.render.PostProcessRenderer +import heckerpowered.matrix.client.render.textureHeight +import heckerpowered.matrix.client.render.textureWidth import heckerpowered.matrix.client.shader.BlitProgram -import heckerpowered.matrix.client.shader.ResourceShader +import heckerpowered.matrix.client.shader.TextureProvider import heckerpowered.matrix.client.shader.UniformProvider -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL11 -import org.lwjgl.opengl.GL13 -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.opengl.GL46 object SignedDistanceField { - var framebufferObject: Int = -1 - var originFramebufferObject: Int = -1 + var framebufferView: GpuTextureView? = null + var originFramebufferView: GpuTextureView? = null var stepSize: Float = 1.0F init { @@ -28,46 +25,33 @@ object SignedDistanceField { } val seedGenShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sdf/seed_gen.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - } + "post/sdf/seed_gen.fsh", + textures = arrayOf( + TextureProvider("framebuffer") { framebufferView } ) ) val jumpFloodingShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sdf/jump_flooding.fsh", GL_FRAGMENT_SHADER), + "post/sdf/jump_flooding.fsh", uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("stepSize") { pointer -> - GL46.glUniform1f(pointer, stepSize) + UniformProvider("MatrixPostUniforms") { + // MatrixPostData0.x = stepSize + putVec4(stepSize, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) } + ), + textures = arrayOf( + TextureProvider("framebuffer") { framebufferView } ) ) val sdfEvalShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/sdf/sdf_eval.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - UniformProvider("framebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE0) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, framebufferObject) - RenderSystem.glUniform1i(pointer, 0) - }, - UniformProvider("originFramebuffer") { pointer -> - GL13.glActiveTexture(GlConst.GL_TEXTURE1) - GL11.glBindTexture(GlConst.GL_TEXTURE_2D, originFramebufferObject) - RenderSystem.glUniform1i(pointer, 1) - } + "post/sdf/sdf_eval.fsh", + textures = arrayOf( + TextureProvider("framebuffer") { framebufferView }, + TextureProvider("originFramebuffer") { originFramebufferView } ) ) @@ -85,11 +69,11 @@ object SignedDistanceField { return steps } - fun computeSignedDistanceField(source: Framebuffer, pingFramebuffer: Framebuffer, pongFramebuffer: Framebuffer): Framebuffer { - framebufferObject = source.colorAttachment - originFramebufferObject = source.colorAttachment + fun computeSignedDistanceField(source: RenderTarget, pingFramebuffer: RenderTarget, pongFramebuffer: RenderTarget): RenderTarget { + framebufferView = source.colorTextureView + originFramebufferView = source.colorTextureView PostProcessRenderer.renderShaderToFramebuffer(seedGenShader, pingFramebuffer) - this.framebufferObject = pingFramebuffer.colorAttachment + this.framebufferView = pingFramebuffer.colorTextureView val resolutionX = source.textureWidth val resolutionY = source.textureHeight @@ -102,17 +86,17 @@ object SignedDistanceField { ping = pong pong = swap - framebufferObject = pong.colorAttachment + framebufferView = pong.colorTextureView PostProcessRenderer.renderShaderToFramebuffer(jumpFloodingShader, ping) } - framebufferObject = ping.colorAttachment + framebufferView = ping.colorTextureView PostProcessRenderer.renderShaderToFramebuffer(sdfEvalShader, pong) return pong } - fun computeSignedDistanceField(source: Framebuffer): Framebuffer { + fun computeSignedDistanceField(source: RenderTarget): RenderTarget { PostProcessRenderer.resetFramebuffers() return computeSignedDistanceField(source, PostProcessRenderer.ping, PostProcessRenderer.pong) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt index 0e4f30c1..6aa60f86 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlitProgram.kt @@ -5,49 +5,222 @@ package heckerpowered.matrix.client.shader +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.buffers.GpuBufferSlice +import com.mojang.blaze3d.buffers.Std140Builder +import com.mojang.blaze3d.pipeline.BindGroupLayout +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.ColorTargetState +import com.mojang.blaze3d.pipeline.DepthStencilState +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.pipeline.RenderTarget +import com.mojang.blaze3d.platform.CompareOp +import com.mojang.blaze3d.shaders.UniformType import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.client.shader.component.ShaderComponent -import net.minecraft.client.gl.VertexBuffer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats +import com.mojang.blaze3d.textures.FilterMode +import com.mojang.blaze3d.GpuFormat +import com.mojang.blaze3d.PrimitiveTopology +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.core.resourceToString +import net.minecraft.resources.Identifier +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.OptionalDouble +/** + * A fullscreen post-process program backed by the 26.2 [RenderPipeline]/[RenderPass] wrapper API, + * working on both the Vulkan and OpenGL backends. + * + * Replaces the former GL-program based implementation: shaders are referenced by resource + * [Identifier] (loaded and cross-compiled by the vanilla shader pipeline), uniforms live in + * std140 uniform blocks written through [UniformProvider]s, and textures are bound by sampler + * name through [TextureProvider]s. Drawing submits a fullscreen triangle (gl_VertexID based, + * see core/screenquad_frag_tex_coord.vsh) into an explicit [RenderTarget]. + */ open class BlitProgram( - vararg shaders: Shader, - uniforms: Array = emptyArray(), - uniformBuffers: Array = emptyArray(), - components: Array = emptyArray(), -) : - Program(*shaders, uniforms = uniforms, uniformBuffers = uniformBuffers, components = components) { - companion object { - private var buffer = VertexBuffer(VertexBuffer.Usage.DYNAMIC) + val fragmentShader: Identifier, + val vertexShader: Identifier = SCREENQUAD_VERTEX_SHADER, + val uniforms: Array = emptyArray(), + val textures: Array = emptyArray(), + /** Enables depth writes for shaders that output gl_FragDepth (e.g. blit with depth copy). */ + val writesDepth: Boolean = false, +) { + constructor( + fragmentShaderPath: String, + uniforms: Array = emptyArray(), + textures: Array = emptyArray(), + writesDepth: Boolean = false, + ) : this(Matrix.identifier(normalizeShaderPath(fragmentShaderPath)), SCREENQUAD_VERTEX_SHADER, uniforms, textures, writesDepth) + + /** Sampler names parsed from the fragment shader source. */ + val samplerNames: List by lazy { parseSamplerNames(fragmentShader) } + + /** std140 uniform block names parsed from the fragment shader source. */ + val uniformBlockNames: List by lazy { parseUniformBlockNames(fragmentShader) } + + private val pipelines = mutableMapOf, RenderPipeline>() + private val uniformBuffers = mutableMapOf() + + fun pipeline(blend: BlendFunction? = null, format: GpuFormat = GpuFormat.RGBA8_UNORM): RenderPipeline { + return pipelines.getOrPut(blend to format) { + val builder = RenderPipeline.builder() + .withLocation( + Matrix.identifier( + "pipeline/" + fragmentShader.path.replace('/', '_') + + (blend?.let { "_blend" } ?: "") + "_" + format.name.lowercase() + ) + ) + .withVertexShader(vertexShader) + .withFragmentShader(fragmentShader) + .withPrimitiveTopology(PrimitiveTopology.TRIANGLES) + .withCull(false) + .withDepthStencilState( + if (writesDepth) java.util.Optional.of(DepthStencilState(CompareOp.ALWAYS_PASS, true)) + else java.util.Optional.empty() + ) + // 26.2 release validates the render pass attachment format against the + // pipeline's declared color target format, so declare the actual target format. + builder.withColorTargetState(ColorTargetState(java.util.Optional.ofNullable(blend), format, ColorTargetState.WRITE_ALL)) + if (samplerNames.isNotEmpty() || uniformBlockNames.isNotEmpty()) { + val layout = BindGroupLayout.builder() + for (sampler in samplerNames) { + layout.withSampler(sampler) + } + for (block in uniformBlockNames) { + layout.withUniform(block, UniformType.UNIFORM_BUFFER) + } + builder.withBindGroupLayout(layout.build()) + } + builder.build() + } + } + + /** + * Renders this program as a fullscreen pass into [target]. + * + * @param blend the blend function baked into the pipeline; `null` disables blending, + * matching the previous implementation's `blit()` (blend off) default. + */ + @JvmOverloads + fun drawTo(target: RenderTarget, blend: BlendFunction? = null) { + val device = RenderSystem.getDevice() + val encoder = device.createCommandEncoder() + + val targetFormat = target.colorTexture?.format ?: GpuFormat.RGBA8_UNORM + val pipeline = pipeline(blend, targetFormat) + // Mod pipelines are built lazily (after the resource reload that compiles the + // pipelines registered in RenderPipelines), so the device's default shader source + // cannot see them; compile explicitly against the ShaderManager-loaded sources. + // The device caches compiled pipelines, so this is a map lookup on subsequent draws + // and transparently recompiles after resource reloads clear the pipeline cache. + device.precompilePipeline(pipeline) { id, type -> + heckerpowered.matrix.client.minecraft.shaderManager.getShader(id, type) + } + + // Write uniform blocks before opening the pass: writeToBuffer must not happen inside one. + val blockSlices = mutableMapOf() + for (block in uniformBlockNames) { + val provider = uniforms.firstOrNull { it.name == block } ?: continue + val ring = uniformBuffers.getOrPut(block) { UniformRing(fragmentShader, block) } + blockSlices[block] = ring.write(provider) + } + + val colorView = target.colorTextureView ?: return + encoder.createRenderPass( + { "matrix blit ${fragmentShader.path}" }, + colorView, + java.util.Optional.empty(), + if (writesDepth && target.useDepth) target.depthTextureView else null, + OptionalDouble.empty() + ).use { pass -> + pass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(pass) + for ((block, slice) in blockSlices) { + pass.setUniform(block, slice) + } + for (texture in textures) { + val view = texture.view() ?: continue + if (texture.name !in samplerNames) { + continue + } + val sampler = RenderSystem.getSamplerCache() + .getClampToEdge(if (texture.bilinear) FilterMode.LINEAR else FilterMode.NEAREST, texture.mipmap) + pass.bindTexture(texture.name, view, sampler) + } + // draw(vertexCount, instanceCount, firstVertex, firstInstance) — the same + // fullscreen-triangle call vanilla's PostPass issues (draw(3, 1, 0, 0)); the GL + // backend maps it to glDrawArraysInstancedBaseInstance(mode, first=arg3, + // count=arg1, instances=arg2, base=arg4). The argument order matters: with the + // first two swapped this silently draws zero vertices on both backends. + pass.draw(3, 1, 0, 0) + } + } + + /** Ring of UBO slots so the same program can be drawn several times per frame. */ + private class UniformRing(location: Identifier, block: String) { + private val slotSize: Long + private val buffer: GpuBuffer + private var cursor = 0 init { - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - buffer.vertex(-1F, -1F, 0F).texture(0F, 0F) - buffer.vertex(1F, -1F, 0F).texture(1F, 0F) - buffer.vertex(1F, 1F, 0F).texture(1F, 1F) - buffer.vertex(-1F, 1F, 0F).texture(0F, 1F) - this.buffer.bind() - this.buffer.upload(buffer.end()) - VertexBuffer.unbind() - } - - fun blit() { - buffer.bind() - buffer.draw() - VertexBuffer.unbind() + // Size is bounded by the largest block the mod uses (14 vec4s + matrices); + // 512 bytes covers two mat4s plus parameters, aligned to the common 256-byte + // UBO offset alignment requirement. + slotSize = 512 + buffer = RenderSystem.getDevice().createBuffer( + { "matrix uniforms ${location.path}#$block" }, + GpuBuffer.USAGE_UNIFORM or GpuBuffer.USAGE_COPY_DST, + slotSize * SLOTS + ) + } + + fun write(provider: UniformProvider): GpuBufferSlice { + val data = ByteBuffer.allocateDirect(slotSize.toInt()).order(ByteOrder.nativeOrder()) + val builder = Std140Builder.intoBuffer(data) + provider.write(builder) + val written = builder.get() + val slice = buffer.slice(slotSize * cursor, slotSize) + cursor = (cursor + 1) % SLOTS + RenderSystem.getDevice().createCommandEncoder().writeToBuffer(slice, written) + return slice + } + + companion object { + private const val SLOTS = 16 } } - fun blit() { - RenderSystem.disableBlend() - enableShader() - buffer.bind() - buffer.draw() - VertexBuffer.unbind() - disableShader() - RenderSystem.enableBlend() + companion object { + val SCREENQUAD_VERTEX_SHADER: Identifier = Matrix.identifier("core/screenquad_frag_tex_coord") + + private val SAMPLER_REGEX = Regex("""uniform\s+sampler\w+\s+([A-Za-z_][A-Za-z0-9_]*)""") + private val UNIFORM_BLOCK_REGEX = Regex("""layout\s*\(\s*std140\s*\)\s*uniform\s+([A-Za-z_][A-Za-z0-9_]*)""") + + fun normalizeShaderPath(path: String): String { + return path + .removePrefix("/") + .removePrefix("assets/matrix/shaders/") + .removeSuffix(".fsh") + .removeSuffix(".frag") + .removeSuffix(".vsh") + .removeSuffix(".vert") + } + + private fun shaderSource(identifier: Identifier): String? { + val base = "/assets/${identifier.namespace}/shaders/${identifier.path}" + return runCatching { resourceToString("$base.fsh") } + .recoverCatching { resourceToString("$base.frag") } + .getOrNull() + } + + fun parseSamplerNames(identifier: Identifier): List { + val source = shaderSource(identifier) ?: return emptyList() + return SAMPLER_REGEX.findAll(source).map { it.groupValues[1] }.distinct().toList() + } + + fun parseUniformBlockNames(identifier: Identifier): List { + val source = shaderSource(identifier) ?: return emptyList() + return UNIFORM_BLOCK_REGEX.findAll(source).map { it.groupValues[1] }.distinct().toList() + } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt index 6a368a30..e7b51b3f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/BlurRenderer.kt @@ -5,56 +5,25 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.platform.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.pipeline.RenderTarget import heckerpowered.matrix.client.MatrixHud import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.render.linearCopyTo +import heckerpowered.matrix.client.render.mainRenderTarget import heckerpowered.matrix.client.render.nearestCopyTo import heckerpowered.matrix.client.render.post.ScaleSampling import heckerpowered.matrix.client.render.shader.GaussianBlurRenderer -import heckerpowered.matrix.client.render.state.FramebufferState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.ViewportState -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gl.Framebuffer -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.client.texture.NativeImage import org.joml.Vector2f -import org.lwjgl.opengl.GL46.* -import java.io.File - object BlurRenderer { - var initialFramebuffer = minecraft.framebuffer - var currentFramebuffer = minecraft.framebuffer + var initialFramebuffer: RenderTarget = minecraft.mainRenderTarget + var currentFramebuffer: RenderTarget = minecraft.mainRenderTarget var radius = 5.0F var kawaseOffset = 1.0F var useDownscaling: Boolean = true - private val imageProvider = UniformProvider("image") { pointer -> - GlStateManager._activeTexture(GL_TEXTURE0) - GlStateManager._bindTexture(currentFramebuffer.colorAttachment) - glUniform1i(pointer, 0) - } - - private val radiusProvider = UniformProvider("radius") { pointer -> - glUniform1f(pointer, radius * MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat()) - } - - private val kawaseOffsetProvider = UniformProvider("offset") { pointer -> - kawaseOffset += 3F - val progress = MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat() - glUniform2f(pointer, progress * kawaseOffset, progress * kawaseOffset) - } - private val halfResolutionBlurFramebuffer by lazy { ScaleSampling.createManagedScalingFramebuffer(0.5) } @@ -63,178 +32,130 @@ object BlurRenderer { PostProcessRenderer.createManagedFramebuffer() } + // 26.2: gaussian_blur_horizontal.fsh / gaussian_blur_vertical.fsh declare + // layout(std140) uniform MatrixPostUniforms { vec4 blurParams0; }; #define radius blurParams0.x + // weight[5] stayed a GLSL-side `const float[]` since it was never varied from Kotlin. val horizontalBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/gaussian_blur_horizontal.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, radiusProvider) + "gaussian_blur_horizontal.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + putVec4(radius * MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat(), 0F, 0F, 0F) + } + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) val verticalBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/gaussian_blur_vertical.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, radiusProvider) + "gaussian_blur_vertical.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + putVec4(radius * MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat(), 0F, 0F, 0F) + } + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) + // 26.2: post/blur/kawase_blur.fsh declares MatrixPostData0..3; #define offset MatrixPostData0.xy val kawaseBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/kawase_blur.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider, kawaseOffsetProvider) + "post/blur/kawase_blur.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + kawaseOffset += 3F + val progress = MatrixHud.magicShownOpacityAnimation.animatedValue.toFloat() + putVec4(progress * kawaseOffset, progress * kawaseOffset, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + } + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) + // 26.2: post/blur/tent.fsh declares MatrixPostData0..3; #define lod MatrixPostData0.x val tentBlurShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/blur/tent.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(PostProcessRenderer.framebufferProvider) + "post/blur/tent.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + } + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) + // 26.2: post/color/colorful.fsh declares MatrixPostData0..3; + // #define brightness .x / saturation .y / contrast .z (all on MatrixPostData0) private val colorfulShader = BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/color/colorful.fsh", GL_FRAGMENT_SHADER), + "post/color/colorful.fsh", uniforms = arrayOf( - PostProcessRenderer.framebufferProvider, - UniformProvider("brightness") { pointer -> - glUniform1f(pointer, 1.1F) - }, - UniformProvider("saturation") { pointer -> - glUniform1f(pointer, 2.0F) - }, - UniformProvider("contrast") { pointer -> - glUniform1f(pointer, 1.0F) - }) + UniformProvider("MatrixPostUniforms") { + putVec4(1.1F, 2.0F, 1.0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + putVec4(0F, 0F, 0F, 0F) + } + ), + textures = arrayOf(PostProcessRenderer.framebufferProvider) ) - val blurTextureRenderProgram = Program( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/blur_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf(UniformProvider("image") { pointer -> - GlStateManager._activeTexture(GL_TEXTURE0) - GlStateManager._bindTexture(blurFramebuffer.colorAttachment) - glUniform1i(pointer, 0) - }) + // 26.2: post/blur/blur_mask.fsh has no value uniforms (sampler2D framebuffer only); the old + // `blurFramebuffer.colorAttachment` binding is now this shader's `framebuffer` TextureProvider. + val blurTextureRenderProgram = BlitProgram( + "post/blur/blur_mask.fsh", + textures = arrayOf(TextureProvider("framebuffer") { blurFramebuffer.colorTextureView }) ) - fun dumpFrameBuffer(framebuffer: Framebuffer) { - val framebufferWidth = framebuffer.textureWidth - val framebufferHeight = framebuffer.textureHeight + fun renderQuad(target: RenderTarget) { + blurTextureRenderProgram.drawTo(target) + } - NativeImage(framebufferWidth, framebufferHeight, false).use { nativeImage -> - RenderSystem.bindTexture(framebuffer.colorAttachment) - nativeImage.loadFromTextureImage(0, false) - nativeImage.mirrorVertically() + fun renderGaussianBlurFullResolution(source: RenderTarget = PostProcessRenderer.sourceFramebuffer) { + PostProcessRenderer.clear(blurFramebuffer) - val file = File("screenshots") - file.mkdir() + GaussianBlurRenderer.direction = Vector2f(1F, 0F) + GaussianBlurRenderer.colorAttachment = source.colorTextureView + GaussianBlurRenderer.gaussianBlurShader.drawTo(GaussianBlurRenderer.fullPing) - val filename = "framebuffer_dump_${framebuffer.hashCode()}.png" - nativeImage.writeTo(File(file, filename)) - } - } + GaussianBlurRenderer.direction = Vector2f(0F, 1F) + GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.fullPing.colorTextureView + GaussianBlurRenderer.gaussianBlurShader.drawTo(GaussianBlurRenderer.fullPong) - fun renderQuad() { - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - buffer.vertex(-1F, -1F, 0F).texture(0F, 0F) - buffer.vertex(1F, -1F, 0F).texture(1F, 0F) - buffer.vertex(1F, 1F, 0F).texture(1F, 1F) - buffer.vertex(-1F, 1F, 0F).texture(0F, 1F) - BufferRenderer.draw(buffer.end()) + GaussianBlurRenderer.fullPong nearestCopyTo blurFramebuffer } - fun renderGaussianBlurFullResolution(source: Framebuffer = PostProcessRenderer.sourceFramebuffer) { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), BlendState(false)) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + fun renderGaussianBlur(source: RenderTarget = PostProcessRenderer.sourceFramebuffer, target: RenderTarget = blurFramebuffer) { + source linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) + ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) + val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - GaussianBlurRenderer.fullPing.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(1F, 0F) - GaussianBlurRenderer.colorAttachment = source.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() + GaussianBlurRenderer.direction = Vector2f(1F, 0F) + GaussianBlurRenderer.colorAttachment = downscalingFramebuffer.colorTextureView + GaussianBlurRenderer.gaussianBlurShader.drawTo(GaussianBlurRenderer.ping) - GaussianBlurRenderer.fullPong.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(0F, 1F) - GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.fullPing.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() + GaussianBlurRenderer.direction = Vector2f(0F, 1F) + GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.ping.colorTextureView + GaussianBlurRenderer.gaussianBlurShader.drawTo(GaussianBlurRenderer.pong) - GaussianBlurRenderer.fullPong nearestCopyTo blurFramebuffer - } - } - - fun renderGaussianBlur(source: Framebuffer = PostProcessRenderer.sourceFramebuffer, target: Framebuffer = blurFramebuffer) { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot(), BlendState(false)) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 2).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 4).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - source linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) - ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - - // blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - GaussianBlurRenderer.ping.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(1F, 0F) - GaussianBlurRenderer.colorAttachment = downscalingFramebuffer.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.pong.beginWrite(true) - GaussianBlurRenderer.direction = Vector2f(0F, 1F) - GaussianBlurRenderer.colorAttachment = GaussianBlurRenderer.ping.colorAttachment - GaussianBlurRenderer.gaussianBlurShader.blit() - - GaussianBlurRenderer.pong linearCopyTo halfResolutionBlurFramebuffer - halfResolutionBlurFramebuffer linearCopyTo target - } + GaussianBlurRenderer.pong linearCopyTo halfResolutionBlurFramebuffer + halfResolutionBlurFramebuffer linearCopyTo target } fun renderKawaseBlur() { - StateIsolation.isolate(FramebufferState.captureSnapshot(), ViewportState.captureSnapshot()) { - glBindTexture(GlConst.GL_TEXTURE_2D, PostProcessRenderer.sourceFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + PostProcessRenderer.sourceFramebuffer linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) + ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) + val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 2).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + PostProcessRenderer.clear(blurFramebuffer) - glBindTexture(GlConst.GL_TEXTURE_2D, ScaleSampling.getDownScalingFramebuffer(1.0 / 4).colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - glBindTexture(GlConst.GL_TEXTURE_2D, blurFramebuffer.colorAttachment) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - PostProcessRenderer.sourceFramebuffer linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 2) - ScaleSampling.getDownScalingFramebuffer(1.0 / 2) linearCopyTo ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - val downscalingFramebuffer = ScaleSampling.getDownScalingFramebuffer(1.0 / 4) - - blurFramebuffer.clear(MinecraftClient.IS_SYSTEM_MAC) - - kawaseOffset = 0F - val shaders = mutableListOf() - for (i in 0..4) { - shaders.add(kawaseBlurShader) - } - PostProcessRenderer.useFramebuffer(downscalingFramebuffer) { - PostProcessRenderer.renderShadersToFramebuffer(shaders, blurFramebuffer) - } + kawaseOffset = 0F + val shaders = mutableListOf() + for (i in 0..4) { + shaders.add(kawaseBlurShader) + } + PostProcessRenderer.useFramebuffer(downscalingFramebuffer) { + PostProcessRenderer.renderShadersToFramebuffer(shaders, blurFramebuffer) } } @@ -245,7 +166,6 @@ object BlurRenderer { @JvmStatic fun onResize(width: Int, height: Int) { - blurFramebuffer.resize(width, height, MinecraftClient.IS_SYSTEM_MAC) - // GL30.glViewport(0, 0, width, height) + blurFramebuffer.resize(width, height) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt index 1c7f6ec0..72a26740 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/DissolveShader.kt @@ -5,16 +5,30 @@ package heckerpowered.matrix.client.shader +import com.mojang.blaze3d.platform.NativeImage +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.minecraft -import net.minecraft.client.texture.ResourceTexture +import net.minecraft.client.renderer.texture.DynamicTexture import org.joml.Vector4f -import org.lwjgl.opengl.GL46.* -import kotlin.time.Duration.Companion.nanoseconds -import kotlin.time.DurationUnit +/** + * Dissolve-effect state and shaders (mesh-attached "burn away" overlay used by HUD elements). + * + * 26.2 note: the previous implementation was a mesh-attached [Program] pair, bound globally via + * `enableShader()`/`disableShader()` around vanilla [net.minecraft.client.gui.Font]/ + * `BufferBuilder` draw calls -- there is no wrapper-API equivalent to "bind this program + * globally, then let unrelated immediate-mode code draw against it": render passes are + * self-contained and target an explicit [com.mojang.blaze3d.pipeline.RenderTarget]. Porting the + * HUD-mesh draw path itself is out of scope here (owned by whoever converts MatrixHud.kt/ + * ManaBar.kt); this class now only owns the state (uniform values) and the equivalent + * full-screen [BlitProgram] built from the std140-converted `post/dissolve/dissolve.fsh`, which + * callers rendering into an explicit target can use directly. [enableShader]/[disableShader] + * are kept as deprecated no-ops purely so existing call sites keep compiling until they're + * rewritten against [plainDissolveProgram]. + */ class DissolveShader : AutoCloseable { - val noiseTexture by lazy { perlinNoiseTextureId } + val noiseTexture: GpuTextureView? get() = perlinNoiseTextureView var dissolveFactor: Float = 1.0f var resolutionX: Float = 1.0F @@ -22,70 +36,61 @@ class DissolveShader : AutoCloseable { var emissiveStrength: Float = 15.0F var emissiveColor: Vector4f = Vector4f(0.1F, 0.5F, 1.0F, 1.0F) - private val dissolveProgramUniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("noiseTexture") { pointer -> - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, noiseTexture) - glUniform1i(pointer, 0) - }, - UniformProvider("dissolveFactor") { pointer -> - glUniform1f(pointer, dissolveFactor) - }, - UniformProvider("resolution") { pointer -> - glUniform2f(pointer, resolutionX, resolutionY) - }, - UniformProvider("time") { pointer -> - glUniform1f(pointer, System.nanoTime().nanoseconds.toDouble(DurationUnit.SECONDS).toFloat() % 10) - }, - UniformProvider("emissiveStrength") { pointer -> - glUniform1f(pointer, emissiveStrength) - }, - UniformProvider("emissiveColor") { pointer -> - glUniform4f(pointer, emissiveColor.x, emissiveColor.y, emissiveColor.z, emissiveColor.w) - }) - - private val program by lazy { - Program( - ResourceShader("/assets/matrix/shaders/position_texture_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/noise_mask.fsh", GL_FRAGMENT_SHADER), - uniforms = dissolveProgramUniforms - ) - } - + // 26.2: post/dissolve/dissolve.fsh declares + // layout(std140) uniform MatrixPostUniforms { vec4 dissolveParams0; vec4 dissolveParams1; vec4 dissolveEmissiveColor; }; + // #define dissolveFactor dissolveParams0.x / emissiveRange .y / emissiveStrength .z / pixelStrength .w + // #define detialStrength dissolveParams1.x / time .y / resolution .zw + // emissiveRange/pixelStrength/detialStrength were never wired to instance state under the old + // pre-std140 pipeline either (GLSL defaults applied: emissiveRange=0.05, pixelStrength=16.0, + // detialStrength=1.0). See MatrixPostUniforms.kt@f25647a "post/dissolve/dissolve" for the + // reference slot layout used here. val plainDissolveProgram by lazy { - Program( - ResourceShader("/assets/matrix/shaders/position_texture_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/post/dissolve/dissolve.fsh", GL_FRAGMENT_SHADER), - uniforms = dissolveProgramUniforms + BlitProgram( + "post/dissolve/dissolve.fsh", + uniforms = arrayOf( + UniformProvider("MatrixPostUniforms") { + putVec4(dissolveFactor, 0.05F, emissiveStrength, 16.0F) + putVec4(1.0F, shaderTimeSeconds(), resolutionX, resolutionY) + putVec4(emissiveColor) + } + ), + textures = arrayOf( + TextureProvider("noiseTexture") { noiseTexture } + ) ) } companion object { - private val perlinNoiseTexture = ResourceTexture(Matrix.identifier("textures/noise/perlin_noise.png")) - val perlinNoiseTextureId by lazy { loadPerlinNoiseTexture() } + private var perlinNoiseTexture: DynamicTexture? = null - private fun loadPerlinNoiseTexture(): Int { - perlinNoiseTexture.load(minecraft.resourceManager) + /** Registered under `matrix:textures/noise/perlin_noise.png`; loaded lazily on first use. */ + val perlinNoiseTextureView: GpuTextureView? by lazy { loadPerlinNoiseTexture() } - glBindTexture(GL_TEXTURE_2D, perlinNoiseTexture.glId) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT) + private fun loadPerlinNoiseTexture(): GpuTextureView? { + val identifier = Matrix.identifier("textures/noise/perlin_noise.png") + val image = minecraft.resourceManager.open(identifier).use { stream -> NativeImage.read(stream) } + val texture = DynamicTexture({ "matrix perlin noise" }, image) + texture.upload() + minecraft.textureManager.register(identifier, texture) + perlinNoiseTexture = texture - return perlinNoiseTexture.glId + // TODO(26.2): the old texture set GL_TEXTURE_WRAP_S/T = GL_MIRRORED_REPEAT. The + // wrapper API's SamplerCache only offers AddressMode.REPEAT / CLAMP_TO_EDGE (no + // mirrored-repeat mode exists), and BlitProgram's TextureProvider binding path + // always samples via getClampToEdge(...) regardless -- there is currently no way to + // reproduce the mirrored-repeat tiling behavior through the core wrapper API. + return texture.textureView } } + @Deprecated("Mesh-attached global shader binding has no 26.2 equivalent; use plainDissolveProgram.drawTo(target) instead") fun enableShader() { - program.enableShader() } + @Deprecated("Mesh-attached global shader binding has no 26.2 equivalent; use plainDissolveProgram.drawTo(target) instead") fun disableShader() { - program.disableShader() } override fun close() { - program.close() } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt index af341fcd..9839959a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/PositionColorProgram.kt @@ -5,37 +5,23 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.render.Color -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER -import org.lwjgl.system.MemoryUtil -object PositionColorProgram : Program( - ResourceShader("/assets/matrix/shaders/position_color.vsh", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/position_color.fsh", GL_FRAGMENT_SHADER), - uniforms = arrayOf( - modelViewMatrixProvider, - projectionMatrixProvider, - UniformProvider("colorModulator") { pointer -> - RenderSystem.glUniform3(pointer, PositionColorProgram.colorBuffer) - } - ) -) { - private val colorBuffer = MemoryUtil.memAllocFloat(4) +/** + * Vertex-color modulation shader (`position_color.vsh`/`.fsh`): multiplies each vertex's own + * color attribute by [color] uniformly. + * + * 26.2 note: this was a mesh-attached [Program], bound globally via `enableShader()` around + * vanilla `BufferBuilder` draw calls with `Position`/`Color` vertex attributes -- there is no + * wrapper-API equivalent for "bind this program globally, then let unrelated immediate-mode + * code draw against it" (render passes are self-contained and target an explicit + * [com.mojang.blaze3d.pipeline.RenderTarget] with a [com.mojang.blaze3d.pipeline.RenderPipeline] + * bound per draw call, not a globally bound program). `position_color.vsh`/`.fsh` also have no + * std140-converted `post/` sibling (unlike the dissolve shaders) since they were never a + * fullscreen pass to begin with. No caller currently references this object in the tree. + * [color] is kept as plain state for whoever ports the mesh-draw call site onto a + * [com.mojang.blaze3d.pipeline.RenderPipeline]. + */ +object PositionColorProgram { var color = Color(1, 1, 1, 1) - set(value) { - field = value - uploadBuffer() - } - - private fun uploadBuffer() { - val color = color - val colorBuffer = colorBuffer - colorBuffer.clear() - colorBuffer.put(color.red / 255F) - colorBuffer.put(color.green / 255F) - colorBuffer.put(color.blue / 255F) - colorBuffer.put(color.alpha / 255F) - } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt index fb95d03e..f8dbf726 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/TexturePixelDissolveProgram.kt @@ -5,45 +5,54 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.platform.GlConst -import heckerpowered.matrix.Matrix -import heckerpowered.matrix.client.minecraft -import net.minecraft.client.texture.ResourceTexture -import org.lwjgl.opengl.GL20 -import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER -import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER +import com.mojang.blaze3d.textures.GpuTextureView + +// 26.2: post/dissolve/texture_pixel_dissolve.fsh declares +// layout(std140) uniform MatrixPostUniforms { vec4 dissolveParams0; vec4 dissolveEmissiveColor; }; +// #define dissolveFactor dissolveParams0.x / emissiveRange .y / pixelStrength .z / detialStrength .w +// The old code never actually supplied emissiveRange/pixelStrength/detialStrength/emissiveColor as +// uniforms (GLSL defaults applied under the pre-std140 pipeline: emissiveRange=0.05, pixelStrength=100.0, +// detialStrength=1.0, emissiveColor=vec4(0,0.5,1.0,1.0)), so this port keeps those exact values. +// See MatrixPostUniforms.kt@f25647a "post/dissolve/texture_pixel_dissolve" for the reference slot layout. +// +// The mutable state lives in a separate holder because Kotlin forbids the super-constructor +// lambdas from capturing the object's own (not yet initialized) instance. +private object TexturePixelDissolveState { + var noiseTexture: GpuTextureView? = null + var normalTexture: GpuTextureView? = null + var dissolveFactor: Float = 1.0f +} object TexturePixelDissolveProgram : BlitProgram( - ResourceShader("/assets/matrix/shaders/sobel.vert", GL_VERTEX_SHADER), - ResourceShader("/assets/matrix/shaders/texture_pixel_dissolve.fsh", GL_FRAGMENT_SHADER), + "post/dissolve/texture_pixel_dissolve.fsh", uniforms = arrayOf( - UniformProvider("noiseTexture") { pointer -> - GL20.glActiveTexture(GlConst.GL_TEXTURE0) - GL20.glBindTexture(GL20.GL_TEXTURE_2D, TexturePixelDissolveProgram.noiseTexture) - GL20.glUniform1i(pointer, 0) - }, - UniformProvider("normalTexture") { pointer -> - GL20.glActiveTexture(GlConst.GL_TEXTURE1) - GL20.glBindTexture(GL20.GL_TEXTURE_2D, TexturePixelDissolveProgram.normalTexture) - GL20.glUniform1i(pointer, 1) - }, - UniformProvider("dissolveFactor") { pointer -> - GL20.glUniform1f(pointer, TexturePixelDissolveProgram.dissolveFactor) + UniformProvider("MatrixPostUniforms") { + putVec4(TexturePixelDissolveState.dissolveFactor, 0.05F, 100.0F, 1.0F) + putVec4(0F, 0.5F, 1.0F, 1.0F) } + ), + textures = arrayOf( + TextureProvider("noiseTexture") { + TexturePixelDissolveState.noiseTexture ?: DissolveShader.perlinNoiseTextureView + }, + TextureProvider("normalTexture") { TexturePixelDissolveState.normalTexture } ) ) { - private val perlinNoiseTexture = ResourceTexture(Matrix.identifier("textures/perlin_noise.png")) - private var perlinNoiseTextureId: Int = 0 - private fun loadPerlinNoiseTexture() { - perlinNoiseTexture.load(minecraft.resourceManager) - perlinNoiseTextureId = perlinNoiseTexture.glId - } + var noiseTexture: GpuTextureView? + get() = TexturePixelDissolveState.noiseTexture + set(value) { + TexturePixelDissolveState.noiseTexture = value + } - init { - loadPerlinNoiseTexture() - } + var normalTexture: GpuTextureView? + get() = TexturePixelDissolveState.normalTexture + set(value) { + TexturePixelDissolveState.normalTexture = value + } - var noiseTexture: Int = perlinNoiseTextureId - var normalTexture: Int = 0 - var dissolveFactor: Float = 1.0f -} \ No newline at end of file + var dissolveFactor: Float + get() = TexturePixelDissolveState.dissolveFactor + set(value) { + TexturePixelDissolveState.dissolveFactor = value + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt b/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt index 8aa8223a..bf4679b5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/shader/UniformProvider.kt @@ -5,103 +5,74 @@ package heckerpowered.matrix.client.shader -import com.mojang.blaze3d.systems.RenderSystem -import heckerpowered.matrix.Matrix +import com.mojang.blaze3d.buffers.Std140Builder +import com.mojang.blaze3d.textures.GpuTextureView import heckerpowered.matrix.client.minecraft -import heckerpowered.matrix.client.player import heckerpowered.matrix.client.projectionMatrix import heckerpowered.matrix.client.render.MatrixRenderSystem import org.joml.Matrix4f -import org.lwjgl.opengl.GL46.* -import org.lwjgl.system.MemoryUtil -import org.slf4j.MarkerFactory import kotlin.time.Duration.Companion.milliseconds import kotlin.time.DurationUnit -private val buffer = MemoryUtil.memAllocFloat(16) - -val projectionMatrixProvider = UniformProvider("projectionMatrix") { pointer -> - buffer.position(0) - RenderSystem.getProjectionMatrix().get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val modelViewMatrixProvider = UniformProvider("modelViewMatrix") { pointer -> - buffer.position(0) - RenderSystem.getModelViewMatrix().get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} - -val inverseProjectionMatrixProvider = UniformProvider("inverseProjectionMatrix") { pointer -> - buffer.position(0) - - val projectionMatrix = projectionMatrix - val invertProjectionMatrix = Matrix4f(projectionMatrix).invert() - invertProjectionMatrix.get(buffer) +/** + * Writes one std140 uniform block of a [BlitProgram]. + * + * [name] is the uniform block's name as declared in the GLSL source + * (`layout(std140) uniform { ... };`); [write] emits the block's members in + * declaration order through [Std140Builder], which handles std140 alignment. This replaces + * the former per-uniform `glUniform*` writers: on the 26.2 wrapper API (Vulkan and OpenGL + * alike) loose uniforms no longer exist, uniform data lives in buffer-backed blocks. + */ +open class UniformProvider(val name: String, val write: Std140Builder.() -> Unit) - glUniformMatrix4fv(pointer, false, buffer) +/** + * Supplies a texture for the sampler uniform called [name] in a [BlitProgram]. + * Returning `null` skips the binding for this draw. + */ +open class TextureProvider( + val name: String, + val bilinear: Boolean = false, + val mipmap: Boolean = false, + val view: () -> GpuTextureView?, +) + +/** Seconds-scale time value matching the previous `time` uniform providers. */ +fun shaderTimeSeconds(): Float { + return System.nanoTime().milliseconds.toDouble(DurationUnit.SECONDS).toFloat() } -val inverseModelViewMatrixProvider = UniformProvider("inverseModelViewMatrix") { pointer -> - buffer.position(0) - - val modelViewMatrix = RenderSystem.getModelViewMatrix() - val invertModelViewMatrix = Matrix4f(modelViewMatrix).invert() - invertModelViewMatrix.get(buffer) +/** Camera-relative matrices, kept for shaders whose blocks embed them. */ +fun Std140Builder.putProjectionMatrix(): Std140Builder = putMat4f(projectionMatrix) - glUniformMatrix4fv(pointer, false, buffer) -} +fun Std140Builder.putInverseProjectionMatrix(): Std140Builder = putMat4f(Matrix4f(projectionMatrix).invert()) -val inverseViewMatrixProvider = UniformProvider("inverseViewMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.inverseViewMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} +fun Std140Builder.putViewMatrix(): Std140Builder = putMat4f(MatrixRenderSystem.viewMatrix) -val viewMatrixProvider = UniformProvider("inverseViewMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.viewMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} +fun Std140Builder.putInverseViewMatrix(): Std140Builder = putMat4f(MatrixRenderSystem.inverseViewMatrix) -val viewProjectionMatrixProvider = UniformProvider("viewProjectionMatrix") { pointer -> - buffer.position(0) - MatrixRenderSystem.viewProjectionMatrix.get(buffer) - glUniformMatrix4fv(pointer, false, buffer) -} +fun Std140Builder.putViewProjectionMatrix(): Std140Builder = putMat4f(MatrixRenderSystem.viewProjectionMatrix) -val playerPositionProvider = UniformProvider("playerPosition") { pointer -> - val tickDelta = minecraft.renderTickCounter.getTickDelta(true) - val position = player.getLerpedPos(tickDelta) - glUniform3f(pointer, position.x.toFloat(), position.y.toFloat(), position.z.toFloat()) +/** Interpolated local player position, matching the previous `playerPosition` provider. */ +fun Std140Builder.putPlayerPosition(): Std140Builder { + val tickDelta = minecraft.deltaTracker.getGameTimeDeltaPartialTick(true) + val position = minecraft.player?.getPosition(tickDelta) + return putVec3( + position?.x?.toFloat() ?: 0F, + position?.y?.toFloat() ?: 0F, + position?.z?.toFloat() ?: 0F + ) } -val cameraPositionProvider = UniformProvider("cameraPosition") { pointer -> - val camera = minecraft.gameRenderer.camera - glUniform3f(pointer, camera.pos.x.toFloat(), camera.pos.y.toFloat(), camera.pos.z.toFloat()) +/** Camera position, matching the previous `cameraPosition` provider. */ +fun Std140Builder.putCameraPosition(): Std140Builder { + val position = minecraft.gameRenderer.mainCamera().position() + return putVec3(position.x.toFloat(), position.y.toFloat(), position.z.toFloat()) } -val resolutionProvider = UniformProvider("resolution") { pointer -> - val width = minecraft.window.framebufferWidth.toFloat() - val height = minecraft.window.framebufferHeight.toFloat() - glUniform2f(pointer, width, height) +/** Framebuffer resolution, matching the previous `resolution` provider. */ +fun Std140Builder.putResolution(): Std140Builder { + return putVec2( + minecraft.window.width.toFloat(), + minecraft.window.height.toFloat() + ) } - -val timeProvider = UniformProvider("time") { pointer -> - glUniform1f(pointer, System.nanoTime().milliseconds.toDouble(DurationUnit.SECONDS).toFloat()) -} - -open class UniformProvider(val name: String, val set: (pointer: Int) -> Unit) { - companion object { - private val MARKER = MarkerFactory.getMarker("UniformProvider") - } - - var pointer = -1 - - fun init(program: Int) { - pointer = glGetUniformLocation(program, name) - if (pointer == -1) { - Matrix.LOGGER.error(MARKER, "Cannot find uniform location, name: $name") - } - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt index 5d684c38..9382d430 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/AvailableStatusTooltip.kt @@ -15,7 +15,7 @@ import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus import heckerpowered.matrix.common.magic.core.description -import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.GuiGraphicsExtractor import java.time.Duration import kotlin.math.min @@ -39,7 +39,7 @@ object AvailableStatusTooltip { shownAnimation.currentValue = -50.0 } - fun render(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer, status: LMagicAvailableStatus) { + fun render(drawContext: GuiGraphicsExtractor, renderer: LegacyMatrixUIRenderer, status: LMagicAvailableStatus) { val minPoint = Point( renderer.scaledWindowWidth / 2 - 125.0, 30.0 + shownAnimation.animatedValue diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt index b10b4171..a4e48813 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/DamageNumberHud.kt @@ -8,21 +8,22 @@ package heckerpowered.matrix.client.ui.element import heckerpowered.foundation.ui.animation.core.AnimationScope import heckerpowered.foundation.ui.animation.tween.TweenSpec import heckerpowered.foundation.ui.color.Argb8 +import heckerpowered.matrix.Matrix import heckerpowered.matrix.client.easingFunction import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.core.worldToScreen -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.util.math.Vec3d +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.client.DeltaTracker +import net.minecraft.world.phys.Vec3 +import kotlin.math.roundToInt import kotlin.math.roundToLong import kotlin.time.Duration.Companion.milliseconds object DamageNumberHud { private val scope = AnimationScope() - private class DamageNumber(val text: String, val color: Argb8, val position: Vec3d, scope: AnimationScope, val uid: Long) { + private class DamageNumber(val text: String, val color: Argb8, val position: Vec3, scope: AnimationScope, val uid: Long) { var size by scope.doubleAnimation(20.0) var yOffset by scope.doubleAnimation(.0) var opacity by scope.doubleAnimation(.0) @@ -45,7 +46,10 @@ object DamageNumberHud { } fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) + // 26.2: HudRenderCallback was replaced by HudElementRegistry; still invoked once per rendered frame. + HudElementRegistry.addLast(Matrix.identifier("damage_numbers")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) + } } private fun formatDamage(value: Float): String { @@ -59,7 +63,7 @@ object DamageNumberHud { return truncated.toString() } - fun addDamageNumber(damage: Float, color: Argb8, position: Vec3d) { + fun addDamageNumber(damage: Float, color: Argb8, position: Vec3) { val formattedDamage = formatDamage(damage) addDamageNumber(formattedDamage, color, position) } @@ -67,7 +71,7 @@ object DamageNumberHud { private var createdThisSecond = 0 private var lastSecondMarkNanos = System.nanoTime() - fun addDamageNumber(text: String, color: Argb8, position: Vec3d) { + fun addDamageNumber(text: String, color: Argb8, position: Vec3) { createdThisSecond++ val damageNumber = DamageNumber(text, color, position, scope, ++counter) @@ -83,7 +87,7 @@ object DamageNumberHud { damageNumbers.add(damageNumber) } - private fun renderDamageNumber(damageNumber: DamageNumber, drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun renderDamageNumber(damageNumber: DamageNumber, drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { if (damageNumber.opacity <= 4.0) return if (!damageNumber.isFading && damageNumber.opacity >= 255.0) { damageNumber.isFading = true @@ -94,49 +98,46 @@ object DamageNumberHud { val base = damageNumber.position val screenPosition = worldToScreen( - Vec3d(base.x, base.y + damageNumber.yOffset, base.z) + Vec3(base.x, base.y + damageNumber.yOffset, base.z) ) ?: return val text = damageNumber.text - val textRenderer = minecraft.textRenderer + val font = minecraft.font - val width = textRenderer.getWidth(text) - val height = textRenderer.fontHeight + val width = font.width(text) + val height = font.lineHeight val centerX = screenPosition.x + width / 2 val centerY = screenPosition.y + height / 2 - val matrices = drawContext.matrices - matrices.push() - matrices.translate(centerX, centerY, 0.0) - matrices.scale( - damageNumber.size.toFloat(), + val pose = drawContext.pose() + pose.pushMatrix() + pose.translate(centerX.toFloat(), centerY.toFloat()) + pose.scale( damageNumber.size.toFloat(), - 1.0f + damageNumber.size.toFloat() ) - matrices.translate(-centerX, -centerY, 0.0) + pose.translate(-centerX.toFloat(), -centerY.toFloat()) val argb = damageNumber.color .withAlpha(damageNumber.opacity.toInt()) .packed - textRenderer.draw( + // 26.2: text()'s no-lightmap 2D path already renders on top like the old SEE_THROUGH + // layer (full-bright, no depth test) — light-value/layer params no longer exposed. + drawContext.text( + font, text, - screenPosition.x.toFloat(), - screenPosition.y.toFloat(), + screenPosition.x.roundToInt(), + screenPosition.y.roundToInt(), argb, - true, - matrices.peek().positionMatrix, - drawContext.vertexConsumers, - TextRenderer.TextLayerType.SEE_THROUGH, - 0, - 15728880 + true ) - matrices.pop() + pose.popMatrix() } - fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { + fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { for (damageNumber in damageNumbers) { renderDamageNumber(damageNumber, drawContext, tickCounter) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt index f4cd5005..121f3cd3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/MagicList.kt @@ -5,21 +5,23 @@ package heckerpowered.matrix.client.ui.element -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.MatrixHud.targetedEntity import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.player +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.FilterMode +import heckerpowered.matrix.client.render.PostProcessRenderer import heckerpowered.matrix.client.shader.BlurRenderer import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus import heckerpowered.matrix.common.magic.core.Magic +import heckerpowered.matrix.common.magic.core.MagicAvailability import heckerpowered.matrix.common.magic.core.MagicCalculationContext -import heckerpowered.matrix.common.magic.core.description -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.text.Text -import net.minecraft.util.math.ColorHelper +import heckerpowered.matrix.data.language.MatrixLanguage +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component +import net.minecraft.util.ARGB /** * Renderer of the magic list in the HUD. @@ -126,7 +128,7 @@ object MagicList { /** * Update the use animation list for the magics, called every frame. */ - private fun updateUseAnimationList(tickCounter: RenderTickCounter) { + private fun updateUseAnimationList(tickCounter: DeltaTracker) { for (i in animationList.indices) { val animation = animationList[i] if (animation == .0) { @@ -135,11 +137,13 @@ object MagicList { // Just update the animation for the current magic, they will automatically stop // when they reach their full duration. - animationList[i] = animation + tickCounter.lastFrameDuration / 2000000 + // 26.2: old Timer.lastFrameDuration (tick delta of the last rendered frame) is now + // DeltaTracker.getGameTimeDeltaTicks() (unpaused per-frame tick delta). + animationList[i] = animation + tickCounter.gameTimeDeltaTicks / 2000000 } } - fun render(drawContext: DrawContext, tickCounter: RenderTickCounter) { + fun render(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { if (magics.isEmpty()) { return } @@ -147,26 +151,27 @@ object MagicList { updateUseAnimationList(tickCounter) } - private fun getMagicAvailableStatus(magic: Magic): LMagicAvailableStatus { + private fun getMagicAvailableStatus(magic: Magic): MagicAvailability { val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) return magic.availableStatus(calculationContext) } private fun calculateMagicWidth(magic: Magic): Double { - val textRenderer = minecraft.textRenderer + val textRenderer = minecraft.font val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) val costString = magic.getCost(calculationContext).toString() - val statusString = magic.availableStatus(calculationContext).description.toString() + val statusString = (magic.availableStatus(calculationContext).firstOrNull()?.description + ?: MatrixLanguage.magicAvailable).string - val magicNameWidth = textRenderer.getWidth(magic.definition.name) - val costWidth = textRenderer.getWidth(costString) - val statusWidth = textRenderer.getWidth(statusString) + val magicNameWidth = textRenderer.width(magic.definition.name) + val costWidth = textRenderer.width(costString) + val statusWidth = textRenderer.width(statusString) return magicNameWidth + costWidth + statusWidth + MAGIC_ELEMENT_SPAN * 3 // 3 spans for the name, cost, and status } - private fun renderMagic(index: Int, drawContext: DrawContext, tickCounter: RenderTickCounter) { + private fun renderMagic(index: Int, drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { if (opacity.animatedValue == .0) { return } @@ -176,12 +181,13 @@ object MagicList { val calculationContext = MagicCalculationContext.fromEntity(player, targetedEntity) val costString = magic.getCost(calculationContext).toString() - val statusString = magic.availableStatus(calculationContext).description.toString() + val statusString = (magic.availableStatus(calculationContext).firstOrNull()?.description + ?: MatrixLanguage.magicAvailable).string - val textRenderer = minecraft.textRenderer - val magicNameWidth = textRenderer.getWidth(magic.definition.name) - val costWidth = textRenderer.getWidth(costString) - val statusWidth = textRenderer.getWidth(statusString) + val textRenderer = minecraft.font + val magicNameWidth = textRenderer.width(magic.definition.name) + val costWidth = textRenderer.width(costString) + val statusWidth = textRenderer.width(statusString) val magicWidth = magicNameWidth + costWidth + statusWidth + MAGIC_ELEMENT_SPAN * 3 // 3 spans for the name, cost, and status @@ -190,41 +196,50 @@ object MagicList { val startX = (MAGIC_ELEMENT_MARGIN + indent + xOffset.animatedValue).toFloat() val endX = (startX + widthAnimation.animatedValue).toFloat() - val startY = (index * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) + drawContext.scaledWindowHeight / 2 - (indentList.size + 1) * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) / 2).toFloat() + val startY = (index * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) + drawContext.guiHeight() / 2 - (indentList.size + 1) * (MAGIC_ELEMENT_HEIGHT + MAGIC_ELEMENT_MARGIN) / 2).toFloat() val endY = startY + MAGIC_ELEMENT_HEIGHT.toFloat() drawContext.enableScissor(startX.toInt(), startY.toInt(), endX.toInt(), endY.toInt()) - BlurRenderer.blurTextureRenderProgram.enableShader() - BlurRenderer.renderQuad() - BlurRenderer.blurTextureRenderProgram.disableShader() - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val builder = Tessellator.getInstance() - val buffer = builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) + // 1.21 composited the blurred HUD by drawing a scissored fullscreen quad through + // blur_mask.fsh, whose alpha<0.1 discard produced a hard cutout: faint-alpha fringes + // never touched the destination. The blit below must stay on the extracted-GUI path + // (drawContext) for GUI ordering and scissoring, and that path only alpha-blends, so + // the mask is pre-punched instead: blur_mask.fsh copies blurFramebuffer into a + // transparent-cleared ping target (blend off, so every discarded texel remains fully + // transparent), and the blit samples the punched copy — restoring the 1.21 hard-cutout + // look through ordinary alpha blending. + PostProcessRenderer.clear(PostProcessRenderer.ping) + BlurRenderer.renderQuad(PostProcessRenderer.ping) + PostProcessRenderer.ping.colorTextureView?.let { punchedView -> + val guiWidth = drawContext.guiWidth().toFloat() + val guiHeight = drawContext.guiHeight().toFloat() + drawContext.blit( + punchedView, + RenderSystem.getSamplerCache().getClampToEdge(FilterMode.LINEAR), + startX.toInt(), startY.toInt(), + (endX - startX).toInt(), (endY - startY).toInt(), + startX / guiWidth, endX / guiWidth, + startY / guiHeight, endY / guiHeight + ) + } val backgroundColorAnimation = backgroundColorAnimationList[index] - val backgroundColor = ColorHelper.Argb.getArgb( + val backgroundColor = ARGB.color( (opacity.animatedValue * 127.5).toInt(), backgroundColorAnimation.red.animatedValue.toInt(), backgroundColorAnimation.green.animatedValue.toInt(), backgroundColorAnimation.blue.animatedValue.toInt() ) - buffer.vertex(transformationMatrix, startX, startY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, endX, startY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, endX, endY, 0F).color(backgroundColor) - buffer.vertex(transformationMatrix, startX, endY, 0F).color(backgroundColor) - - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.disableBlend() + // 26.2: manual Tessellator/BufferRenderer quad replaced by GuiGraphicsExtractor.fill, + // which draws the same axis-aligned rectangle through the GUI render pipeline. + drawContext.fill(startX.toInt(), startY.toInt(), endX.toInt(), endY.toInt(), backgroundColor) - val foregroundColor = ColorHelper.Argb.getArgb((opacity.animatedValue * 255).toInt(), 255, 255, 255) - drawContext.drawText(textRenderer, magic.definition.name, startX.toInt() + 5, startY.toInt() + 5, foregroundColor, false) - drawContext.drawText(textRenderer, Text.literal(costString), startX.toInt() + magicNameWidth + 15, startY.toInt() + 5, foregroundColor, false) - drawContext.drawText(textRenderer, statusString, startX.toInt() + magicNameWidth + costWidth + 25, startY.toInt() + 5, foregroundColor, false) + val foregroundColor = ARGB.color((opacity.animatedValue * 255).toInt(), 255, 255, 255) + drawContext.text(textRenderer, magic.definition.name, startX.toInt() + 5, startY.toInt() + 5, foregroundColor, false) + drawContext.text(textRenderer, Component.literal(costString), startX.toInt() + magicNameWidth + 15, startY.toInt() + 5, foregroundColor, false) + drawContext.text(textRenderer, statusString, startX.toInt() + magicNameWidth + costWidth + 25, startY.toInt() + 5, foregroundColor, false) drawContext.disableScissor() } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt index e666131a..23c57181 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaBar.kt @@ -19,9 +19,9 @@ import heckerpowered.matrix.common.magic.channel.CasterContext import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.common.magic.rule.resource.CastingResourcePipeline import heckerpowered.matrix.data.language.MatrixLanguage -import net.minecraft.client.gui.DrawContext -import net.minecraft.text.Text -import net.minecraft.util.math.MathHelper +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.network.chat.Component +import net.minecraft.util.Mth class ManaBar { companion object { @@ -48,23 +48,36 @@ class ManaBar { easingFunction.oscillations = 0 } + /** + * The ledger-backed max mana is legitimately 0 until the first server sync after the HUD + * appears (and while the animation ramps up from its initial 0), so a 0-divisor + * percentage means "empty bar", not NaN (which crashes the roundToInt in the renderer). + */ + private fun percentageOfMaxMana(amount: Double): Double { + val maxMana = maxMana.animatedValue + if (maxMana <= 0.0) { + return 0.0 + } + return amount / maxMana + } + private fun manaPercentage(): Double { if (mana.value.isInfinite()) { return 1.0 } - return mana.animatedValue / maxMana.animatedValue + return percentageOfMaxMana(mana.animatedValue) } private val actualManaPercentage: Double get() = if (mana.value.isInfinite()) { 1.0 } else { - (mana.animatedValue - manaUsage.animatedValue) / maxMana.animatedValue + percentageOfMaxMana(mana.animatedValue - manaUsage.animatedValue) } private val dissolveShader = DissolveShader() - private fun renderManaBar(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer) { + private fun renderManaBar(drawContext: GuiGraphicsExtractor, renderer: LegacyMatrixUIRenderer) { if (!manaUsage.isAnimating) { mana.value -= manaUsage.value manaUsage.value = .0 @@ -74,7 +87,7 @@ class ManaBar { 10.0 + shownAnimation.animatedValue ) val maxPoint = Point( - MathHelper.lerp(manaPercentage(), 50.0, renderer.scaledWindowWidth - 50.0), + Mth.lerp(manaPercentage(), 50.0, renderer.scaledWindowWidth - 50.0), 25.0 + shownAnimation.animatedValue ) @@ -98,7 +111,7 @@ class ManaBar { val window = MinecraftClient.getInstance().window val scaleFactor = window.scaleFactor - val maxX = MathHelper.lerp(actualManaPercentage, 50.0, renderer.scaledWindowWidth - 50.0) + val maxX = Mth.lerp(actualManaPercentage, 50.0, renderer.scaledWindowWidth - 50.0) RenderSystem.enableScissor( (minPoint.x * scaleFactor).toInt(), (window.framebufferHeight - maxPoint.y * scaleFactor).toInt(), @@ -117,12 +130,11 @@ class ManaBar { dissolveShader.resolutionX = 1.0F dissolveShader.resolutionY = 1.0F */ - val multiplier = 1F - RenderSystem.setShaderColor(multiplier, multiplier, multiplier, 1.0F) + // 26.2: RenderSystem.setShaderColor no longer exists; the old calls used + // multiplier = 1F on both sides, i.e. identity — nothing to replace. renderer.renderRectangle(Rectangle(minPoint, maxPoint), manaBarColor) - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F) - val usagePercentage = manaUsage.animatedValue / maxMana.animatedValue + val usagePercentage = percentageOfMaxMana(manaUsage.animatedValue) val usageMinPoint = Point( (maxPoint.x - usagePercentage * (renderer.scaledWindowWidth - 100)).coerceAtLeast(50.0), minPoint.y @@ -130,7 +142,7 @@ class ManaBar { renderer.renderRectangle(Rectangle(usageMinPoint, maxPoint), usageManaColor) - val costPercentage = manaCost.animatedValue / maxMana.animatedValue + val costPercentage = percentageOfMaxMana(manaCost.animatedValue) val costMinPoint = Point( (usageMinPoint.x - costPercentage * (renderer.scaledWindowWidth - 100)).coerceAtLeast(50.0), maxPoint.y @@ -154,13 +166,13 @@ class ManaBar { val total = (castingResources.animatedValue * 10).toLong() / 10.0 if (total != 0.0) { renderer.render( - Text.literal("${MatrixLanguage.mana.string} ≈ $total + ${currentMana}/${maxMana}"), + Component.literal("${MatrixLanguage.mana.string} ≈ $total + ${currentMana}/${maxMana}"), Point(55.0, 12.5 + shownAnimation.animatedValue), Color(255, 255, 255, 255), true ) } else { renderer.render( - Text.literal("${MatrixLanguage.mana.string} = ${currentMana}/${maxMana}"), + Component.literal("${MatrixLanguage.mana.string} = ${currentMana}/${maxMana}"), Point(55.0, 12.5 + shownAnimation.animatedValue), Color(255, 255, 255, 255), true ) @@ -170,7 +182,7 @@ class ManaBar { val animationRemaining: Boolean get() = manaUsage.isAnimating || mana.isAnimating - fun render(drawContext: DrawContext, renderer: LegacyMatrixUIRenderer) { + fun render(drawContext: GuiGraphicsExtractor, renderer: LegacyMatrixUIRenderer) { if (!visibility) { opacityAnimation.value = .0 shownAnimation.value = -50.0 diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt index e94852f8..acb55267 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/ManaCostTooltip.kt @@ -5,7 +5,6 @@ package heckerpowered.matrix.client.ui.element -import com.mojang.blaze3d.systems.RenderSystem import heckerpowered.matrix.client.MatrixHud import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.player @@ -15,9 +14,9 @@ import heckerpowered.matrix.client.ui.foundation.animation.ColorAnimation import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.data.language.MatrixLanguage -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.util.ARGB import java.time.Duration import kotlin.math.abs import kotlin.math.min @@ -56,7 +55,7 @@ object ManaCostTooltip { } } - fun render(drawContext: DrawContext, tickCounter: RenderTickCounter) { + fun render(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { val currentMagic = MatrixHud.selectedMagic val target = MatrixHud.targetedEntity val calculationContext = MagicCalculationContext.fromEntity(player, target) @@ -81,30 +80,20 @@ object ManaCostTooltip { return } - val minPoint = Point(drawContext.scaledWindowWidth / 2 - 125.0, drawContext.scaledWindowHeight - shownAnimation.animatedValue) - val maxPoint = Point(drawContext.scaledWindowWidth / 2 + 125.0, minPoint.y + 15) + val minPoint = Point(drawContext.guiWidth() / 2 - 125.0, drawContext.guiHeight() - shownAnimation.animatedValue) + val maxPoint = Point(drawContext.guiWidth() / 2 + 125.0, minPoint.y + 15) val color = backgroundColorAnimation - val red = color.red.animatedValue.toFloat() - val green = color.green.animatedValue.toFloat() - val blue = color.blue.animatedValue.toFloat() - val alpha = (opacityAnimation.animatedValue * 0.5).toFloat() - - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR) - buffer.vertex(transformationMatrix, maxPoint.x.toFloat(), maxPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, maxPoint.x.toFloat(), minPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, minPoint.x.toFloat(), minPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - buffer.vertex(transformationMatrix, minPoint.x.toFloat(), maxPoint.y.toFloat(), 0.0F).color(red, green, blue, alpha) - - RenderSystem.enableBlend() - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - BufferRenderer.drawWithGlobalProgram(buffer.end()) - RenderSystem.disableBlend() - - val textRenderer = minecraft.textRenderer + val red = (color.red.animatedValue * 255.0).toInt() + val green = (color.green.animatedValue * 255.0).toInt() + val blue = (color.blue.animatedValue * 255.0).toInt() + val alpha = (opacityAnimation.animatedValue * 0.5 * 255.0).toInt() + + // 26.2: manual Tessellator/BufferRenderer quad replaced by GuiGraphicsExtractor.fill, + // which draws the same axis-aligned rectangle through the GUI render pipeline. + drawContext.fill(minPoint.x.toInt(), minPoint.y.toInt(), maxPoint.x.toInt(), maxPoint.y.toInt(), ARGB.color(alpha, red, green, blue)) + + val textRenderer = minecraft.font val difference = abs(normalCost - cost) if (difference != lastDifference) { differenceChangedAnimation.value = .0 @@ -135,21 +124,21 @@ object ManaCostTooltip { return } - val vertexConsumerProvider = drawContext.vertexConsumers val yOffset = 2.5F + // 26.2: manual textRenderer.draw(...) into a vertex consumer replaced by + // GuiGraphicsExtractor.text, which renders through the GUI text pipeline. if (stateForegroundOpacity > 3) { if (displayState) { - textRenderer.draw(MatrixLanguage.manaCostIncreased, minPoint.x.toFloat() + 5F, minPoint.y.toFloat() + yOffset, foregroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) + drawContext.text(textRenderer, MatrixLanguage.manaCostIncreased, (minPoint.x + 5.0).toInt(), (minPoint.y + yOffset).toInt(), foregroundColor.toInt(), false) } else { - textRenderer.draw(MatrixLanguage.manaCostReduced, minPoint.x.toFloat() + 5F, minPoint.y.toFloat() + yOffset, foregroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) + drawContext.text(textRenderer, MatrixLanguage.manaCostReduced, (minPoint.x + 5.0).toInt(), (minPoint.y + yOffset).toInt(), foregroundColor.toInt(), false) } } if ((foregroundOpacity * 255).toInt() > 3 && cost != normalCost) { - val width = textRenderer.getWidth(displayedDifference.toString()) - textRenderer.draw(displayedDifference.toString(), maxPoint.x.toFloat() - 5F - width, minPoint.y.toFloat() + yOffset, differenceForegroundColor.toInt(), false, transformationMatrix, vertexConsumerProvider, TextRenderer.TextLayerType.NORMAL, 0, 15728880) + val width = textRenderer.width(displayedDifference.toString()) + drawContext.text(textRenderer, displayedDifference.toString(), (maxPoint.x - 5.0).toInt() - width, (minPoint.y + yOffset).toInt(), differenceForegroundColor.toInt(), false) } - drawContext.draw() } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt index 6a0e7afc..a7f3f63e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/StatusHud.kt @@ -5,25 +5,21 @@ package heckerpowered.matrix.client.ui.element +import com.mojang.blaze3d.pipeline.BlendFunction import heckerpowered.matrix.client.MatrixHud import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.player import heckerpowered.matrix.client.render.shader.hud.ProgressRingRenderer -import heckerpowered.matrix.client.render.state.BlendFuncSeparateState -import heckerpowered.matrix.client.render.state.ProgramState -import heckerpowered.matrix.client.render.state.StateIsolation -import heckerpowered.matrix.client.render.state.capabilities.BlendState -import heckerpowered.matrix.client.render.state.capabilities.CullFaceState -import heckerpowered.matrix.client.render.state.capabilities.DepthTestState import heckerpowered.matrix.client.ui.foundation.animation.SimpleDoubleAnimation -import heckerpowered.matrix.common.effect.ModMobEffects.WITHER_ARMOR_CHARGED_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects import heckerpowered.matrix.common.item.ModComponents.borrowedTimeCharge import heckerpowered.matrix.common.item.ModComponents.borrowedTimeMaxCharge import heckerpowered.matrix.common.item.ModComponents.borrowedTimeState -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.* -import net.minecraft.entity.EquipmentSlot -import net.minecraft.util.math.ColorHelper +import net.minecraft.client.DeltaTracker +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.util.ARGB +import org.joml.Vector2f import org.joml.Vector4f object StatusHud { @@ -38,17 +34,49 @@ object StatusHud { // HudRenderCallback.EVENT.register(this::onHudRender) } - fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { + fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + // Drop rings a skipped capture left behind (e.g. vanilla menu blur active last frame). + pendingRings.clear() renderWitherArmor(drawContext, tickCounter) renderPhaseWalk(drawContext, tickCounter) } + private class PendingRing( + val color: Vector4f, + val progress: Float, + val center: Vector2f, + val radius: Float, + val thickness: Float, + val aspectRatio: Float, + ) + + private val pendingRings = mutableListOf() + + /** + * Draws the rings queued during extraction into [MatrixHud.hudFramebuffer]. Called by + * MatrixHud.onHudCaptureBegin right after the framebuffer is cleared and BEFORE the HUD + * stratum renders into it — this runs at GUI draw time (the extraction-time drawTo used to + * be wiped by that clear), and keeps the 1.21 order of ring below, text on top. + */ + fun flushPendingRings() { + for (ring in pendingRings) { + ProgressRingRenderer.color = ring.color + ProgressRingRenderer.progress = ring.progress + ProgressRingRenderer.center = ring.center + ProgressRingRenderer.radius = ring.radius + ProgressRingRenderer.thickness = ring.thickness + ProgressRingRenderer.aspectRatio = ring.aspectRatio + ProgressRingRenderer.progressRingShader.drawTo(MatrixHud.hudFramebuffer, BlendFunction.TRANSLUCENT) + } + pendingRings.clear() + } + private val phaseWalkProgress = SimpleDoubleAnimation(initValue = .0) private val phaseWalkOpacity = SimpleDoubleAnimation(initValue = .0) private val phaseWalkYOffset = SimpleDoubleAnimation() - private fun renderPhaseWalk(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val chestplate = player.getEquippedStack(EquipmentSlot.CHEST) + private fun renderPhaseWalk(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + val chestplate = player.getItemBySlot(EquipmentSlot.CHEST) val isPhaseWalking = chestplate.components.getOrDefault(borrowedTimeState, false) val currentCharge = chestplate.components.getOrDefault(borrowedTimeCharge, 0L) val maxCharge = chestplate.components.getOrDefault(borrowedTimeMaxCharge, 0L) @@ -76,8 +104,8 @@ object StatusHud { ) } - private fun renderWitherArmor(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val statusEffect = player.getStatusEffect(WITHER_ARMOR_CHARGED_EFFECT) + private fun renderWitherArmor(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + val statusEffect = player.getEffect(ModMobEffects.WitherArmorCharged) if (statusEffect != null) { val previousValue = progress.value progress.value = 1.0 - statusEffect.duration / 200.0 @@ -103,12 +131,12 @@ object StatusHud { renderProgressRing(drawContext, progress.animatedValue.toFloat(), (statusEffect?.amplifier ?: 0).toString(), "凋零护甲", opacityAnimation.animatedValue.toFloat()) } - private fun renderProgressRing(drawContext: DrawContext, progress: Float, progressString: String, description: String, opacity: Float, xOffset: Float = 0F, yOffset: Float = 0F) { + private fun renderProgressRing(drawContext: GuiGraphicsExtractor, progress: Float, progressString: String, description: String, opacity: Float, xOffset: Float = 0F, yOffset: Float = 0F) { MatrixHud.renderHud = true MatrixHud.useBloom = true - val scaledWidth = drawContext.scaledWindowWidth - val scaledHeight = drawContext.scaledWindowHeight + val scaledWidth = drawContext.guiWidth() + val scaledHeight = drawContext.guiHeight() val progressRingX = scaledWidth.toFloat() val progressRingY = scaledHeight / 2F @@ -119,50 +147,52 @@ object StatusHud { val minY = progressRingY + PROGRESS_RING_SIZE / 2 + yOffset val maxY = progressRingY - PROGRESS_RING_SIZE / 2 + yOffset - val transformationMatrix = drawContext.matrices.peek().positionMatrix - val tessellator = Tessellator.getInstance() - val buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE) - - buffer.vertex(transformationMatrix, minX, minY, 0F).texture(0F, 0F) - buffer.vertex(transformationMatrix, maxX, minY, 0F).texture(1F, 0F) - buffer.vertex(transformationMatrix, maxX, maxY, 0F).texture(1F, 1F) - buffer.vertex(transformationMatrix, minX, maxY, 0F).texture(0F, 1F) - - ProgressRingRenderer.color = Vector4f(1.5F, 1.5F, 1.5F, opacity) - ProgressRingRenderer.progress = progress - - StateIsolation.isolate( - BlendState(true), - BlendFuncSeparateState(), - DepthTestState(false), - CullFaceState(false), - ProgramState(ProgressRingRenderer.progressRingShader) - ) { - BufferRenderer.draw(buffer.end()) - } + // 26.2: the ring was a POSITION_TEXTURE quad drawn through progressRingShader (the + // quad's texcoords spanned the ring). progressRingShader is now a fullscreen + // BlitProgram, so the quad placement moves into the shader's center/radius/thickness + // uniforms (fragTexCoord space, y-up), and the pass targets MatrixHud.hudFramebuffer -- + // the framebuffer that was implicitly bound here in 1.21 -- so the ring still feeds the + // blur/bloom composite (the 1.5x HDR color is preserved for the bloom pass). This runs + // during GUI EXTRACTION, but hudFramebuffer is cleared at GUI draw time right before + // the stratum renders, so the pass itself is queued and flushed post-clear + // (see flushPendingRings). + val radius = (PROGRESS_RING_SIZE / 2F) / scaledHeight + pendingRings.add( + PendingRing( + color = Vector4f(1.5F, 1.5F, 1.5F, opacity), + progress = progress, + center = Vector2f( + ((minX + maxX) / 2F) / scaledWidth, + 1F - ((minY + maxY) / 2F) / scaledHeight + ), + radius = radius, + thickness = radius * 0.2F, + aspectRatio = scaledWidth.toFloat() / scaledHeight, + ) + ) - val width = minecraft.textRenderer.getWidth(progressString) + val width = minecraft.font.width(progressString) val textAlpha = (opacity * 255).toInt() if (textAlpha <= 3) { return } - drawContext.drawText( - minecraft.textRenderer, + drawContext.text( + minecraft.font, progressString, ((minX + maxX) / 2).toInt() - width / 2, - ((minY + maxY) / 2).toInt() - minecraft.textRenderer.fontHeight / 2, - ColorHelper.Argb.getArgb(textAlpha, 255, 255, 255), + ((minY + maxY) / 2).toInt() - minecraft.font.lineHeight / 2, + ARGB.color(textAlpha, 255, 255, 255), true ) - val descWidth = minecraft.textRenderer.getWidth(description) - drawContext.drawText( - minecraft.textRenderer, + val descWidth = minecraft.font.width(description) + drawContext.text( + minecraft.font, description, ((minX + maxX) / 2).toInt() - descWidth / 2, - minY.toInt() + minecraft.textRenderer.fontHeight, - ColorHelper.Argb.getArgb(textAlpha, 255, 255, 255), + minY.toInt() + minecraft.font.lineHeight, + ARGB.color(textAlpha, 255, 255, 255), true ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt index d5bae526..481b74e0 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/element/SystemCrashBar.kt @@ -6,8 +6,9 @@ package heckerpowered.matrix.client.ui.element import com.google.common.base.Stopwatch +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.client.minecraft import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.client.render.LegacyMatrixUIRenderer import heckerpowered.matrix.client.render.Point import heckerpowered.matrix.client.render.Rectangle import heckerpowered.matrix.client.ui.foundation.animation.AnimationClock @@ -15,11 +16,11 @@ import heckerpowered.matrix.client.ui.foundation.animation.DoubleAnimation import heckerpowered.matrix.client.ui.foundation.animation.EasingMode import heckerpowered.matrix.client.ui.foundation.animation.ElasticEase import heckerpowered.matrix.data.language.MatrixLanguage -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.util.math.MathHelper +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiGraphicsExtractor +import net.minecraft.client.DeltaTracker +import net.minecraft.util.Mth import java.io.File import java.io.FileOutputStream import java.time.Duration @@ -40,12 +41,14 @@ object SystemCrashBar { private val opacityAnimation = DoubleAnimation(opacityClock, easingFunction) fun onInitialize() { - HudRenderCallback.EVENT.register(this::onHudRender) + // 26.2: HudRenderCallback was replaced by HudElementRegistry; still invoked once per rendered frame. + HudElementRegistry.addLast(Matrix.identifier("system_crash_bar")) { drawContext, tickCounter -> + onHudRender(drawContext, tickCounter) + } } - private fun onHudRender(drawContext: DrawContext, tickCounter: RenderTickCounter) { - val renderer = LegacyMatrixUIRenderer(drawContext.vertexConsumers) - render(renderer) + private fun onHudRender(drawContext: GuiGraphicsExtractor, tickCounter: DeltaTracker) { + render(drawContext) } fun systemCrash() { @@ -74,11 +77,25 @@ object SystemCrashBar { Runtime.getRuntime().exec("\"${file.absolutePath}\"") } catch (e: Exception) { e.printStackTrace() - MinecraftClient.getInstance().close() + Minecraft.getInstance().close() } } - fun render(renderer: LegacyMatrixUIRenderer) { + // 26.2: LegacyMatrixUIRenderer needed a VertexConsumerProvider.Immediate, which + // GuiGraphicsExtractor no longer exposes (immediate-mode drawing was removed). This now + // draws directly through GuiGraphicsExtractor.fill()/text(), which is order-independent + // on min/max like the old renderRectangle() quad, keeping the same rectangles and text. + private fun renderRectangle(drawContext: GuiGraphicsExtractor, rectangle: Rectangle, color: Color) { + drawContext.fill( + rectangle.min.x.toInt(), + rectangle.min.y.toInt(), + rectangle.max.x.toInt(), + rectangle.max.y.toInt(), + color.toInt() + ) + } + + fun render(drawContext: GuiGraphicsExtractor) { if (stopWatch.elapsed(TimeUnit.NANOSECONDS).toDouble() >= CHANNEL_TIME.toNanos().toDouble() && !bsod) { bsod = true windowsBlueScreen() @@ -88,32 +105,34 @@ object SystemCrashBar { val progressBackground = Color(128, 0, 0, (128.0 * opacityAnimation.animatedValue).toInt()) val progressForeground = Color(255, 0, 0, (255.0 * opacityAnimation.animatedValue).toInt()) + val scaledWindowWidth = drawContext.guiWidth() + val scaledWindowHeight = drawContext.guiHeight() + val minPoint = Point( - renderer.scaledWindowWidth / 2 - 125.0, - renderer.scaledWindowHeight - 100.0 + scaledWindowWidth / 2 - 125.0, + scaledWindowHeight - 100.0 ) val maxPoint = Point( - renderer.scaledWindowWidth / 2 + 125.0, - renderer.scaledWindowHeight - 125.0 + scaledWindowWidth / 2 + 125.0, + scaledWindowHeight - 125.0 ) - renderer.renderRectangle(Rectangle(minPoint, maxPoint), progressBackground) + renderRectangle(drawContext, Rectangle(minPoint, maxPoint), progressBackground) val progressMaxPoint = Point( - MathHelper.lerp(progress, minPoint.x, maxPoint.x), + Mth.lerp(progress, minPoint.x, maxPoint.x), maxPoint.y ) - renderer.renderRectangle(Rectangle(minPoint, progressMaxPoint), progressForeground) + renderRectangle(drawContext, Rectangle(minPoint, progressMaxPoint), progressForeground) if (255 * opacityAnimation.animatedValue <= 0.05) { return } - renderer.render( + drawContext.text( + minecraft.font, MatrixLanguage.systemCrashing, - Point( - renderer.scaledWindowWidth / 2 - 125.0 + 8, - renderer.scaledWindowHeight - 125.0 + 8.5 - ), - Color(255, 255, 255, (255 * opacityAnimation.animatedValue).toInt()), + (scaledWindowWidth / 2 - 125.0 + 8).toInt(), + (scaledWindowHeight - 125.0 + 8.5).toInt(), + Color(255, 255, 255, (255 * opacityAnimation.animatedValue).toInt()).toInt(), true ) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt b/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt index 0b39fad2..bdf83977 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/client/ui/foundation/animation/AnimationClock.kt @@ -6,7 +6,7 @@ package heckerpowered.matrix.client.ui.foundation.animation import heckerpowered.matrix.core.lerp -import net.minecraft.util.math.MathHelper +import net.minecraft.util.Mth import org.apache.commons.lang3.time.StopWatch import java.time.Duration import kotlin.math.max @@ -50,7 +50,7 @@ class AnimationClock(var duration: Duration, var from: Double, var to: Double, v private fun getValueAt(timeNanos: Long): Double { val progress = (timeNanos.toDouble() / duration.toNanos().toDouble()).coerceIn(.0..1.0) - return MathHelper.lerp(progress, 0.0, 1.0) + return Mth.lerp(progress, 0.0, 1.0) } val progress: Double diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt b/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt index 9450849f..d144185b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/MatrixServerPlayNetworking.kt @@ -15,6 +15,7 @@ object MatrixServerPlayNetworking { PayloadTypeRegistry.serverboundPlay().register(ServerboundWarpPayload.type, ServerboundWarpPayload.codec) PayloadTypeRegistry.serverboundPlay().register(ServerboundActivateBloodPactPayload.type, ServerboundActivateBloodPactPayload.codec) PayloadTypeRegistry.serverboundPlay().register(ServerboundBorrowedTimePayload.type, ServerboundBorrowedTimePayload.codec) + PayloadTypeRegistry.serverboundPlay().register(ServerboundOverclockPayload.type, ServerboundOverclockPayload.codec) PayloadTypeRegistry.clientboundPlay().register(ClientboundSyncManaPayload.type, ClientboundSyncManaPayload.codec) PayloadTypeRegistry.clientboundPlay().register(ClientboundSystemCrashPayload.type, ClientboundSystemCrashPayload.codec) @@ -30,5 +31,6 @@ object MatrixServerPlayNetworking { ServerPlayNetworking.registerGlobalReceiver(ServerboundWarpPayload.type, ServerboundWarpPayload::handle) ServerPlayNetworking.registerGlobalReceiver(ServerboundActivateBloodPactPayload.type, ServerboundActivateBloodPactPayload::handle) ServerPlayNetworking.registerGlobalReceiver(ServerboundBorrowedTimePayload.type, ServerboundBorrowedTimePayload::handle) + ServerPlayNetworking.registerGlobalReceiver(ServerboundOverclockPayload.type, ServerboundOverclockPayload::handle) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt b/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt index 13b348e2..6c213f05 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/combat/damage/DamageSourceEnvelope.kt @@ -7,4 +7,10 @@ package heckerpowered.matrix.common.combat.damage import net.minecraft.world.damagesource.DamageSource -class DamageSourceEnvelope(val origin: DamageSource, val rawDamage: Float) : DamageSource(origin.typeRegistryEntry, origin.source, origin.attacker) \ No newline at end of file +class DamageSourceEnvelope(val origin: DamageSource, val rawDamage: Float) : DamageSource(origin.typeHolder(), origin.directEntity, origin.entity) { + override var isAdditionalDamage: Boolean + get() = origin.isAdditionalDamage + set(value) { + origin.isAdditionalDamage = value + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt b/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt index 629afc54..ab5c6fed 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/command/MatrixCommands.kt @@ -6,13 +6,28 @@ package heckerpowered.matrix.common.command import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.DoubleArgumentType +import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana +import heckerpowered.matrix.common.magic.system.ManaLedger +import heckerpowered.matrix.common.network.ClientboundSyncManaPayload import heckerpowered.matrix.common.persistent.isInfiniteMana +import heckerpowered.matrix.core.mana +import heckerpowered.matrix.core.maxMana import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking +import net.minecraft.commands.Commands.argument import net.minecraft.commands.Commands.hasPermission import net.minecraft.commands.Commands.literal +import net.minecraft.commands.arguments.EntityArgument +import net.minecraft.server.level.ServerPlayer import net.minecraft.server.permissions.PermissionCheck import net.minecraft.server.permissions.Permissions +/** + * `/matrix mana ...` debug commands, tree restored from the pre-migration jar: + * `set []` writes an absolute mana value (clamped to `0..maxMana`) and + * `infinite` toggles infinite mana for the executing player. + */ object MatrixCommands { fun onInitialize() { @@ -21,14 +36,46 @@ object MatrixCommands { literal("matrix").then( literal("mana") .requires(hasPermission(PermissionCheck.Require(Permissions.COMMANDS_GAMEMASTER))) - .then(literal("infinite")) - .executes { context -> - val player = context.source.playerOrException - player.isInfiniteMana = !player.isInfiniteMana - return@executes Command.SINGLE_SUCCESS - } + .then( + literal("set").then( + argument("amount", DoubleArgumentType.doubleArg(0.0)) + .executes { context -> + setMana(context.source.playerOrException, DoubleArgumentType.getDouble(context, "amount")) + Command.SINGLE_SUCCESS + } + .then( + argument("target", EntityArgument.players()).executes { context -> + val amount = DoubleArgumentType.getDouble(context, "amount") + EntityArgument.getPlayers(context, "target").forEach { setMana(it, amount) } + Command.SINGLE_SUCCESS + } + ) + ) + ) + .then( + literal("infinite").executes { context -> + val player = context.source.playerOrException + player.isInfiniteMana = !player.isInfiniteMana + Command.SINGLE_SUCCESS + } + ) ) ) } } -} \ No newline at end of file + + /** + * The pre-migration `setMana` wrote the clamped value into the persistent mana pool and + * synced immediately; mana is a ledger balance now, so reach the same clamped target by + * issuing/extinguishing the difference. + */ + private fun setMana(player: ServerPlayer, amount: Double) { + val target = amount.coerceIn(0.0, player.maxMana.toDouble().coerceAtLeast(0.0)) + val delta = target - player.mana.toDouble() + when { + delta > 0 -> ManaLedger.issueMana(player, delta.mana) + delta < 0 -> ManaLedger.extinguishMana(player, (-delta).mana) + } + ServerPlayNetworking.send(player, ClientboundSyncManaPayload(player.mana.toDouble(), player.maxMana.toDouble())) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/effect/IgniteEffect.kt b/common/src/main/kotlin/heckerpowered/matrix/common/effect/IgniteEffect.kt index f3f6bec7..a04a5bb8 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/effect/IgniteEffect.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/effect/IgniteEffect.kt @@ -6,7 +6,7 @@ package heckerpowered.matrix.common.effect import heckerpowered.matrix.common.combat.damage.* -import heckerpowered.matrix.common.effect.ModMobEffects.IGNITE_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.Ignite import heckerpowered.matrix.common.entity.rule.AttributeComputationContext import heckerpowered.matrix.common.entity.rule.AttributeComputationRule import heckerpowered.matrix.common.rule.RuleRegistry @@ -83,7 +83,7 @@ object IgniteEffect : MobEffect( val target = context.target if (context.source.isAdditionalDamage) return - if (!target.hasEffect(IGNITE_EFFECT)) return + if (!target.hasEffect(Ignite)) return if (!source.`is`(DamageTypeTags.IS_FIRE)) return context.damageMultiplier += 0.2 @@ -94,7 +94,7 @@ object IgniteEffect : MobEffect( val target = context.target if (context.source.isAdditionalDamage) return - val igniteEffect = target.getEffect(IGNITE_EFFECT) ?: return + val igniteEffect = target.getEffect(Ignite) ?: return if (source.`is`(DamageTypeTags.IS_FIRE)) return igniteEffect.mapDuration { it + 10 } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/WitherArmorEnchantment.kt b/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/WitherArmorEnchantment.kt index fe6f17bb..f45f55b5 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/WitherArmorEnchantment.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/enchantment/WitherArmorEnchantment.kt @@ -5,7 +5,7 @@ package heckerpowered.matrix.common.enchantment -import heckerpowered.matrix.common.effect.ModMobEffects.WITHER_ARMOR_CHARGED_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.WitherArmorCharged import heckerpowered.matrix.common.entity.rule.EntityUpdateContext import heckerpowered.matrix.common.entity.rule.EntityUpdateRule import heckerpowered.matrix.common.rule.RuleRegistry @@ -30,9 +30,9 @@ object WitherArmorEnchantment : EntityUpdateRule { val enchantmentLevel = entity.getEnchantmentLevel(ModEnchantments.WitherArmor) if (enchantmentLevel <= 0) return - if (entity.hasEffect(WITHER_ARMOR_CHARGED_EFFECT)) return + if (entity.hasEffect(WitherArmorCharged)) return - entity.addEffect(MobEffectInstance(WITHER_ARMOR_CHARGED_EFFECT, 20 * 10, 0, true, true)) + entity.addEffect(MobEffectInstance(WitherArmorCharged, 20 * 10, 0, true, true)) if (entity is ServerPlayer) { entity.level().server.playerList.sendActiveEffects(entity, entity.connection) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt index 1e1a0a52..7a297ed7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/AttractorEntity.kt @@ -49,11 +49,11 @@ class AttractorEntity(entityType: EntityType, level: Level) : E get() = entityData.get(AttractorEntity.ownerUuid).getOrNull() set(value) = entityData.set(AttractorEntity.ownerUuid, Optional.ofNullable(value)) - var owner: LivingEntity? - get() = super.getOwner() - set(value) { - ownerUuid = EntityReference.of(value) - } + // 26.2: a Kotlin `owner` property would accidentally override OwnableEntity's default + // getOwner(); reads go through the interface default, writes through this setter. + fun setOwner(value: LivingEntity?) { + ownerUuid = EntityReference.of(value) + } constructor(level: Level) : this(ModEntityTypes.attractor, level) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt index a5ab0798..8ed06c58 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/DevEntity.kt @@ -5,65 +5,72 @@ package heckerpowered.matrix.common.entity -import net.minecraft.entity.EntityType -import net.minecraft.entity.attribute.DefaultAttributeContainer -import net.minecraft.entity.attribute.EntityAttribute -import net.minecraft.entity.attribute.EntityAttributes -import net.minecraft.entity.boss.BossBar -import net.minecraft.entity.boss.ServerBossBar -import net.minecraft.entity.damage.DamageSource -import net.minecraft.entity.mob.PathAwareEntity -import net.minecraft.registry.entry.RegistryEntry -import net.minecraft.server.network.ServerPlayerEntity -import net.minecraft.world.World +import heckerpowered.matrix.common.magic.channel.ChannelQueue +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.ai.attributes.AttributeSupplier +import net.minecraft.world.entity.ai.attributes.Attribute +import net.minecraft.world.entity.ai.attributes.Attributes +import net.minecraft.world.BossEvent +import net.minecraft.server.level.ServerBossEvent +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.entity.PathfinderMob +import net.minecraft.core.Holder +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.level.Level import net.minecraft.world.entity.Mob.createMobAttributes +import java.util.UUID -class DevEntity(entityType: EntityType, world: World) : PathAwareEntity(entityType, world) { +class DevEntity(entityType: EntityType, world: Level) : PathfinderMob(entityType, world) { - private val bossBar = ServerBossBar(this.displayName, BossBar.Color.BLUE, BossBar.Style.NOTCHED_20) + override var polarity: Long = 0L + override var healthSpoofValue: Float = 0.0F + override val channelQueues: MutableMap = mutableMapOf() - constructor(world: World) : this(ModEntityTypes.devEntity, world) + private val bossBar = ServerBossEvent(uuid, this.displayName, BossEvent.BossBarColor.BLUE, BossEvent.BossBarOverlay.NOTCHED_20) + + constructor(world: Level) : this(ModEntityTypes.devEntity, world) companion object { const val HEALTH_SCALE = 10000000.0 - fun createDevAttributes(): DefaultAttributeContainer.Builder { + fun createDevAttributes(): AttributeSupplier.Builder { return createMobAttributes() - .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 35.0) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.23) - .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 20.0) - .add(EntityAttributes.GENERIC_ARMOR, 20.0) - .add(EntityAttributes.GENERIC_ARMOR_TOUGHNESS, 2.0) - .add(EntityAttributes.GENERIC_MAX_HEALTH, 1000.0 * HEALTH_SCALE) - .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0) - .add(EntityAttributes.ZOMBIE_SPAWN_REINFORCEMENTS) + .add(Attributes.FOLLOW_RANGE, 35.0) + .add(Attributes.MOVEMENT_SPEED, 0.23) + .add(Attributes.ATTACK_DAMAGE, 20.0) + .add(Attributes.ARMOR, 20.0) + .add(Attributes.ARMOR_TOUGHNESS, 2.0) + .add(Attributes.MAX_HEALTH, 1000.0 * HEALTH_SCALE) + .add(Attributes.KNOCKBACK_RESISTANCE, 1.0) + .add(Attributes.SPAWN_REINFORCEMENTS_CHANCE) } } - override fun damage(source: DamageSource, amount: Float): Boolean { - return super.damage(source, amount) + override fun hurtServer(level: ServerLevel, source: DamageSource, amount: Float): Boolean { + return super.hurtServer(level, source, amount) } - override fun getAttributeValue(attribute: RegistryEntry): Double { - if (attribute == EntityAttributes.GENERIC_MAX_HEALTH) { + override fun getAttributeValue(attribute: Holder): Double { + if (attribute == Attributes.MAX_HEALTH) { return 1000.0 * HEALTH_SCALE } return super.getAttributeValue(attribute) } - override fun mobTick() { - super.mobTick() + override fun customServerAiStep(level: ServerLevel) { + super.customServerAiStep(level) - bossBar.setPercent(health / maxHealth) + bossBar.setProgress(health / maxHealth) } - override fun onStartedTrackingBy(player: ServerPlayerEntity?) { - super.onStartedTrackingBy(player) + override fun startSeenByPlayer(player: ServerPlayer) { + super.startSeenByPlayer(player) bossBar.addPlayer(player) } - override fun onStoppedTrackingBy(player: ServerPlayerEntity?) { - super.onStoppedTrackingBy(player) + override fun stopSeenByPlayer(player: ServerPlayer) { + super.stopSeenByPlayer(player) bossBar.removePlayer(player) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt index ddc520bd..b9911e38 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/FinderArrowEntity.kt @@ -7,51 +7,52 @@ package heckerpowered.matrix.common.entity import heckerpowered.matrix.common.entity.ModEntityTypes.FINDER_ARROW_ENTITY import heckerpowered.matrix.common.item.FinderArrowItem -import heckerpowered.matrix.core.squaredDistanceTo -import net.minecraft.core.SectionPos.y -import net.minecraft.core.SectionPos.z -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.effect.StatusEffectInstance -import net.minecraft.entity.effect.StatusEffects -import net.minecraft.entity.projectile.PersistentProjectileEntity -import net.minecraft.item.ItemStack -import net.minecraft.particle.ParticleTypes -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.math.Vec3d -import net.minecraft.world.World -import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom.pos +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects +import net.minecraft.world.entity.projectile.arrow.AbstractArrow +import net.minecraft.world.item.ItemStack +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.core.BlockPos +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 +import net.minecraft.world.level.Level -class FinderArrowEntity : PersistentProjectileEntity { - constructor(world: World, owner: LivingEntity, stack: ItemStack, shotFrom: ItemStack?) : super(FINDER_ARROW_ENTITY, owner, world, stack, shotFrom) - constructor(world: World) : super(FINDER_ARROW_ENTITY, world) +class FinderArrowEntity : AbstractArrow { + constructor(world: Level, owner: LivingEntity, stack: ItemStack, shotFrom: ItemStack?) : super(FINDER_ARROW_ENTITY, owner, world, stack, shotFrom) + constructor(world: Level) : super(FINDER_ARROW_ENTITY, world) override fun tick() { super.tick() - if (world.isClient && !inGround) { - world.addParticle(ParticleTypes.INSTANT_EFFECT, x, y, z, 0.0, 0.0, 0.0) + if (level().isClientSide && !isInGround) { + // 26.2: INSTANT_EFFECT particles carry a color option; white with full power + // matches the pre-migration default appearance. + level().addParticle( + net.minecraft.core.particles.SpellParticleOption.create(ParticleTypes.INSTANT_EFFECT, 1.0F, 1.0F, 1.0F, 1.0F), + x, y, z, 0.0, 0.0, 0.0 + ) } - if (inGround) { + if (isInGround) { return } - val previousPosition = Vec3d(prevX, prevY, prevZ) - val currentPosition = pos - val searchBox = Box(previousPosition, currentPosition).expand(12.0, 9999.0, 12.0) - world.getOtherEntities(owner, searchBox) + val previousPosition = Vec3(xo, yo, zo) + val currentPosition = position() + val searchBox = AABB(previousPosition, currentPosition).inflate(12.0, 9999.0, 12.0) + level().getEntities(getOwner(), searchBox) .filterIsInstance() .filter { - val blockPos = BlockPos.ofFloored(it.x, it.y, it.z) - this squaredDistanceTo it <= 144 // 144 = 12 * 12 (radius) - || it.world.isSkyVisible(blockPos) + val blockPos = BlockPos.containing(it.x, it.y, it.z) + this.distanceToSqr(it) <= 144 // 144 = 12 * 12 (radius) + || it.level().canSeeSky(blockPos) } .forEach { - val statusEffectInstance = StatusEffectInstance(StatusEffects.GLOWING, 20 * 5, 0) - it.addStatusEffect(statusEffectInstance, effectCause) + val statusEffectInstance = MobEffectInstance(MobEffects.GLOWING, 20 * 5, 0) + it.addEffect(statusEffectInstance, effectSource) } } - override fun getDefaultItemStack(): ItemStack { + override fun getDefaultPickupItem(): ItemStack { return ItemStack(FinderArrowItem) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt index 51578b02..a4aa2a49 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ItemProjectileEntity.kt @@ -5,19 +5,19 @@ package heckerpowered.matrix.common.entity -import net.minecraft.entity.EntityType -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.data.DataTracker -import net.minecraft.entity.projectile.ProjectileEntity -import net.minecraft.item.ItemStack -import net.minecraft.world.World +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.LivingEntity +import net.minecraft.network.syncher.SynchedEntityData +import net.minecraft.world.entity.projectile.Projectile +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.Level -class ItemProjectileEntity(entityType: EntityType, world: World, owner: LivingEntity?, var stack: ItemStack) : ProjectileEntity(entityType, world) { +class ItemProjectileEntity(entityType: EntityType, world: Level, owner: LivingEntity?, var stack: ItemStack) : Projectile(entityType, world) { init { - this.owner = owner + this.setOwner(owner) } - override fun initDataTracker(builder: DataTracker.Builder) { + override fun defineSynchedData(builder: SynchedEntityData.Builder) { } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt index 81f34bf8..558e5fa0 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/MagicLightningBolt.kt @@ -6,9 +6,9 @@ package heckerpowered.matrix.common.entity import heckerpowered.matrix.client.render.Color -import heckerpowered.matrix.common.effect.ModMobEffects.ARMOR_PENETRATION_EFFECT -import heckerpowered.matrix.common.effect.ModMobEffects.CRIPPLE_MOVEMENT_EFFECT -import heckerpowered.matrix.common.effect.ModMobEffects.EXPOSED_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.ArmorPenetration +import heckerpowered.matrix.common.effect.ModMobEffects.CrippleMovement +import heckerpowered.matrix.common.effect.ModMobEffects.Exposed import heckerpowered.matrix.common.entity.MagicLightningBolt.LightningType.* import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.ExecutionPolicy @@ -18,9 +18,12 @@ import heckerpowered.matrix.common.magic.spell.ExplosionMagic.damageCalculator import heckerpowered.matrix.common.magic.spell.LightningBoltMagic import heckerpowered.matrix.common.tag.MatrixDamageTypes import heckerpowered.matrix.core.extension.damage +import heckerpowered.matrix.mixin.LivingEntityAccessor import net.minecraft.network.protocol.game.ClientboundAddEntityPacket import net.minecraft.server.level.ServerLevel import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects import net.minecraft.world.entity.Entity import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.LightningBolt @@ -58,57 +61,61 @@ class MagicLightningBolt(entityType: EntityType, level: Leve constructor(level: Level) : this(ModEntityTypes.MAGIC_LIGHTNING_ENTITY, level) private fun onStruckByLightning(entity: Entity) { - ++entity.fireTicks - if (entity.fireTicks == 0) { - entity.setOnFireFor(8.0f) + // Strikes only happen on the logical server; 26.2 splits Entity#hurt into + // hurtServer/hurtClient, and hurtServer (normal invulnerability frames) is the + // exact equivalent of the 1.21 Entity#damage these calls used. + val serverLevel = level() as? ServerLevel ?: return + ++entity.remainingFireTicks + if (entity.remainingFireTicks == 0) { + entity.igniteForSeconds(8.0f) } - val channeler = this.channeler + val channeler = this.cause val damageSource = if (channeler != null) { - channeler.world.damageSources.create(MatrixDamageTypes.magic, channeler) + channeler.level().damageSources().source(MatrixDamageTypes.magic, channeler) } else { - damageSources.generic() + damageSources().generic() } when (lightningType) { NORMAL -> performNormalStrike(entity) - RED -> entity.damage(damageSource, 20.0F) + RED -> entity.hurtServer(serverLevel, damageSource, 20.0F) ORANGE -> { if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(ARMOR_PENETRATION_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(ArmorPenetration, 20 * 10, 4)) } - entity.damage(damageSource, 5.0F) + entity.hurtServer(serverLevel, damageSource, 5.0F) } YELLOW -> { channeler?.apply { - lastAttackedTicks = Int.MAX_VALUE - swingHand(activeHand) + (this as LivingEntityAccessor).`matrix$setAttackStrengthTicker`(Int.MAX_VALUE) + swing(usedItemHand) attack(entity) - addCritParticles(entity) - addEnchantedHitParticles(entity) + crit(entity) + magicCrit(entity) } - entity.damage(damageSource, 5.0F) + entity.hurtServer(serverLevel, damageSource, 5.0F) if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 20 * 10, 0)) + entity.addEffect(MobEffectInstance(MobEffects.GLOWING, 20 * 10, 0)) } } GREEN -> { channeler?.heal(2F) - entity.damage(damageSource, 5.0F) + entity.hurtServer(serverLevel, damageSource, 5.0F) if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(StatusEffects.POISON, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(MobEffects.POISON, 20 * 10, 4)) } } CYAN -> { if (entity is LivingEntity) { - if (entity.hasStatusEffect(CRIPPLE_MOVEMENT_EFFECT)) { - entity.addStatusEffect(StatusEffectInstance(EXPOSED_EFFECT, 20 * 10, 0)) + if (entity.hasEffect(CrippleMovement)) { + entity.addEffect(MobEffectInstance(Exposed, 20 * 10, 0)) } val channeler = channeler if (channeler == null) { - entity.addStatusEffect(StatusEffectInstance(CRIPPLE_MOVEMENT_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(CrippleMovement, 20 * 10, 4)) } else { val invocation = MagicInvocation.fromEntity(channeler, entity) val attempt = ExecutionPolicy(costMana = false) @@ -119,11 +126,11 @@ class MagicLightningBolt(entityType: EntityType, level: Leve BLUE -> { if (channeler == null) { - entity.damage(damageSource, 5.0F) + entity.hurtServer(serverLevel, damageSource, 5.0F) return } - for (target in entity.world.getOtherEntities(entity, entity.boundingBox.expand(6.0))) { + for (target in entity.level().getEntities(entity, entity.boundingBox.inflate(6.0))) { if (target !is LivingEntity) { continue } @@ -134,13 +141,13 @@ class MagicLightningBolt(entityType: EntityType, level: Leve } PURPLE -> { - entity.damage(damageSource, 5F) - world.createExplosion(entity, damageSource, damageCalculator, entity.x, entity.y, entity.z, 1.0F, false, World.ExplosionSourceType.MOB) + entity.hurtServer(serverLevel, damageSource, 5F) + level().explode(entity, damageSource, damageCalculator, entity.x, entity.y, entity.z, 1.0F, false, Level.ExplosionInteraction.MOB) // TODO: add status effect } BLACK -> { - entity.kill() + (entity.level() as? ServerLevel)?.let(entity::kill) } } } @@ -165,10 +172,11 @@ class MagicLightningBolt(entityType: EntityType, level: Leve } private fun performOrangeStrike(entity: Entity) { + val level = this.level() as? ServerLevel ?: return if (entity is LivingEntity) { - entity.addStatusEffect(StatusEffectInstance(ARMOR_PENETRATION_EFFECT, 20 * 10, 4)) + entity.addEffect(MobEffectInstance(ArmorPenetration, 20 * 10, 4)) } - entity.damage(damageSource, 5.0F) + entity.hurtServer(level, damageSource(), 5.0F) } override fun recreateFromPacket(packet: ClientboundAddEntityPacket) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt index 116a9f4a..8369dc95 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/entity/ModEntityTypes.kt @@ -17,14 +17,13 @@ import net.minecraft.world.entity.MobCategory object ModEntityTypes { - val MAGIC_LIGHTNING_ENTITY: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("magic_lightning"), - EntityType.Builder.create({ entityType, world -> MagicLightningBolt(entityType, world) }, SpawnGroup.MISC) - .disableSaving() - .dimensions(0.0F, 0.0F) - .maxTrackingRange(16) - .trackingTickInterval(Integer.MAX_VALUE) - .build() + val MAGIC_LIGHTNING_ENTITY: EntityType = register( + "magic_lightning", + EntityType.Builder.of({ entityType, world -> MagicLightningBolt(entityType, world) }, MobCategory.MISC) + .noSave() + .sized(0.0F, 0.0F) + .clientTrackingRange(16) + .updateInterval(Integer.MAX_VALUE) ) val attractor = register( @@ -37,23 +36,21 @@ object ModEntityTypes { .updateInterval(10) ) - val FINDER_ARROW_ENTITY: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("finder_arrow"), - EntityType.Builder.create({ entityType, world -> FinderArrowEntity(world) }, SpawnGroup.MISC) - .dimensions(0.5F, 0.5F) + val FINDER_ARROW_ENTITY: EntityType = register( + "finder_arrow", + EntityType.Builder.of({ entityType, world -> FinderArrowEntity(world) }, MobCategory.MISC) + .sized(0.5F, 0.5F) .eyeHeight(0.13F) - .maxTrackingRange(4) - .trackingTickInterval(20) - .build() + .clientTrackingRange(4) + .updateInterval(20) ) - val devEntity: EntityType = Registry.register( - Registries.ENTITY_TYPE, Matrix.identifier("dev"), - EntityType.Builder.create({ entityType, world -> DevEntity(world) }, SpawnGroup.CREATURE) - .dimensions(0.6f, 1.95f) + val devEntity: EntityType = register( + "dev", + EntityType.Builder.of({ entityType, world -> DevEntity(world) }, MobCategory.CREATURE) + .sized(0.6f, 1.95f) .eyeHeight(1.74F) - .maxTrackingRange(8) - .build() + .clientTrackingRange(8) ) private fun register(name: String, builder: EntityType.Builder): EntityType { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt index e4b272f4..d5113def 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalAxeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.AxeItem object CoalAxeItem : AxeItem( ModToolMaterials.coal, 6.5F, -3.15F, - Properties() + Properties().setId(ModItemIds.coalAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt index 4abf3089..bf02b523 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalBootsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.BOOTS) + Properties().setId(ModItemIds.coalBoots).humanoidArmor(ModArmorMaterials.coal, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt index 67956244..b1fcd06f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalChestplateItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.CHESTPLATE) + Properties().setId(ModItemIds.coalChestplate).humanoidArmor(ModArmorMaterials.coal, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt index 01c7447e..4703c4a7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHelmetItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object CoalHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.HELMET) + Properties().setId(ModItemIds.coalHelmet).humanoidArmor(ModArmorMaterials.coal, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt index 815757f4..32e08971 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalHoeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.HoeItem object CoalHoeItem : HoeItem( ModToolMaterials.coal, -1.5F, -1.0F, - Properties() + Properties().setId(ModItemIds.coalHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt index 4f4cc246..a93c1f69 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalLeggingsItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.ToolMaterial import net.minecraft.world.item.equipment.ArmorType object CoalLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.coal, ArmorType.LEGGINGS) + Properties().setId(ModItemIds.coalLeggings).humanoidArmor(ModArmorMaterials.coal, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt index 4d3ec29f..afbdd64d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalPickaxeItem.kt @@ -5,8 +5,9 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item object CoalPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.coal, 1.0F, -2.8F) + Properties().setId(ModItemIds.coalPickaxe).pickaxe(ModToolMaterials.coal, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt index cc3b2a77..6fb8d4bf 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalShovelItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.ShovelItem object CoalShovelItem : ShovelItem( ModToolMaterials.coal, 1.5F, -3.0F, - Properties() + Properties().setId(ModItemIds.coalShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt index 490a3de2..917bfcce 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/CoalSwordItem.kt @@ -5,8 +5,9 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item object CoalSwordItem : Item( - Properties().sword(ModToolMaterials.coal,3.0F, -2.4F) + Properties().setId(ModItemIds.coalSword).sword(ModToolMaterials.coal,3.0F, -2.4F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt index 601e12c4..61f04e78 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldAxeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.AxeItem object EmeraldAxeItem : AxeItem( ModToolMaterials.emerald, 5.0F, -3.0F, - Properties() + Properties().setId(ModItemIds.emeraldAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt index 8cfd9908..3690d0fc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldBootsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.BOOTS) + Properties().setId(ModItemIds.emeraldBoots).humanoidArmor(ModArmorMaterials.emerald, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt index 071eb868..8fb04fa6 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldChestplateItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.CHESTPLATE) + Properties().setId(ModItemIds.emeraldChestplate).humanoidArmor(ModArmorMaterials.emerald, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt index ce915eff..da09dfdd 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHelmetItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.HELMET) + Properties().setId(ModItemIds.emeraldHelmet).humanoidArmor(ModArmorMaterials.emerald, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt index d81c73d7..5858a2d7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldHoeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.HoeItem object EmeraldHoeItem : HoeItem( ModToolMaterials.emerald, -3.5F, 0.0F, - Properties() + Properties().setId(ModItemIds.emeraldHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt index fc18ac82..936d8791 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldLeggingsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object EmeraldLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.emerald, ArmorType.LEGGINGS) + Properties().setId(ModItemIds.emeraldLeggings).humanoidArmor(ModArmorMaterials.emerald, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt index af2686ca..2266d7eb 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldPickaxeItem.kt @@ -5,8 +5,9 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item object EmeraldPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.emerald, 1.0F, -2.8F) + Properties().setId(ModItemIds.emeraldPickaxe).pickaxe(ModToolMaterials.emerald, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt index e67aa1e9..458224e7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldShovelItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.ShovelItem object EmeraldShovelItem : ShovelItem( ModToolMaterials.emerald, 1.5F, -3.0F, - Properties() + Properties().setId(ModItemIds.emeraldShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt index d958a0c2..8443697b 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/EmeraldSwordItem.kt @@ -5,8 +5,9 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item object EmeraldSwordItem : Item( - Properties().sword(ModToolMaterials.emerald,3.0F, -2.4F) + Properties().setId(ModItemIds.emeraldSword).sword(ModToolMaterials.emerald,3.0F, -2.4F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt index 63726808..09d6b865 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/FinderArrowItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.entity.FinderArrowEntity import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.projectile.arrow.AbstractArrow @@ -12,7 +13,7 @@ import net.minecraft.world.item.ArrowItem import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level -object FinderArrowItem : ArrowItem(Properties()) { +object FinderArrowItem : ArrowItem(Properties().setId(ModItemIds.finderArrow)) { override fun createArrow(level: Level, itemStack: ItemStack, owner: LivingEntity, firedFromWeapon: ItemStack?): AbstractArrow { return FinderArrowEntity(level, owner, itemStack.copyWithCount(1), firedFromWeapon) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt index 815d4e23..ddf5aa24 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliAxeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.AxeItem object LapisLazuliAxeItem : AxeItem( ModToolMaterials.lapisLazuli, 6.0F, -3.0F, - Properties() + Properties().setId(ModItemIds.lapisLazuliAxe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt index ea037bde..1989b5b0 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliBootsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.BOOTS) + Properties().setId(ModItemIds.lapisLazuliBoots).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt index efa7c9d6..e96c4602 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliChestplateItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.ToolMaterial import net.minecraft.world.item.equipment.ArmorType object LapisLazuliChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.CHESTPLATE) + Properties().setId(ModItemIds.lapisLazuliChestplate).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt index 50eb0537..6610010c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHelmetItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.HELMET) + Properties().setId(ModItemIds.lapisLazuliHelmet).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt index eb02a1aa..88baa328 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliHoeItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.HoeItem object LapisLazuliHoeItem : HoeItem( ModToolMaterials.lapisLazuli, -2.0F, -1.0F, - Properties() + Properties().setId(ModItemIds.lapisLazuliHoe) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt index a44e7e80..58c4f8d7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliLeggingsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object LapisLazuliLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.LEGGINGS) + Properties().setId(ModItemIds.lapisLazuliLeggings).humanoidArmor(ModArmorMaterials.lapisLazuli, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt index 6c6b1002..d20e24ba 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliPickaxeItem.kt @@ -5,8 +5,9 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item object LapisLazuliPickaxeItem : Item( - Properties().pickaxe(ModToolMaterials.lapisLazuli, 1.0F, -2.8F) + Properties().setId(ModItemIds.lapisLazuliPickaxe).pickaxe(ModToolMaterials.lapisLazuli, 1.0F, -2.8F) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt index df8f5a5a..bd05854c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliShovelItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.ShovelItem object LapisLazuliShovelItem : ShovelItem( ModToolMaterials.lapisLazuli, 1.5F, -3.0F, - Properties() + Properties().setId(ModItemIds.lapisLazuliShovel) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt index 13ecfe84..f475ad10 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LapisLazuliSwordItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.ExecutionPolicy import heckerpowered.matrix.common.magic.channel.MagicInvocation @@ -15,7 +16,7 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack object LapisLazuliSwordItem : Item( - Properties().sword(ModToolMaterials.lapisLazuli, 3.0F, -2.4F) + Properties().setId(ModItemIds.lapisLazuliSword).sword(ModToolMaterials.lapisLazuli, 3.0F, -2.4F) ) { override fun postHurtEnemy(itemStack: ItemStack, mob: LivingEntity, attacker: LivingEntity) { super.postHurtEnemy(itemStack, mob, attacker) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt index 0bf65651..32356ed0 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/LightningChestplate1.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.entity.rule.AttributeComputationContext import heckerpowered.matrix.common.entity.rule.AttributeComputationRule import heckerpowered.matrix.common.entity.rule.LivingDeathContext @@ -38,7 +39,7 @@ import java.util.function.Consumer * Lightning Chestplate 1 'Warp Dancer' */ object LightningChestplate1 : Item( - Properties() + Properties().setId(ModItemIds.lightningChestplateBorrowedTime) .humanoidArmor(ModArmorMaterials.lightning, ArmorType.CHESTPLATE) .fireResistant() .rarity(Rarity.EPIC) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt index abdfe368..184c2b90 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/MagicTalismanItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.rule.RuleRegistry @@ -14,7 +15,7 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.Rarity object MagicTalismanItem : Item( - Properties() + Properties().setId(ModItemIds.magicTalisman) .fireResistant() .stacksTo(1) .rarity(Rarity.EPIC) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/MatrixPotions.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/MatrixPotions.kt index 4ce92aa7..286478a3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/MatrixPotions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/MatrixPotions.kt @@ -6,7 +6,7 @@ package heckerpowered.matrix.common.item import heckerpowered.matrix.Matrix -import heckerpowered.matrix.common.effect.ModMobEffects.ANGERED_EFFECT +import heckerpowered.matrix.common.effect.ModMobEffects.Angered import net.fabricmc.fabric.api.registry.FabricPotionBrewingBuilder import net.minecraft.core.Holder import net.minecraft.core.Registry @@ -18,7 +18,7 @@ import net.minecraft.world.item.alchemy.Potions object MatrixPotions { - val angeredPotion = register("angered", MobEffectInstance(ANGERED_EFFECT, 20 * 30)) + val angeredPotion = register("angered", MobEffectInstance(Angered, 20 * 30)) private fun register(@Suppress("SameParameterValue") name: String, vararg effects: MobEffectInstance): Holder { val identifier = Matrix.identifier(name) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt index a480d84c..06623b64 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/MetaBowItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.shootPerMinute import heckerpowered.matrix.core.utility.FixedRateRepeater import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents @@ -21,7 +22,7 @@ import net.minecraft.world.level.Level import kotlin.time.Duration.Companion.minutes object MetaBowItem : BowItem( - Properties() + Properties().setId(ModItemIds.metaBow) .durability(3840) .component(shootPerMinute, 3600) ) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt index d44451b0..f5fea61a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneAxeItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower import heckerpowered.matrix.common.item.ModComponents.redstoneSuitPower import heckerpowered.matrix.data.language.MatrixLanguage @@ -24,7 +25,7 @@ import java.util.function.Consumer object RedstoneAxeItem : AxeItem( ModToolMaterials.redstone, 5.0F, -3.0F, - Properties() + Properties().setId(ModItemIds.redstoneAxe) .component(redstoneSuitPower, 20) .component(redstoneSuitMaxPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt index c2d1b77d..81d78e25 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneBootsItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower import heckerpowered.matrix.common.item.ModComponents.redstoneSuitPower import heckerpowered.matrix.data.language.MatrixLanguage @@ -18,7 +19,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.BOOTS) + Properties().setId(ModItemIds.redstoneBoots).humanoidArmor(ModArmorMaterials.redstone, ArmorType.BOOTS) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt index ccfe0cfd..cfb833ea 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneChestplateItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageSettlementContext import heckerpowered.matrix.common.combat.damage.DamageSettlementRule import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower @@ -24,7 +25,7 @@ import java.util.function.Consumer import kotlin.math.ceil object RedstoneChestplateItem : Item( - Properties() + Properties().setId(ModItemIds.redstoneChestplate) .humanoidArmor(ModArmorMaterials.redstone, ArmorType.CHESTPLATE) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt index 23c4f3cf..2ec631f7 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHelmetItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.entity.rule.EntityUpdateContext import heckerpowered.matrix.common.entity.rule.EntityUpdateRule import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower @@ -25,7 +26,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.HELMET) + Properties().setId(ModItemIds.redstoneHelmet).humanoidArmor(ModArmorMaterials.redstone, ArmorType.HELMET) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), EntityUpdateRule, RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt index a26ed39c..c3ecb6d9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneHoeItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower import heckerpowered.matrix.common.item.ModComponents.redstoneSuitPower import heckerpowered.matrix.data.language.MatrixLanguage @@ -23,7 +24,7 @@ import java.util.function.Consumer object RedstoneHoeItem : HoeItem( ModToolMaterials.redstone, -2.0F, -1.0F, - Properties() + Properties().setId(ModItemIds.redstoneHoe) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt index e9ea01d5..091faf4c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneLeggingsItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageOutcomeContext import heckerpowered.matrix.common.combat.damage.DamageOutcomeRule import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower @@ -27,7 +28,7 @@ import net.minecraft.world.item.equipment.ArmorType import java.util.function.Consumer object RedstoneLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.redstone, ArmorType.LEGGINGS) + Properties().setId(ModItemIds.redstoneLeggings).humanoidArmor(ModArmorMaterials.redstone, ArmorType.LEGGINGS) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider, DamageOutcomeRule { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt index 3e478507..f1c272fc 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstonePickaxeItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower import heckerpowered.matrix.common.item.ModComponents.redstoneSuitPower import heckerpowered.matrix.data.language.MatrixLanguage @@ -22,7 +23,7 @@ import net.minecraft.world.level.block.state.BlockState import java.util.function.Consumer object RedstonePickaxeItem : Item( - Properties() + Properties().setId(ModItemIds.redstonePickaxe) .pickaxe(ModToolMaterials.redstone, 1.0F, -2.8F) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt index 2e963975..2b8befa6 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneShovelItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.item.ModComponents.redstoneSuitMaxPower import heckerpowered.matrix.common.item.ModComponents.redstoneSuitPower import heckerpowered.matrix.data.language.MatrixLanguage @@ -23,7 +24,7 @@ import java.util.function.Consumer object RedstoneShovelItem : ShovelItem( ModToolMaterials.redstone, 1.5F, -3.0F, - Properties() + Properties().setId(ModItemIds.redstoneShovel) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) ), RedstoneSuit, TooltipProvider { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt index f86fa04f..17c665b3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/RedstoneSwordItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attackerAsLiving @@ -23,7 +24,7 @@ import net.minecraft.world.item.component.TooltipProvider import java.util.function.Consumer object RedstoneSwordItem : Item( - Properties() + Properties().setId(ModItemIds.redstoneSword) .sword(ModToolMaterials.redstone, 3.0F, -2.4F) .component(redstoneSuitMaxPower, 20) .component(redstoneSuitPower, 0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt index c776d9ff..a69d4e31 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneBootsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneBootsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.BOOTS) + Properties().setId(ModItemIds.stoneBoots).humanoidArmor(ModArmorMaterials.stone, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt index 88e3220a..43d5df67 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneChestplateItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.CHESTPLATE) + Properties().setId(ModItemIds.stoneChestplate).humanoidArmor(ModArmorMaterials.stone, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt index 2f94dd68..6e59e099 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneHelmetItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneHelmetItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.HELMET) + Properties().setId(ModItemIds.stoneHelmet).humanoidArmor(ModArmorMaterials.stone, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt index b1cf30f4..41c81baa 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/StoneLeggingsItem.kt @@ -5,9 +5,10 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object StoneLeggingsItem : Item( - Properties().humanoidArmor(ModArmorMaterials.stone, ArmorType.LEGGINGS) + Properties().setId(ModItemIds.stoneLeggings).humanoidArmor(ModArmorMaterials.stone, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt index 6a8b918a..17d98921 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WardenChestplateItem.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attackerAsLiving @@ -28,7 +29,7 @@ import java.util.function.Consumer // TODO: EntityPolarity // TODO: Restrict negative effects object WardenChestplateItem : Item( - Properties().humanoidArmor(ModArmorMaterials.warden, ArmorType.CHESTPLATE) + Properties().setId(ModItemIds.wardenChestplate).humanoidArmor(ModArmorMaterials.warden, ArmorType.CHESTPLATE) .fireResistant() .rarity(Rarity.EPIC) ), TooltipProvider, DamageComputationRule, KnockbackRule { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt index 4143d3ff..d88ba59f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet.kt @@ -98,9 +98,7 @@ open class WizardHelmet(properties: Properties) : Item( val sink = MaxManaCalculationSink(maxMana = defaultMaxMana) CalculationPipeline.apply(context, sink) - val maxMana = sink.maxMana - val multiplier = sink.multiplier - return maxMana * multiplier + return sink.maxMana * sink.multiplier } protected open fun overloadBreakChancePerSecond(extraLoad: Double): Double { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt index bea99769..cf516fca 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet1.kt @@ -5,13 +5,14 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Rarity /** * Wizard Helmet 1 'Basic' */ object WizardHelmet1 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet1) .rarity(Rarity.COMMON) .maxMana(8.0) .maxLoad(105.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt index 389c89d7..b53eed09 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet10.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageSettlementContext import heckerpowered.matrix.common.combat.damage.DamageSettlementRule import heckerpowered.matrix.common.network.ClientboundSyncHealthPayload @@ -22,7 +23,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity object WizardHelmet10 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet10) .fireResistant() .rarity(Rarity.EPIC) .maxMana(12.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt index adee2cd4..b6e664cd 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet13.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attacker @@ -41,7 +42,7 @@ import kotlin.math.floor * Wizard Helmet 13 'Overflux Crown' */ object WizardHelmet13 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet13) .fireResistant() .rarity(Rarity.EPIC) .maxMana(12.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt index a28fe887..97731a34 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet2.kt @@ -5,13 +5,14 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Rarity /** * Wizard Helmet 2 'Ruin' */ object WizardHelmet2 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet2) .rarity(Rarity.COMMON) .maxMana(9.0) .maxLoad(110.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt index 327dbe29..92aee5e8 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet3.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attacker @@ -19,7 +20,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 3 'Blood-forged Ruin' */ object WizardHelmet3 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet3) .rarity(Rarity.UNCOMMON) .maxMana(10.0) .maxLoad(200.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt index 9e47e3b0..12a01697 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet4.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attacker @@ -19,7 +20,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 4 'Might and Method' */ object WizardHelmet4 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet4) .rarity(Rarity.RARE) .maxMana(11.0) .maxLoad(120.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt index aa1773e4..18d9d59d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmet5.kt @@ -5,6 +5,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.combat.damage.DamageComputationContext import heckerpowered.matrix.common.combat.damage.DamageComputationRule import heckerpowered.matrix.common.combat.damage.attacker @@ -24,7 +25,7 @@ import net.minecraft.world.item.Rarity * Wizard Helmet 5 'Axiom of Annihilation' */ object WizardHelmet5 : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmet5) .rarity(Rarity.EPIC) .maxMana(12.0) .maxLoad(125.0) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt index e42943e2..ed1436a3 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WizardHelmetHacker.kt @@ -6,6 +6,7 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import heckerpowered.matrix.common.magic.core.Magic import heckerpowered.matrix.common.magic.system.Magics import net.minecraft.world.entity.player.Player @@ -13,8 +14,12 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity object WizardHelmetHacker : WizardHelmet( - Properties() + Properties().setId(ModItemIds.wizardHelmetHacker) .rarity(Rarity.EPIC) + // The pre-refactor mana system gave every player a helmet-independent 100-point pool; + // the ledger refactor made max mana helmet-derived but never assigned this dev helmet + // a capacity, leaving it at 0/0. 100 mirrors the old pool base. + .maxMana(100.0) ) { override fun getMagics(player: Player, itemStack: ItemStack): Sequence { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt index 5a0a2ec8..86218c19 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenBootsItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenBootsItem : Item( - Properties() + Properties().setId(ModItemIds.woodenBoots) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.BOOTS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt index 4f7c01d5..0bfb3b26 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenChestplateItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenChestplateItem : Item( - Properties() + Properties().setId(ModItemIds.woodenChestplate) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.CHESTPLATE) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt index 70ab7e04..ffcb0c07 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenHelmetItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenHelmetItem : Item( - Properties() + Properties().setId(ModItemIds.woodenHelmet) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.HELMET) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt index 2e8dfc9e..542f3236 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/item/WoodenLeggingsItem.kt @@ -5,10 +5,11 @@ package heckerpowered.matrix.common.item +import heckerpowered.matrix.common.reference.ModItemIds import net.minecraft.world.item.Item import net.minecraft.world.item.equipment.ArmorType object WoodenLeggingsItem : Item( - Properties() + Properties().setId(ModItemIds.woodenLeggings) .humanoidArmor(ModArmorMaterials.wooden, ArmorType.LEGGINGS) ) \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt index 183f5e65..fe00038e 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/channel/ChannelExecutor.kt @@ -70,6 +70,6 @@ object ChannelExecutor { it.initialProgressOffset = Minecraft.getInstance().deltaTracker.getGameTimeDeltaPartialTick(true) }) ChannelSequenceRenderer.offsetAnimationMap - .computeIfAbsent(target) { ChannelSequenceRenderer.Companion.OffsetAnimation() } + .computeIfAbsent(target) { ChannelSequenceRenderer.OffsetAnimation() } } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt index dc769599..955a71da 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/core/Magic.kt @@ -16,6 +16,7 @@ import heckerpowered.matrix.common.magic.rule.calculation.sink.CostCalculationSi import heckerpowered.matrix.common.magic.rule.effect.MagicCastPipeline import heckerpowered.matrix.common.magic.rule.effect.MagicChannelPipeline import heckerpowered.matrix.common.magic.rule.resource.CastingResourcePipeline +import heckerpowered.matrix.core.isInfiniteMana import heckerpowered.matrix.common.persistent.queueSize import net.minecraft.core.Holder import net.minecraft.world.Difficulty @@ -178,6 +179,12 @@ abstract class Magic(val definition: MagicDefinition) { * @return true if the required cost can be satisfied; false otherwise. */ protected open fun checkMana(context: MagicCalculationContext): Boolean { + // Infinite mana (/matrix mana infinite, operator-gated) bypasses the affordability + // gate entirely; ExecutionPolicy.payCost already skips the actual payment, this was + // the missing half that still reported InsufficientMana. + if (context.playerOrNull()?.isInfiniteMana == true) { + return true + } val requiredCost = getCost(context).mana val resourceSet = CastingResourcePipeline.collect(context) return resourceSet.canAfford(context, requiredCost) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt index 5a05148a..757f22d4 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/AttractMagic.kt @@ -28,7 +28,7 @@ object AttractMagic : Magic( val caster = invocation.caster.entityOrNull() target.level().addFreshEntity(AttractorEntity(target.level()).also { it.setPos(target.position()) - it.owner = caster + it.setOwner(caster) }) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/DecisiveStrikeMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/DecisiveStrikeMagic.kt index 43e8a1bb..23e731b9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/DecisiveStrikeMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/DecisiveStrikeMagic.kt @@ -18,6 +18,7 @@ import heckerpowered.matrix.common.magic.system.GameTick.Companion.ticks import heckerpowered.matrix.common.persistent.mana import heckerpowered.matrix.common.persistent.maxMana import heckerpowered.matrix.core.extension.damage +import heckerpowered.matrix.mixin.EntityInvoker import net.minecraft.world.entity.ai.attributes.Attributes object DecisiveStrikeMagic : Magic( @@ -68,7 +69,7 @@ object DecisiveStrikeMagic : Magic( val target = context.target val damageSource = context.defaultMagicDamageSource() - if (target?.isInvulnerable == true || target?.isInvulnerableToBase(damageSource) == true) { + if (target?.isInvulnerable == true || (target as? EntityInvoker)?.`matrix$isInvulnerableToBase`(damageSource) == true) { availability += MagicAvailableStatus.TargetImmune } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/ExplosionMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/ExplosionMagic.kt index e194c9d8..ef44c83f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/ExplosionMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/ExplosionMagic.kt @@ -17,6 +17,8 @@ import heckerpowered.matrix.common.magic.core.SpellRank.CHIMERA import heckerpowered.matrix.common.magic.core.targetRank import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana import heckerpowered.matrix.common.magic.system.GameTick.Companion.ticks +import heckerpowered.matrix.common.persistent.magicClock +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.level.Level import net.minecraft.world.level.SimpleExplosionDamageCalculator import java.util.* @@ -42,7 +44,10 @@ object ExplosionMagic : Magic( val target = invocation.target val damageSource = invocation.defaultMagicDamageSource() - target.level().explode(caster, damageSource, damageCalculator, target.x, target.y, target.z, 4.0F, false, Level.ExplosionInteraction.MOB) + // Pre-migration jar: explosion power is the caster's magic overclock rate (HUD N key, + // 1.0 when absent or not a player) times the 4.0 base. + val power = ((caster as? ServerPlayer)?.magicClock ?: 1.0) * 4.0 + target.level().explode(caster, damageSource, damageCalculator, target.x, target.y, target.z, power.toFloat(), false, Level.ExplosionInteraction.MOB) } override fun getBaseChannelTime(context: MagicCalculationContext): Long { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/MemoryWipeMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/MemoryWipeMagic.kt index b0b586c3..b798878c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/MemoryWipeMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/MemoryWipeMagic.kt @@ -14,6 +14,9 @@ import heckerpowered.matrix.common.magic.rule.effect.ChannelEffect import heckerpowered.matrix.common.magic.system.GameTick.Companion.ticks import heckerpowered.matrix.common.rule.RuleRegistry import heckerpowered.matrix.common.rule.register +import heckerpowered.matrix.mixin.BrainAccessor +import heckerpowered.matrix.mixin.LivingEntityAccessor +import heckerpowered.matrix.mixin.MobAccessor import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.Mob import net.minecraft.world.entity.NeutralMob @@ -86,12 +89,12 @@ object MemoryWipeMagic : Magic( val target = invocation.target val caster = invocation.caster.asPlayerOrNull() - target.brain.memories + (target.brain as BrainAccessor).`matrix$getMemories`() .filter { it.key !in MEMORY_WIPE_PRESERVED_MEMORIES } .forEach { it.value.clear() } if (target is Mob) { target.target = null - target.targetSelector.availableGoals + (target as MobAccessor).`matrix$getTargetSelector`().availableGoals .map { it.goal } .forEach { it.stop() } } @@ -100,8 +103,10 @@ object MemoryWipeMagic : Magic( target.stopBeingAngry() } target.lastHurtByMob = null - target.lastHurtByPlayer = null - target.lastHurtByPlayerMemoryTime = 0 + (target as LivingEntityAccessor).apply { + `matrix$setLastHurtByPlayer`(null) + `matrix$setLastHurtByPlayerMemoryTime`(0) + } if (caster == null) return if (target is Villager) { @@ -115,15 +120,17 @@ object MemoryWipeMagic : Magic( brain.clearMemories() if (this is Mob) { target = null - targetSelector.availableGoals + (this as MobAccessor).`matrix$getTargetSelector`().availableGoals .map { it.goal } .forEach { it.stop() } } if (this is NeutralMob) { stopBeingAngry() } - lastHurtByPlayer = null - lastHurtByPlayerMemoryTime = 0 + (this as LivingEntityAccessor).apply { + `matrix$setLastHurtByPlayer`(null) + `matrix$setLastHurtByPlayerMemoryTime`(0) + } lastHurtByMob = null } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TeleportMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TeleportMagic.kt index 474a6a0a..d88a970c 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TeleportMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TeleportMagic.kt @@ -14,6 +14,7 @@ import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana import heckerpowered.matrix.common.magic.system.GameTick.Companion.ticks import heckerpowered.matrix.core.utility.getOtherEntities import heckerpowered.matrix.core.utility.withinDistance +import heckerpowered.matrix.mixin.LivingEntityAccessor import net.minecraft.world.entity.player.Player object TeleportMagic : Magic( @@ -36,7 +37,7 @@ object TeleportMagic : Magic( .filter { it != caster } .forEach { it.invulnerableTime = 0 - caster.attackStrengthTicker = Int.MAX_VALUE + (caster as LivingEntityAccessor).`matrix$setAttackStrengthTicker`(Int.MAX_VALUE) if (caster is Player) { caster.attack(it) caster.crit(it) diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TuckInMagic.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TuckInMagic.kt index 9f1def18..52b9e325 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TuckInMagic.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/spell/TuckInMagic.kt @@ -14,6 +14,7 @@ import heckerpowered.matrix.common.magic.core.MagicDefinition import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana import heckerpowered.matrix.common.magic.system.GameTick.Companion.ticks import heckerpowered.matrix.core.extension.damage +import heckerpowered.matrix.mixin.LivingEntityAccessor import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.attributes.Attributes @@ -57,7 +58,7 @@ object TuckInMagic : Magic( private fun consumeFromAbsorptionThenHealth(caster: LivingEntity, consumptionAmount: Double) { val currentAbsorptionAmount = caster.absorptionAmount.toDouble() val absorptionConsumptionAmount = consumptionAmount.coerceAtMost(currentAbsorptionAmount) - caster.internalSetAbsorptionAmount((currentAbsorptionAmount - absorptionConsumptionAmount).toFloat()) + (caster as LivingEntityAccessor).`matrix$internalSetAbsorptionAmount`((currentAbsorptionAmount - absorptionConsumptionAmount).toFloat()) val remainingConsumptionAmount = consumptionAmount - absorptionConsumptionAmount if (remainingConsumptionAmount <= 0.0) return diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt index fab10e8b..071ff099 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/MagicSystem.kt @@ -13,9 +13,13 @@ import net.minecraft.world.entity.LivingEntity object MagicSystem { fun onInitialize() { + // Registers the built-in magics; nothing invoked this before, leaving the magic + // registry empty at runtime (no HUD, no magic enchantments in datagen). + Magics.onInitialize() ChannelQueuePersistenceRule.onInitialize() ChannelQueueTicker.onInitialize() ManaRegenerationTicker.onInitialize() + ManaOverclockRule.onInitialize() } @JvmStatic diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/Magics.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/Magics.kt index 74c50166..f0bc9c9a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/Magics.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/Magics.kt @@ -54,7 +54,16 @@ object Magics : Iterable { registerMagic(TuckInMagic) } + private var initialized = false + + // Idempotent: invoked from mod initialization (MagicSystem) and defensively from datagen, + // which needs the registry populated for the per-magic enchantment loop in + // ModEnchantmentGenerator regardless of entrypoint ordering. fun onInitialize() { + if (initialized) { + return + } + initialized = true registerBuiltinMagics() } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt index 88bc6b0f..76b4e530 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaLedger.kt @@ -36,6 +36,12 @@ object ManaLedger { private fun transferMana(from: LedgerAccount, to: LedgerAccount, amount: Mana): TransactionResult { val ledgerAmount = amount.toLedgerUnits() + if (ledgerAmount <= 0) { + // The ledger contract rejects non-positive transfers; issuing/extinguishing zero + // mana (e.g. proportional issuance for a player without a wizard helmet, whose + // max mana is 0) is a no-op, not an error. + return TransactionResult.Approved + } return from.postTransfer(to, ledgerAmount) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaOverclockRule.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaOverclockRule.kt new file mode 100644 index 00000000..07aaedd9 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaOverclockRule.kt @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.magic.system + +import heckerpowered.matrix.common.magic.core.MagicCalculationContext +import heckerpowered.matrix.common.magic.rule.calculation.contributor.CalculationContributor +import heckerpowered.matrix.common.magic.rule.calculation.sink.CalculationSink +import heckerpowered.matrix.common.magic.rule.calculation.sink.MaxManaCalculationSink +import heckerpowered.matrix.common.persistent.manaClock +import heckerpowered.matrix.common.rule.RuleRegistry +import heckerpowered.matrix.common.rule.register +import net.minecraft.server.level.ServerPlayer + +/** + * Applies the player's mana overclock rate (HUD M key, persisted in + * [heckerpowered.matrix.common.persistent.OverclockState]) to max-mana calculation. + * + * Pre-migration behavior contract: the overclock handler wrote `maxMana += delta * 100` on a + * 100-base persistent pool, i.e. `maxMana = base * rate`. Max mana is a derived value in the + * ledger system (recomputed from the worn helmet every tick), so the same observable scaling + * is contributed here as a multiplier instead of a one-shot write; mana above the shrunk + * bound is clamped by the account's transaction constraints exactly like the old handler's + * explicit clamp, and the regeneration ticker syncs the result to the HUD. + */ +object ManaOverclockRule : CalculationContributor { + fun onInitialize() { + RuleRegistry.register(this) + } + + override fun contribute(context: MagicCalculationContext, sink: CalculationSink) { + if (sink !is MaxManaCalculationSink) return + val player = context.playerOrNull() as? ServerPlayer ?: return + sink.multiplier *= player.manaClock + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt index 7002c186..f28cc310 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/magic/system/ManaRegenerationTicker.kt @@ -39,6 +39,7 @@ object ManaRegenerationTicker { val account = ManaLedger.account(player) if (player.isInfiniteMana) { val maximum = account.incomingRemainingUnits() ?: return + if (maximum <= 0) return ManaLedger.Authority.postTransfer(account, maximum) return } @@ -48,10 +49,11 @@ object ManaRegenerationTicker { CalculationPipeline.apply(context, sink) val regenerationAmount = (sink.regeneration * sink.multiplier).mana.toLedgerUnits() - ManaLedger.Authority.postTransfer( - account, - regenerationAmount.coerceTransferUnits(ManaLedger.Authority, account) - ) + val transferAmount = regenerationAmount.coerceTransferUnits(ManaLedger.Authority, account) + // A player without a wizard helmet has zero max mana; a zero regeneration tick is a + // no-op, not a ledger error (the ledger contract rejects non-positive transfers). + if (transferAmount <= 0) return + ManaLedger.Authority.postTransfer(account, transferAmount) } private fun syncMana(player: ServerPlayer) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt index 1c9d17d9..59bc35d6 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundChannelMagicPayload.kt @@ -12,7 +12,7 @@ import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.ChannelQueue.Companion.getOrCreateChannelQueue import heckerpowered.matrix.common.magic.channel.MagicInvocation import heckerpowered.matrix.common.magic.core.MagicCalculationContext -import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.magic.system.Magics import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking.Context import net.minecraft.core.UUIDUtil import net.minecraft.network.codec.ByteBufCodecs @@ -45,7 +45,7 @@ class ClientboundChannelMagicPayload( fun handle(context: Context) { context.client().execute { - val magic = MagicSystem.getMagicByUuid(magicUuid) ?: return@execute + val magic = Magics[magicUuid] ?: return@execute val player = context.player() val entity = player.level().getEntity(entityId) ?: return@execute if (entity !is LivingEntity) { diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundExplosionPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundExplosionPayload.kt index 7272c59c..c4ad0121 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundExplosionPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ClientboundExplosionPayload.kt @@ -6,7 +6,8 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix -import heckerpowered.matrix.client.render.particle.system.ExplosionParticle +// GPU particle system retired (see common/attic) +// import heckerpowered.matrix.client.render.particle.system.ExplosionParticle import heckerpowered.matrix.client.render.post.CameraShake import heckerpowered.matrix.client.render.post.ShockwaveRenderer import net.fabricmc.api.EnvType @@ -54,7 +55,8 @@ class ClientboundExplosionPayload( CameraShake.shake(strength = 1F, duration = 100.milliseconds) - ExplosionParticle.randomVelocityModule.speedRange = Vector2f(0.0F, 20.0F) - ExplosionParticle.spawnParticleAt(entity.position()) + // GPU particle system retired (see common/attic) + // ExplosionParticle.randomVelocityModule.speedRange = Vector2f(0.0F, 20.0F) + // ExplosionParticle.spawnParticleAt(entity.position()) } } \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundActivateBloodPactPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundActivateBloodPactPayload.kt index f0f8a59f..7b2d97f8 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundActivateBloodPactPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundActivateBloodPactPayload.kt @@ -6,8 +6,8 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix -import heckerpowered.matrix.common.effect.ModMobEffects.BLOOD_PACT_EFFECT -import heckerpowered.matrix.common.enchantment.ModEnchantments.bloodPact +import heckerpowered.matrix.common.effect.ModMobEffects.BloodPact +import heckerpowered.matrix.common.enchantment.ModEnchantments import heckerpowered.matrix.common.enchantment.getEnchantmentLevel import heckerpowered.matrix.common.persistent.wizardHelmet import heckerpowered.matrix.common.persistent.wizardHelmetStack @@ -31,13 +31,13 @@ data object ServerboundActivateBloodPactPayload : CustomPacketPayload { fun handle(@Suppress("unused") payload: ServerboundActivateBloodPactPayload, context: Context) { val player = context.player() val level = player.level() - if (player.wizardHelmetStack.getEnchantmentLevel(level, bloodPact) <= 0) return - if (player.hasEffect(BLOOD_PACT_EFFECT) || player.cooldowns.isOnCooldown(player.wizardHelmetStack)) { + if (player.wizardHelmetStack.getEnchantmentLevel(level, ModEnchantments.BloodPact) <= 0) return + if (player.hasEffect(BloodPact) || player.cooldowns.isOnCooldown(player.wizardHelmetStack)) { level.playSound(null, player.x, player.y, player.z, SoundEvents.BLAZE_HURT, SoundSource.PLAYERS, 3.0F, 1.0F) return } - player.addEffect(MobEffectInstance(BLOOD_PACT_EFFECT, 20 * 30, 0, false, true)) + player.addEffect(MobEffectInstance(BloodPact, 20 * 30, 0, false, true)) level.playSound(null, player.x, player.y, player.z, SoundEvents.WITHER_SPAWN, SoundSource.PLAYERS, 1.0F, 1.0F) player.cooldowns.addCooldown(player.wizardHelmetStack, 20 * (30 + 14)) // 30 = duration, 14 = cooldown diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt new file mode 100644 index 00000000..1aa47255 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundOverclockPayload.kt @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.network + +import heckerpowered.ledger.transaction.constraint.BoundedTransactionConstraint +import heckerpowered.matrix.Matrix +import heckerpowered.matrix.common.magic.resource.Mana.Companion.mana +import heckerpowered.matrix.common.magic.system.ManaLedger +import heckerpowered.matrix.common.magic.system.ManaLedger.toLedgerUnits +import heckerpowered.matrix.common.persistent.OverclockState +import heckerpowered.matrix.core.mana +import heckerpowered.matrix.core.maxMana +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context +import net.minecraft.network.codec.ByteBufCodecs +import net.minecraft.network.codec.StreamCodec +import net.minecraft.network.protocol.common.custom.CustomPacketPayload + +/** + * Sent by the client HUD (see [heckerpowered.matrix.client.MatrixHud]) whenever the player + * adjusts their mana/magic overclock ratio (N/M keys). + * + * [handle] was restored from the pre-migration jar's `OverclockPayload`: rates are clamped + * to `1.0..10.0` and persisted per player in [OverclockState]. The old handler's follow-up + * effects are owned by the ledger system now — max mana scaling is contributed by + * [heckerpowered.matrix.common.magic.system.ManaOverclockRule] (mana above the shrunk bound + * is clamped by the account's transaction constraints) and the HUD sync happens through the + * regeneration ticker's per-tick `ClientboundSyncManaPayload`. + */ +data class ServerboundOverclockPayload( + private val manaOverclock: Double, + private val magicOverclock: Double, +) : CustomPacketPayload { + companion object { + val payloadId = Matrix.identifier("overclock") + val type = CustomPacketPayload.Type(payloadId) + val codec = StreamCodec.composite( + ByteBufCodecs.DOUBLE, ServerboundOverclockPayload::manaOverclock, + ByteBufCodecs.DOUBLE, ServerboundOverclockPayload::magicOverclock, + ::ServerboundOverclockPayload + ) + } + + override fun type(): CustomPacketPayload.Type { + return type + } + + fun handle(context: Context) { + val player = context.player() + val data = OverclockState.getPlayerState(player) + data.manaOverclock = manaOverclock.coerceIn(1.0, 10.0) + data.magicOverclock = magicOverclock.coerceIn(1.0, 10.0) + + // The pre-migration handler applied the new max mana immediately: it wrote the scaled + // value and clamped mana down to it. The bound lives in the ledger account's + // transaction constraints now and is normally only refreshed on equip, so refresh it + // here with the overclocked max mana and extinguish any mana above the shrunk bound. + val maxMana = player.maxMana + ManaLedger.account(player).transactionConstraints = + setOf(BoundedTransactionConstraint(0, maxMana.toLedgerUnits())) + val excess = player.mana.toDouble() - maxMana.toDouble() + if (excess > 0) { + ManaLedger.extinguishMana(player, excess.mana) + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt index c0521c32..f1412e35 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundUseMagicPayload.kt @@ -8,8 +8,7 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix import heckerpowered.matrix.common.magic.channel.ChannelExecutor import heckerpowered.matrix.common.magic.channel.MagicInvocation -import heckerpowered.matrix.common.magic.core.LMagicAvailableStatus -import heckerpowered.matrix.common.magic.system.MagicSystem +import heckerpowered.matrix.common.magic.system.Magics import heckerpowered.matrix.common.persistent.wizardHelmet import heckerpowered.matrix.common.persistent.wizardHelmetStack import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context @@ -47,14 +46,14 @@ data class ServerboundUseMagicPayload( } val wizardHelmetStack = player.wizardHelmetStack - val magic = MagicSystem.getMagicByUuid(uuid) ?: return - if (player.wizardHelmet?.hasMagic(wizardHelmetStack, magic) != true) { + val magic = Magics[uuid] ?: return + if (player.wizardHelmet?.hasMagic(player, wizardHelmetStack, magic) != true) { return } val invocation = MagicInvocation.fromEntity(player, targetedEntity) val result = ChannelExecutor.channel(magic, invocation) - if (result != LMagicAvailableStatus.AVAILABLE) { + if (!result.isAvailable) { @Suppress("LoggingStringTemplateAsArgument") Matrix.LOGGER.debug("Magic channel failed: $result") } diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt index 2be5e21f..d86b7c57 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/network/ServerboundWarpPayload.kt @@ -6,12 +6,16 @@ package heckerpowered.matrix.common.network import heckerpowered.matrix.Matrix +import heckerpowered.matrix.core.ScheduledExecutor import heckerpowered.matrix.core.ServerTimeRatio import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.Context import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.minecraft.server.dedicated.DedicatedServer +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer +import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds import kotlin.time.DurationUnit @@ -28,6 +32,48 @@ data class ServerboundWarpPayload( ByteBufCodecs.BOOL, ServerboundWarpPayload::playerStandaloneTick, ::ServerboundWarpPayload ) + + @Volatile + private var player: ServerPlayer? = null + + /** + * Pre-migration jar's standalone player tick (borrowed time): a 50ms real-time task + * that keeps the player entity + connection ticking at ~20Hz on the server thread + * while the world runs at the warped rate. Started lazily on first standalone warp, + * never cancelled — old-jar lifecycle verbatim. ServerLevel.tickNonPassenger is the + * 26.2 name of Yarn's ServerWorld.tickEntity; connection.tick() of networkHandler.tick(). + * Packet responsiveness during warped ticks is owned by MinecraftServerMixin's + * waitForTasks hook (16a3466), not by this task. + */ + private val task by lazy { + ScheduledExecutor.schedule(50.milliseconds) { + try { + val current = player ?: return@schedule + val level = current.level() as? ServerLevel ?: return@schedule + val server = level.server + // Self-clean instead of ticking into a dead state: once the server stops, + // submit() runs the lambda INLINE on this pool thread (scheduleExecutables + // is false), which would tick the entity off-thread; a removed or + // disconnected player would leak the whole ServerLevel through the static. + if (server.isStopped || current.isRemoved || current.hasDisconnected()) { + player = null + return@schedule + } + server.submit { + val serverPlayer = player ?: return@submit + if (serverPlayer.isRemoved) { + return@submit + } + (serverPlayer.level() as? ServerLevel)?.tickNonPassenger(serverPlayer) + serverPlayer.connection.tick() + } + } catch (e: Exception) { + // scheduleAtFixedRate cancels the task permanently on any escaped + // throwable — one bad tick must not disable standalone warp for the session. + Matrix.LOGGER.error("standalone warp tick failed: ${e.message}", e) + } + } + } } override fun type(): CustomPacketPayload.Type { @@ -42,6 +88,12 @@ data class ServerboundWarpPayload( val newTickDurationNanos = ((1.seconds.toLong(DurationUnit.NANOSECONDS) / 20L) / timeScale).toLong() ServerTimeRatio(server).tickDuration = newTickDurationNanos.nanoseconds - // TODO: Player standalone tick + // Time slow can be only used in single player mode. + player = if (playerStandaloneTick) { + task + context.player() + } else { + null + } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockData.kt b/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockData.kt new file mode 100644 index 00000000..d27eda54 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockData.kt @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.persistent + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder + +/** + * Per-player overclock rates adjusted from the HUD (N/M keys), both in `1.0..10.0`. + * + * Restored from the pre-migration jar: the mana rate scales the player's max mana and the + * magic rate scales magic strength (currently the explosion power of + * [heckerpowered.matrix.common.magic.spell.ExplosionMagic]). + */ +data class OverclockData( + var manaOverclock: Double = 1.0, + var magicOverclock: Double = 1.0, +) { + companion object { + /** Field names match the pre-migration NBT layout (`ManaOverclock`/`MagicOverclock`). */ + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance.group( + Codec.DOUBLE.optionalFieldOf("ManaOverclock", 1.0).forGetter(OverclockData::manaOverclock), + Codec.DOUBLE.optionalFieldOf("MagicOverclock", 1.0).forGetter(OverclockData::magicOverclock), + ).apply(instance) { mana, magic -> OverclockData(mana, magic) } + } + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockState.kt b/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockState.kt new file mode 100644 index 00000000..f46c74c8 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/persistent/OverclockState.kt @@ -0,0 +1,67 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.persistent + +import com.mojang.serialization.Codec +import heckerpowered.matrix.Matrix +import net.minecraft.core.UUIDUtil +import net.minecraft.server.MinecraftServer +import net.minecraft.server.level.ServerPlayer +import net.minecraft.util.datafix.DataFixTypes +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.level.saveddata.SavedData +import net.minecraft.world.level.saveddata.SavedDataType +import java.util.UUID + +/** + * World-persistent overclock rates keyed by player UUID, restored from the pre-migration jar. + * + * 26.2 note: [SavedData] moved from the `writeNbt`/factory model to codec-based + * [SavedDataType]s; the codec reproduces the pre-migration tag layout + * (`players` -> uuid -> [OverclockData]) inside the new `data/matrix/overclock_state.dat` + * location (saved data files are namespaced directories now, so the old flat + * `matrix_overclock_state.dat` is no longer reachable through the vanilla storage API). + */ +class OverclockState : SavedData() { + val overclockData: MutableMap = mutableMapOf() + + companion object { + val CODEC: Codec = + Codec.unboundedMap(UUIDUtil.STRING_CODEC, OverclockData.CODEC) + .optionalFieldOf("players", emptyMap()) + .xmap( + { players -> OverclockState().also { it.overclockData.putAll(players) } }, + { state -> state.overclockData }, + ) + .codec() + + val TYPE: SavedDataType = SavedDataType( + Matrix.identifier("overclock_state"), + { OverclockState() }, + CODEC, + DataFixTypes.SAVED_DATA_COMMAND_STORAGE, + ) + + fun getServerState(server: MinecraftServer): OverclockState { + val state = server.overworld().dataStorage.computeIfAbsent(TYPE) + // Mirrors the pre-migration implementation: mark dirty on every access so the + // mutable per-player entries handed out below always get persisted. + state.setDirty() + return state + } + + fun getPlayerState(player: LivingEntity): OverclockData { + val server = requireNotNull(player.level().server) { "overclock state is server-side only" } + return getServerState(server).overclockData.computeIfAbsent(player.uuid) { OverclockData() } + } + } +} + +/** The player's magic overclock rate in `1.0..10.0`; scales magic strength. */ +val ServerPlayer.magicClock: Double get() = OverclockState.getPlayerState(this).magicOverclock + +/** The player's mana overclock rate in `1.0..10.0`; scales max mana. */ +val ServerPlayer.manaClock: Double get() = OverclockState.getPlayerState(this).manaOverclock diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/recipe/MatrixRecipeSerializer.kt b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/MatrixRecipeSerializer.kt new file mode 100644 index 00000000..93198d91 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/MatrixRecipeSerializer.kt @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.common.recipe + +import net.minecraft.core.Registry +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.resources.Identifier + +/** + * Restored from the last working 1.21 build (matrix-1.0.0.jar): the recipe serializer + * registration was lost from the source tree. The original registered with the plain + * string id, i.e. under the `minecraft` namespace ("minecraft:redstone_suit_charger"), + * which the generated recipe data references — kept identical for data compatibility. + */ +object MatrixRecipeSerializer { + fun onInitialize() { + Registry.register( + BuiltInRegistries.RECIPE_SERIALIZER, + Identifier.withDefaultNamespace("redstone_suit_charger"), + RedstoneSuitChargeRecipe.serializer + ) + } +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt index ccf182a6..9bc24fae 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/common/recipe/RedstoneSuitChargeRecipe.kt @@ -63,6 +63,7 @@ object RedstoneSuitChargeRecipe : CustomRecipe() { val mapCodec: MapCodec = MapCodec.unit(RedstoneSuitChargeRecipe) val streamCodec: StreamCodec = StreamCodec.unit(RedstoneSuitChargeRecipe) + @get:JvmName("serializerInstance") val serializer: RecipeSerializer = RecipeSerializer(mapCodec, streamCodec) override fun getSerializer(): RecipeSerializer { diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt b/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt index 2e9b3974..538b14da 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/FramebufferExtension.kt @@ -5,18 +5,25 @@ package heckerpowered.matrix.core -import com.mojang.blaze3d.platform.GlStateManager -import heckerpowered.matrix.client.render.OpenGLExtensions.clearGLError -import heckerpowered.matrix.client.render.recommendMipLevel -import net.minecraft.client.gl.Framebuffer -import org.lwjgl.opengl.GL46.* - +import com.mojang.blaze3d.GpuFormat +import com.mojang.blaze3d.pipeline.RenderTarget +import heckerpowered.matrix.client.render.MipmapsFramebuffer + +/** + * HDR framebuffer support surface, implemented via Mixin onto [RenderTarget]. + * + * On the 26.2 GpuDevice wrapper API, [RenderTarget.createBuffers] always allocates the color + * attachment as `GpuFormat.RGBA8_UNORM`. [framebufferColorFormat] records the format Matrix + * *wants* new framebuffers to use (read by [MipmapsFramebuffer] and by whatever + * allocation path a Mixin end up driving); it no longer patches a raw GL image-format + * constant since there is nothing resembling `initFbo`/`glTexImage2D` left to intercept. + */ interface FramebufferExtension { companion object { @JvmStatic - var framebufferColorFormat = GL_RGBA16F + var framebufferColorFormat: GpuFormat = GpuFormat.RGBA16_FLOAT - fun changeColorFormat(colorFormat: Int, action: () -> T): T { + fun changeColorFormat(colorFormat: GpuFormat, action: () -> T): T { val previousColorFormat = framebufferColorFormat framebufferColorFormat = colorFormat val result = action() @@ -25,7 +32,7 @@ interface FramebufferExtension { } /** - * Indicates whether mipmaps should be allocated for this [Framebuffer]. + * Indicates whether mipmaps should be allocated for this [RenderTarget]. * * When set to `true`, the framebuffer's color attachment will be initialized * with enough storage to hold a full mipmap chain, allowing rendering to or sampling @@ -39,58 +46,37 @@ interface FramebufferExtension { * accessing this property will always return `false`, and setting it will have no effect. * No exceptions will be thrown in such cases. */ - var Framebuffer.allocateMipmaps: Boolean + var RenderTarget.allocateMipmaps: Boolean get() = (this as? FramebufferExtension)?.useMipmaps ?: false set(value) { (this as? FramebufferExtension)?.useMipmaps = value } /** + * Points this [RenderTarget] at mip level [mipLevel] for both writing (rendering) and + * reading (sampling), then narrows the effective viewport to that level's dimensions. * + * 26.2 note: the old immediate-mode `beginWrite`/`glFramebufferTexture2D`/`glViewport` + * sequence has no equivalent — render passes are self-contained and target an explicit + * [com.mojang.blaze3d.textures.GpuTextureView] instead of a bound FBO attachment. This + * only has a real implementation for [MipmapsFramebuffer], which owns a per-level + * [com.mojang.blaze3d.textures.GpuTextureView] array; for any other [RenderTarget] this + * is a no-op. */ - fun Framebuffer.beginWriteLod(mipLevel: Int, attachment: Int = GL_COLOR_ATTACHMENT0, setTextureSize: Boolean = true, setViewport: Boolean = true) { - clearGLError() - - beginWrite(false) - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, colorAttachment, mipLevel) - endWrite() - - beginRead() - val textureWidth = glGetTexLevelParameteri(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_WIDTH) - val textureHeight = glGetTexLevelParameteri(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_HEIGHT) - endRead() - - this.textureWidth = textureWidth - this.textureHeight = textureHeight - - if (setViewport) { - viewportWidth = textureWidth - viewportHeight = textureHeight - GlStateManager._viewport(0, 0, textureWidth, textureHeight) - } + fun RenderTarget.beginWriteLod(mipLevel: Int, setViewport: Boolean = true) { + (this as? MipmapsFramebuffer)?.levelOfDetail = mipLevel } - fun Framebuffer.endWriteLod() { + fun RenderTarget.endWriteLod() { beginWriteLod(0) } - fun Framebuffer.beginReadLod(mipLevel: Int) { - beginRead() - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, mipLevel) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipLevel) - endRead() + fun RenderTarget.beginReadLod(mipLevel: Int) { + (this as? MipmapsFramebuffer)?.levelOfDetail = mipLevel } - fun Framebuffer.endReadLod() { - beginRead() - val textureWidth = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) - val textureHeight = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT) - - val maxMipLevel = recommendMipLevel(textureWidth, textureHeight) - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxMipLevel) - endRead() + fun RenderTarget.endReadLod() { + (this as? MipmapsFramebuffer)?.levelOfDetail = 0 } } diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt index 5914bbbb..eaa1605a 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ScheduledExecutor.kt @@ -12,7 +12,11 @@ import kotlin.time.Duration import kotlin.time.DurationUnit object ScheduledExecutor { - private val executor = ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()) + private val executor = ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()) { runnable -> + // Daemon threads: an armed fixed-rate task (standalone warp tick) must never keep the + // JVM alive after a normal game quit — the default factory's non-daemon workers would. + Thread(runnable, "matrix-scheduler").apply { isDaemon = true } + } fun schedule(tickDuration: Duration, task: () -> Unit): ScheduledFuture<*> { val future = executor.scheduleAtFixedRate(task, 0, tickDuration.toLong(DurationUnit.NANOSECONDS), TimeUnit.NANOSECONDS) diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt index bfc56ce9..ff84d59d 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/ServerTimeRatio.kt @@ -5,37 +5,47 @@ package heckerpowered.matrix.core -import heckerpowered.foundation.ui.animation.time.MonotonicTimeline +import heckerpowered.matrix.mixin.MinecraftServerAccessor +import heckerpowered.matrix.mixin.TickRateManagerAccessor import net.minecraft.server.MinecraftServer import net.minecraft.util.Util import kotlin.time.Duration import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.DurationUnit -import kotlin.time.TimeMark -import kotlin.time.TimeSource +// Restored from 16a3466 ("Fix time warp"): the direct nanosecondsPerTick write bypasses +// setTickRate's >= 1 tps clamp (0.01x slow-time needs 0.2 tps), and all deadline math uses +// Util.getNanos() — the server loop's clock, which the client JVM redirects to the GLFW +// timer (System.nanoTime() has a different epoch and would produce a never-arriving +// deadline, freezing the integrated server). +// +// Field access goes through mixin accessors, NOT class-tweaker widenings: in production the +// tweaker's accessible-field entries did not take effect (IllegalAccessError), while mixin +// accessors behave identically in dev and production. class ServerTimeRatio(private val minecraftServer: MinecraftServer) { + private val serverAccess get() = minecraftServer as MinecraftServerAccessor + private val tickRateAccess get() = minecraftServer.tickRateManager() as TickRateManagerAccessor + var tickDuration: Duration - get() = minecraftServer.tickRateManager().nanosecondsPerTick().nanoseconds + get() = tickRateAccess.`matrix$getNanosecondsPerTick`().nanoseconds set(value) { val newTickDurationNanos = value.toLong(DurationUnit.NANOSECONDS) - if (minecraftServer.tickRateManager().nanosecondsPerTick() == newTickDurationNanos) { + if (tickRateAccess.`matrix$getNanosecondsPerTick`() == newTickDurationNanos) { // The tick time has already synced. return } - minecraftServer.tickRateManager().nanosecondsPerTick = newTickDurationNanos + tickRateAccess.`matrix$setNanosecondsPerTick`(newTickDurationNanos) val currentTickStartTimeNanos = minecraftServer.tickStartTimeNanos - val currentTickEndTimeNanos = minecraftServer.tickEndTimeNanos - val currentTimeNanos = System.nanoTime() + val currentTickEndTimeNanos = serverAccess.`matrix$getNextTickTimeNanos`() + val currentTimeNanos = Util.getNanos() val timeRange = currentTickStartTimeNanos.toDouble()..currentTickEndTimeNanos.toDouble() val remainingTimeRatio = (1 - currentTimeNanos.toDouble().inverseLerp(timeRange)).coerceIn(.0..1.0) val newCurrentTickEndTime = currentTimeNanos + (newTickDurationNanos * remainingTimeRatio).toLong() // Not waiting for next tick means wait until `tickStartTimeNanos` - minecraftServer.waitingForNextTick = false - minecraftServer.nextTickTimeNanos = newCurrentTickEndTime - minecraftServer.tickEndTimeNanos = newCurrentTickEndTime + serverAccess.`matrix$setWaitingForNextTick`(false) + serverAccess.`matrix$setNextTickTimeNanos`(newCurrentTickEndTime) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt b/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt index 1b7141ae..2b00c5f9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/Vec3Extensions.kt @@ -5,9 +5,20 @@ package heckerpowered.matrix.core +import net.minecraft.world.entity.Entity import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 +/** + * Interpolated (render) position of this entity at [tickDelta] between the previous and + * current tick. Thin alias over [Entity.getPosition] (mojmap) — kept as an extension since + * several renderer call sites (ported from the 1.21/yarn `getLerpedPos` name) read more + * clearly with the old name. + */ +fun Entity.getLerpedPos(tickDelta: Float): Vec3 { + return getPosition(tickDelta) +} + fun Vec3.toAABB(): AABB { return AABB(this, this) } diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/extension/LivingEntityExtension.kt b/common/src/main/kotlin/heckerpowered/matrix/core/extension/LivingEntityExtension.kt index 9b6e8797..f362d084 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/extension/LivingEntityExtension.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/extension/LivingEntityExtension.kt @@ -11,12 +11,15 @@ import heckerpowered.matrix.common.entity.ability.HealMeasurementScope import heckerpowered.matrix.common.item.WizardHelmet13 import heckerpowered.matrix.common.magic.core.MagicCalculationContext import heckerpowered.matrix.common.persistent.wizardHelmetStack +import heckerpowered.matrix.mixin.LivingEntityAccessor import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.attributes.Attributes import net.minecraft.world.entity.player.Player val LivingEntity.attackDamage: Double - get() = getAttributeValue(Attributes.ATTACK_DAMAGE) + // 26.2 removed attack_damage from many default mob attribute sets and getAttributeValue + // throws for absent attributes; absent means "cannot attack", i.e. 0 damage. + get() = if (attributes.hasAttribute(Attributes.ATTACK_DAMAGE)) getAttributeValue(Attributes.ATTACK_DAMAGE) else 0.0 fun LivingEntity.healOverflow(amount: Float) { val actualAmount = amount * healingMultiplier.toFloat() @@ -50,7 +53,7 @@ fun LivingEntity.addAbsorptionUpTo(amount: Float, maximumAmount: Float): Float { if (currentAmount >= maximumAmount) return 0.0F val addedAmount = amount.coerceAtMost(maximumAmount - currentAmount) - internalSetAbsorptionAmount(currentAmount + addedAmount) + (this as LivingEntityAccessor).`matrix$internalSetAbsorptionAmount`(currentAmount + addedAmount) return addedAmount } diff --git a/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt b/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt index 41213b4e..7abeff4f 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/core/utility/EntitySearch.kt @@ -6,7 +6,11 @@ package heckerpowered.matrix.core.utility import heckerpowered.matrix.core.* +import heckerpowered.matrix.mixin.EntitySectionAccessor +import heckerpowered.matrix.mixin.EntitySectionStorageAccessor +import heckerpowered.matrix.mixin.LevelEntityGetterAdapterAccessor import net.minecraft.core.SectionPos +import net.minecraft.util.ClassInstanceMultiMap import net.minecraft.world.entity.Entity import net.minecraft.world.entity.boss.enderdragon.EnderDragonPart import net.minecraft.world.level.Level @@ -132,7 +136,10 @@ fun Level.getEntities(searchBox: AABB): Sequence = sequence { return@sequence } - val entities = entityGetter.sectionStorage + @Suppress("UNCHECKED_CAST") + val sectionStorage = (entityGetter as LevelEntityGetterAdapterAccessor) + .`matrix$getSectionStorage`() as EntitySectionStorage + val entities = sectionStorage .getEntities(searchBox) .mapNotNull { it as? Entity } @@ -169,7 +176,8 @@ fun EntitySectionStorage.getAccessibleNonEmptySections( val minSectionKey = SectionPos.asLong(sectionX, 0, 0) val maxSectionKey = SectionPos.asLong(sectionX, -1, -1) - val sections = sectionIds + val sections = (this@getAccessibleNonEmptySections as EntitySectionStorageAccessor) + .`matrix$getSectionIds`() .subSet(minSectionKey, maxSectionKey + 1L) .asSequence() .filter { sectionKey -> @@ -184,5 +192,8 @@ fun EntitySectionStorage.getAccessibleNonEmptySections( } } -fun EntitySection.getEntities(searchBox: AABB): Sequence = - storage.asSequence().filter { it.boundingBox.intersects(searchBox) } \ No newline at end of file +fun EntitySection.getEntities(searchBox: AABB): Sequence { + @Suppress("UNCHECKED_CAST") + val storage = (this as EntitySectionAccessor).`matrix$getStorage`() as ClassInstanceMultiMap + return storage.asSequence().filter { it.boundingBox.intersects(searchBox) } +} \ No newline at end of file diff --git a/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixGuiRenderState.kt b/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixGuiRenderState.kt new file mode 100644 index 00000000..dd9fb305 --- /dev/null +++ b/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixGuiRenderState.kt @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + +package heckerpowered.matrix.extension + +/** + * Injected into GuiRenderState (classtweaker inject-interface + soft @Implements in + * GuiRenderStateMixin). Marks where the Matrix HUD's stratum begins so GuiRendererMixin can + * split the vanilla draw list and capture the mod's HUD into its own framebuffer — the 26.2 + * replacement for 1.21's "bind hudFramebuffer while the HUD draws" capture semantics. + */ +interface MatrixGuiRenderState { + /** Starts a fresh stratum and remembers it as the beginning of the Matrix HUD content. */ + fun beginMatrixHudStratum() + + /** + * Starts a fresh stratum and remembers it as the END boundary of the Matrix HUD content: + * everything the HUD callback extracted lives in [start, end), and later strata + * (screens, tooltips, toasts) stay out of the capture. + */ + fun endMatrixHudStratum() + + /** + * Whether a Matrix HUD stratum was begun this frame AND the capture split is applicable + * (no vanilla menu-blur split active; with one the renderer degrades to vanilla behavior). + */ + fun hasMatrixHudStratum(): Boolean + + /** Index into the strata list where the Matrix HUD content begins, or -1. */ + fun matrixHudStrataStart(): Int + + /** Exclusive end index of the Matrix HUD strata, or Integer.MAX_VALUE if never marked. */ + fun matrixHudStrataEnd(): Int +} diff --git a/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixMinecraftServer.kt b/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixMinecraftServer.kt index 5ee97c0f..9caa5fd9 100644 --- a/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixMinecraftServer.kt +++ b/common/src/main/kotlin/heckerpowered/matrix/extension/MatrixMinecraftServer.kt @@ -1,6 +1,10 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) 2026 heckerpowered + */ + package heckerpowered.matrix.extension interface MatrixMinecraftServer { var tickStartTimeNanos: Long - var tickEndTimeNanos: Long -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/equipment/coal.json b/common/src/main/resources/assets/matrix/equipment/coal.json new file mode 100644 index 00000000..72b88cab --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/coal.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:coal" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:coal" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/emerald.json b/common/src/main/resources/assets/matrix/equipment/emerald.json new file mode 100644 index 00000000..1f789145 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/emerald.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:emerald" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:emerald" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/lapis_lazuli.json b/common/src/main/resources/assets/matrix/equipment/lapis_lazuli.json new file mode 100644 index 00000000..1b28e146 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/lapis_lazuli.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:lapis_lazuli" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:lapis_lazuli" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/lightning.json b/common/src/main/resources/assets/matrix/equipment/lightning.json new file mode 100644 index 00000000..c01434b4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/lightning.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:warden" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:warden" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/redstone.json b/common/src/main/resources/assets/matrix/equipment/redstone.json new file mode 100644 index 00000000..5ad29d82 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/redstone.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:redstone" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:redstone" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/stone.json b/common/src/main/resources/assets/matrix/equipment/stone.json new file mode 100644 index 00000000..8d8f4313 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/stone.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:stone" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:stone" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/warden.json b/common/src/main/resources/assets/matrix/equipment/warden.json new file mode 100644 index 00000000..c01434b4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/warden.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:warden" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:warden" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/wizard.json b/common/src/main/resources/assets/matrix/equipment/wizard.json new file mode 100644 index 00000000..5f35642b --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/wizard.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:wizard" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:wizard" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/equipment/wooden.json b/common/src/main/resources/assets/matrix/equipment/wooden.json new file mode 100644 index 00000000..239118ec --- /dev/null +++ b/common/src/main/resources/assets/matrix/equipment/wooden.json @@ -0,0 +1,14 @@ +{ + "layers": { + "humanoid": [ + { + "texture": "matrix:wooden" + } + ], + "humanoid_leggings": [ + { + "texture": "matrix:wooden" + } + ] + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_axe.json b/common/src/main/resources/assets/matrix/items/coal_axe.json new file mode 100644 index 00000000..5eb5ee44 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_boots.json b/common/src/main/resources/assets/matrix/items/coal_boots.json new file mode 100644 index 00000000..f02fce88 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_chestplate.json b/common/src/main/resources/assets/matrix/items/coal_chestplate.json new file mode 100644 index 00000000..d171d24f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_helmet.json b/common/src/main/resources/assets/matrix/items/coal_helmet.json new file mode 100644 index 00000000..30390f59 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_hoe.json b/common/src/main/resources/assets/matrix/items/coal_hoe.json new file mode 100644 index 00000000..6d17daa3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_leggings.json b/common/src/main/resources/assets/matrix/items/coal_leggings.json new file mode 100644 index 00000000..f3964df4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_pickaxe.json b/common/src/main/resources/assets/matrix/items/coal_pickaxe.json new file mode 100644 index 00000000..440080ec --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_shovel.json b/common/src/main/resources/assets/matrix/items/coal_shovel.json new file mode 100644 index 00000000..bdbac663 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/coal_sword.json b/common/src/main/resources/assets/matrix/items/coal_sword.json new file mode 100644 index 00000000..d1189c81 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/coal_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/coal_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_axe.json b/common/src/main/resources/assets/matrix/items/emerald_axe.json new file mode 100644 index 00000000..2720840d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_boots.json b/common/src/main/resources/assets/matrix/items/emerald_boots.json new file mode 100644 index 00000000..5ee9dcca --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_chestplate.json b/common/src/main/resources/assets/matrix/items/emerald_chestplate.json new file mode 100644 index 00000000..b566a6d0 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_helmet.json b/common/src/main/resources/assets/matrix/items/emerald_helmet.json new file mode 100644 index 00000000..18a99fef --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_hoe.json b/common/src/main/resources/assets/matrix/items/emerald_hoe.json new file mode 100644 index 00000000..0f842f7e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_leggings.json b/common/src/main/resources/assets/matrix/items/emerald_leggings.json new file mode 100644 index 00000000..c2c4af6d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json b/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json new file mode 100644 index 00000000..8240a398 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_shovel.json b/common/src/main/resources/assets/matrix/items/emerald_shovel.json new file mode 100644 index 00000000..730d8d2c --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/emerald_sword.json b/common/src/main/resources/assets/matrix/items/emerald_sword.json new file mode 100644 index 00000000..30395703 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/emerald_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/emerald_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/finder_arrow.json b/common/src/main/resources/assets/matrix/items/finder_arrow.json new file mode 100644 index 00000000..f69b2da0 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/finder_arrow.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/finder_arrow" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json new file mode 100644 index 00000000..d6f679f3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json new file mode 100644 index 00000000..27688da3 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json new file mode 100644 index 00000000..21812cb9 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json new file mode 100644 index 00000000..fbf2c79c --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json new file mode 100644 index 00000000..17f48c3f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json new file mode 100644 index 00000000..e221e4e5 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json new file mode 100644 index 00000000..6b5d2592 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json new file mode 100644 index 00000000..b12ca7eb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json b/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json new file mode 100644 index 00000000..6d386e21 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lapis_lazuli_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lapis_lazuli_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json b/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json new file mode 100644 index 00000000..9672dcc1 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/lightning_chestplate_borrowed_time.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/lightning_chestplate_borrowed_time" + } +} diff --git a/common/src/main/resources/assets/matrix/items/magic_talisman.json b/common/src/main/resources/assets/matrix/items/magic_talisman.json new file mode 100644 index 00000000..0888514d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/magic_talisman.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/magic_talisman" + } +} diff --git a/common/src/main/resources/assets/matrix/items/meta_bow.json b/common/src/main/resources/assets/matrix/items/meta_bow.json new file mode 100644 index 00000000..a6fe5fc0 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/meta_bow.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/meta_bow" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_axe.json b/common/src/main/resources/assets/matrix/items/redstone_axe.json new file mode 100644 index 00000000..966c94c5 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_axe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_boots.json b/common/src/main/resources/assets/matrix/items/redstone_boots.json new file mode 100644 index 00000000..df03865a --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_chestplate.json b/common/src/main/resources/assets/matrix/items/redstone_chestplate.json new file mode 100644 index 00000000..208f27a6 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_helmet.json b/common/src/main/resources/assets/matrix/items/redstone_helmet.json new file mode 100644 index 00000000..8b7d6752 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_hoe.json b/common/src/main/resources/assets/matrix/items/redstone_hoe.json new file mode 100644 index 00000000..7a1e478d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_hoe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_leggings.json b/common/src/main/resources/assets/matrix/items/redstone_leggings.json new file mode 100644 index 00000000..ee06827f --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json b/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json new file mode 100644 index 00000000..67871b3e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_pickaxe" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_shovel.json b/common/src/main/resources/assets/matrix/items/redstone_shovel.json new file mode 100644 index 00000000..93b88639 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_shovel" + } +} diff --git a/common/src/main/resources/assets/matrix/items/redstone_sword.json b/common/src/main/resources/assets/matrix/items/redstone_sword.json new file mode 100644 index 00000000..9c822203 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/redstone_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/redstone_sword" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_boots.json b/common/src/main/resources/assets/matrix/items/stone_boots.json new file mode 100644 index 00000000..2f550b3e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_chestplate.json b/common/src/main/resources/assets/matrix/items/stone_chestplate.json new file mode 100644 index 00000000..665ac9a9 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_helmet.json b/common/src/main/resources/assets/matrix/items/stone_helmet.json new file mode 100644 index 00000000..0eec7a53 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/stone_leggings.json b/common/src/main/resources/assets/matrix/items/stone_leggings.json new file mode 100644 index 00000000..daf7deeb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/stone_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/stone_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/items/warden_chestplate.json b/common/src/main/resources/assets/matrix/items/warden_chestplate.json new file mode 100644 index 00000000..fbd9d442 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/warden_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/warden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json new file mode 100644 index 00000000..7a84d57d --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_1.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_1" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json new file mode 100644 index 00000000..8e821d88 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_10.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_10" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json new file mode 100644 index 00000000..2f5b67ab --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_13.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_13" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json new file mode 100644 index 00000000..6cb29797 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_2.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_2" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json new file mode 100644 index 00000000..8f8eb6a5 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_3.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_3" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json new file mode 100644 index 00000000..9dbe5ad4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_4.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_4" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json new file mode 100644 index 00000000..5328a750 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_5.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_5" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json b/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json new file mode 100644 index 00000000..a05c0b45 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wizard_helmet_hacker.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wizard_helmet_hacker" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_boots.json b/common/src/main/resources/assets/matrix/items/wooden_boots.json new file mode 100644 index 00000000..884c4647 --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_boots" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_chestplate.json b/common/src/main/resources/assets/matrix/items/wooden_chestplate.json new file mode 100644 index 00000000..acf790bb --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_helmet.json b/common/src/main/resources/assets/matrix/items/wooden_helmet.json new file mode 100644 index 00000000..06dda93e --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_helmet" + } +} diff --git a/common/src/main/resources/assets/matrix/items/wooden_leggings.json b/common/src/main/resources/assets/matrix/items/wooden_leggings.json new file mode 100644 index 00000000..72f0c3be --- /dev/null +++ b/common/src/main/resources/assets/matrix/items/wooden_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "matrix:item/wooden_leggings" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/lightning_chestplate_borrowed_time.json b/common/src/main/resources/assets/matrix/models/item/lightning_chestplate_borrowed_time.json new file mode 100644 index 00000000..bf468dc4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/lightning_chestplate_borrowed_time.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/warden_chestplate" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_1.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_1.json new file mode 100644 index 00000000..f035132c --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_basic" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_10.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_10.json new file mode 100644 index 00000000..16631be4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_10.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_warp_dancer" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_13.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_13.json new file mode 100644 index 00000000..984bef48 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_13.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_apogee" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_2.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_2.json new file mode 100644 index 00000000..46b67734 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_doom" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_3.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_3.json new file mode 100644 index 00000000..9e029f42 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_3.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_ruin" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_4.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_4.json new file mode 100644 index 00000000..16631be4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_4.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_warp_dancer" + } +} diff --git a/common/src/main/resources/assets/matrix/models/item/wizard_helmet_5.json b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_5.json new file mode 100644 index 00000000..984bef48 --- /dev/null +++ b/common/src/main/resources/assets/matrix/models/item/wizard_helmet_5.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "matrix:item/wizard_helmet_apogee" + } +} diff --git a/common/src/main/resources/assets/matrix/shaders/blit/blit.fsh b/common/src/main/resources/assets/matrix/shaders/blit/blit.fsh index 50e8e7f1..0ddc65fc 100644 --- a/common/src/main/resources/assets/matrix/shaders/blit/blit.fsh +++ b/common/src/main/resources/assets/matrix/shaders/blit/blit.fsh @@ -1,11 +1,14 @@ -#version 330 core +#version 330 in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float lod = .0; uniform sampler2D depthAttachment; +layout(std140) uniform BlitConfig { + float lod; +}; + out vec4 fragColor; void main() { @@ -14,4 +17,4 @@ void main() { if (fragColor.r == 0.0 && fragColor.g == 0.0 && fragColor.b == 0.0) { discard; } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/blit/blit_no_depth.fsh b/common/src/main/resources/assets/matrix/shaders/blit/blit_no_depth.fsh index 389fb722..665bd733 100644 --- a/common/src/main/resources/assets/matrix/shaders/blit/blit_no_depth.fsh +++ b/common/src/main/resources/assets/matrix/shaders/blit/blit_no_depth.fsh @@ -1,9 +1,12 @@ -#version 330 core +#version 330 in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float lod = .0; + +layout(std140) uniform BlitConfig { + float lod; +}; out vec4 fragColor; @@ -12,4 +15,4 @@ void main() { if (fragColor.r == 0.0 && fragColor.g == 0.0 && fragColor.b == 0.0) { discard; } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/blit/blit_replace.fsh b/common/src/main/resources/assets/matrix/shaders/blit/blit_replace.fsh new file mode 100644 index 00000000..ffdf582e --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/blit/blit_replace.fsh @@ -0,0 +1,19 @@ +#version 330 + +in vec2 fragTexCoord; + +uniform sampler2D framebuffer; + +layout(std140) uniform BlitConfig { + float lod; +}; + +out vec4 fragColor; + +// linearCopyTo/nearestCopyTo were raw glBlitFramebuffer calls in 1.21: a full REPLACE of +// every destination pixel, black/transparent included. blit_no_depth.fsh's black-pixel +// discard belongs to the compositing copyFramebuffer path only — reusing it here left the +// destination's previous contents behind in transparent regions (the acrylic-wash leak). +void main() { + fragColor = textureLod(framebuffer, fragTexCoord, lod); +} diff --git a/common/src/main/resources/assets/matrix/shaders/core/guide_line.fsh b/common/src/main/resources/assets/matrix/shaders/core/guide_line.fsh new file mode 100644 index 00000000..8d7d54af --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/core/guide_line.fsh @@ -0,0 +1,14 @@ +#version 330 + +layout(std140) uniform GuideLineTransform { + mat4 ViewProjMat; + vec4 LineParams; +}; + +in vec4 vertexColor; + +out vec4 fragColor; + +void main() { + fragColor = vec4(vertexColor.rgb * LineParams.z, vertexColor.a); +} diff --git a/common/src/main/resources/assets/matrix/shaders/core/guide_line.vsh b/common/src/main/resources/assets/matrix/shaders/core/guide_line.vsh new file mode 100644 index 00000000..6e7850b6 --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/core/guide_line.vsh @@ -0,0 +1,20 @@ +#version 330 + +layout(std140) uniform GuideLineTransform { + mat4 ViewProjMat; + vec4 LineParams; +}; + +in vec3 Position; +in vec4 Color; + +out vec4 vertexColor; + +// 1.21 drew these as plain GL_LINES through position_color — hardware line rasterization, +// no width-quad expansion. The expansion variant's screen-direction sign-flip degenerated +// at near-vertical angles (segments vanished view-dependently), so this matches the old +// mechanism exactly: project and let the rasterizer draw 1px lines on both backends. +void main() { + gl_Position = ViewProjMat * vec4(Position, 1.0); + vertexColor = Color; +} diff --git a/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh b/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh new file mode 100644 index 00000000..86ce583d --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/core/screenquad_frag_tex_coord.vsh @@ -0,0 +1,9 @@ +#version 330 + +out vec2 fragTexCoord; + +void main() { + vec2 uv = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2); + gl_Position = vec4(uv * vec2(2, 2) + vec2(-1, -1), 0, 1); + fragTexCoord = uv; +} diff --git a/common/src/main/resources/assets/matrix/shaders/debug.fsh b/common/src/main/resources/assets/matrix/shaders/debug.fsh index 1e046ffb..7873f116 100644 --- a/common/src/main/resources/assets/matrix/shaders/debug.fsh +++ b/common/src/main/resources/assets/matrix/shaders/debug.fsh @@ -3,5 +3,5 @@ out vec4 fragColor; void main() { - fragColor = vec4(1.0, .0, .0, 1.0); + fragColor = vec4(1.0, 0.0, 0.0, 1.0); } \ No newline at end of file diff --git a/common/src/main/resources/assets/matrix/shaders/gaussian_blur_horizontal.fsh b/common/src/main/resources/assets/matrix/shaders/gaussian_blur_horizontal.fsh index 1f6c271c..d4069f07 100644 --- a/common/src/main/resources/assets/matrix/shaders/gaussian_blur_horizontal.fsh +++ b/common/src/main/resources/assets/matrix/shaders/gaussian_blur_horizontal.fsh @@ -4,16 +4,21 @@ in vec2 fragTexCoord; out vec4 fragColor; uniform sampler2D framebuffer; -uniform float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); -uniform float radius = 5.0; +const float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); + +layout(std140) uniform MatrixPostUniforms { + vec4 blurParams0; +}; + +#define radius blurParams0.x void main() { vec2 tex_offset = 1.0 / textureSize(framebuffer, 0) * radius; vec3 result = texture(framebuffer, fragTexCoord).rgb * weight[0]; for (int i = 1; i < 5; ++i) { - result += texture(framebuffer, fragTexCoord + vec2(.0, tex_offset.y * i)).rgb * weight[i]; - result += texture(framebuffer, fragTexCoord - vec2(.0, tex_offset.y * i)).rgb * weight[i]; + result += texture(framebuffer, fragTexCoord + vec2(0.0, tex_offset.y * i)).rgb * weight[i]; + result += texture(framebuffer, fragTexCoord - vec2(0.0, tex_offset.y * i)).rgb * weight[i]; } fragColor = vec4(result, 1.0); diff --git a/common/src/main/resources/assets/matrix/shaders/gaussian_blur_vertical.fsh b/common/src/main/resources/assets/matrix/shaders/gaussian_blur_vertical.fsh index e7ea713b..d05389a6 100644 --- a/common/src/main/resources/assets/matrix/shaders/gaussian_blur_vertical.fsh +++ b/common/src/main/resources/assets/matrix/shaders/gaussian_blur_vertical.fsh @@ -4,16 +4,21 @@ in vec2 fragTexCoord; out vec4 fragColor; uniform sampler2D framebuffer; -uniform float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); -uniform float radius = 5.0; +const float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); + +layout(std140) uniform MatrixPostUniforms { + vec4 blurParams0; +}; + +#define radius blurParams0.x void main() { vec2 tex_offset = 1.0 / textureSize(framebuffer, 0) * radius; vec3 result = texture(framebuffer, fragTexCoord).rgb * weight[0]; for (int i = 1; i < 5; ++i) { - result += texture(framebuffer, fragTexCoord + vec2(tex_offset.x * i, .0)).rgb * weight[i]; - result += texture(framebuffer, fragTexCoord - vec2(tex_offset.x * i, .0)).rgb * weight[i]; + result += texture(framebuffer, fragTexCoord + vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; + result += texture(framebuffer, fragTexCoord - vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; } fragColor = vec4(result, 1.0); diff --git a/common/src/main/resources/assets/matrix/shaders/gbuffer/position_reconstruction.fsh b/common/src/main/resources/assets/matrix/shaders/gbuffer/position_reconstruction.fsh index bf74a989..af005d63 100644 --- a/common/src/main/resources/assets/matrix/shaders/gbuffer/position_reconstruction.fsh +++ b/common/src/main/resources/assets/matrix/shaders/gbuffer/position_reconstruction.fsh @@ -15,7 +15,9 @@ vec3 worldAbsolutePosition(vec2 uv, float depth) { // Convert UV coordinates and depth to clip space coordinates. // UV is mapped from [0,1] to [-1,1]. // Depth is mapped from [0,1] (typically from a depth texture or depth buffer) to [-1,1] (clip space z). - vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); // Convert clip space coordinates to view space coordinates. // inverse projection matrix handles the perspective projection, but the result is still a homogeneous coordinate. @@ -44,7 +46,7 @@ void main() { ncd.y = -ndc.y; float depth = texture(depthAttachment, fragTexCoord).r; - vec4 clipPosition = vec4(ndc, depth * 2.0 - 1.0, 1.0); + vec4 clipPosition = vec4(ndc, depth, 1.0); // zero-to-one depth, see above vec4 viewPosition = inverseProjectionMatrix * clipPosition; viewPosition /= viewPosition.w;// Perspective divide vec4 worldPosition = inverseModelViewMatrix * viewPosition; diff --git a/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.fsh b/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.fsh new file mode 100644 index 00000000..d7eb9741 --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.fsh @@ -0,0 +1,49 @@ +#version 330 + +#moj_import + +uniform sampler2D Sampler0; + +in vec2 texCoord0; +in vec4 vertexColor; +in vec3 dissolveParams; + +out vec4 fragColor; + +const float emissiveStrength = 15.0; +const float pixelStrength = 16.0; +const float detialStrength = 1.0; +const vec4 emissiveColor = vec4(0.1, 0.5, 1.0, 1.0); + +vec2 dissolveTexCoord() { + vec2 uv = texCoord0 - 0.5; + // dissolveParams.y carries (height/width) / 4 packed into the Normal channel. + uv.y *= max(dissolveParams.y * 4.0, 0.0001); + return uv + 0.5; +} + +float pixelColor() { + vec2 pixelTexCoord = dissolveTexCoord(); + float time = dissolveParams.z * 10.0; + return texture(Sampler0, pixelTexCoord + vec2(time * 0.1, time * 0.1)).b; +} + +float pixelAnimation() { + float pixelNoise = dissolveTexCoord().r; + return pixelNoise - mix(1.5, -1.5, dissolveParams.x); +} + +float border() { + vec4 normalColor = texture(Sampler0, ceil(dissolveTexCoord() * pixelStrength) / pixelStrength); + vec4 offsetColor = texture(Sampler0, ceil((dissolveTexCoord() + 0.01) * pixelStrength) / pixelStrength); + return (normalColor.b - offsetColor.b) * detialStrength; +} + +void main() { + float opacityMask = clamp((pixelColor() + border()) - pixelAnimation(), 0.0, 1.0); + + vec4 color = vertexColor; + color.a *= ceil(opacityMask); + color.rgb = pow(1.0 - opacityMask, 10.0) * (emissiveColor.rgb * emissiveStrength); + fragColor = color * ColorModulator; +} diff --git a/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.vsh b/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.vsh new file mode 100644 index 00000000..c28aa98d --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/gui/dissolve_rect.vsh @@ -0,0 +1,20 @@ +#version 330 + +#moj_import +#moj_import + +in vec3 Position; +in vec2 UV0; +in vec4 Color; +in vec3 Normal; + +out vec2 texCoord0; +out vec4 vertexColor; +out vec3 dissolveParams; + +void main() { + gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); + texCoord0 = UV0; + vertexColor = Color; + dissolveParams = Normal * 0.5 + 0.5; +} diff --git a/common/src/main/resources/assets/matrix/shaders/lib/scene_depth.glsl b/common/src/main/resources/assets/matrix/shaders/lib/scene_depth.glsl index 3f233e47..0414a9af 100644 --- a/common/src/main/resources/assets/matrix/shaders/lib/scene_depth.glsl +++ b/common/src/main/resources/assets/matrix/shaders/lib/scene_depth.glsl @@ -2,7 +2,9 @@ vec3 worldPositionFromDepth(vec2 uv, float depth, mat4 inverseProjectionMatrix, // Convert UV coordinates and depth to clip space coordinates. // UV is mapped from [0,1] to [-1,1]. // Depth is mapped from [0,1] (typically from a depth texture or depth buffer) to [-1,1] (clip space z). - vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); // Convert clip space coordinates to view space coordinates. // inverse projection matrix handles the perspective projection, bu the result is still a homogeneous coordinate. @@ -27,7 +29,9 @@ vec3 worldPositionFromDepth(vec2 uv, float depth, mat4 inverseProjectionMatrix, vec3 worldPositionFromDepth(vec2 uv, float depth, mat4 inverseViewProjectionMatrix) { // NDC mapping: [0,1] -> [-1,1] (OpenGL convention) - vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); // Single 4x4 multiply in homogeneous space vec4 worldHomogeneous = inverseViewProjectionMatrix * clipSpacePosition; diff --git a/common/src/main/resources/assets/matrix/shaders/point_sprite/point_sprite.vsh b/common/src/main/resources/assets/matrix/shaders/point_sprite/point_sprite.vsh index 08f392fc..a38dfd58 100644 --- a/common/src/main/resources/assets/matrix/shaders/point_sprite/point_sprite.vsh +++ b/common/src/main/resources/assets/matrix/shaders/point_sprite/point_sprite.vsh @@ -2,9 +2,14 @@ layout (location = 0) in vec2 Position; -uniform float time; +layout(std140) uniform MatrixPointSpriteUniforms { + vec4 pointSpriteParams; +}; + +#define time pointSpriteParams.x out vec2 OutPosition; +out vec4 InColor; vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; @@ -124,12 +129,13 @@ void main() vec3 windForce = vec3(0.01, 0.0, 0.0); float r = snoise3(vec3(Position * 3.0, time)) * 0.01; - vec3 velocity = curlNoise(position + vec3(.0, .0, time * 0.2)) * 0.001 + windForce; + vec3 velocity = curlNoise(position + vec3(0.0, 0.0, time * 0.2)) * 0.001 + windForce; OutPosition = (position + velocity).xy; if (OutPosition.x > 1 || OutPosition.y < -1 || OutPosition.y > 1){ OutPosition = vec2(-1.0, OutPosition.y); } - gl_Position = vec4(OutPosition, .0, 1.0); + gl_Position = vec4(OutPosition, 0.0, 1.0); gl_PointSize = 6.0; -} \ No newline at end of file + InColor = vec4(1.0, 0.5, 1.0, 1.0); +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/aura.fsh b/common/src/main/resources/assets/matrix/shaders/post/aura.fsh index f96b57d9..5321dcea 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/aura.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/aura.fsh @@ -7,9 +7,14 @@ uniform sampler2D entityColorAttachment; uniform sampler2D sceneDepthAttachment; uniform sampler2D sceneColorAttachment; uniform sampler2D noiseColorAttachment; -uniform float time; -uniform float alpha; -uniform vec4 auraColor = vec4(0, 0, 0, 0); + +layout(std140) uniform MatrixPostUniforms { + vec4 auraParams; + vec4 auraColor; +}; + +#define time auraParams.x +#define alpha auraParams.y out vec4 fragColor; @@ -23,7 +28,7 @@ void main() { float sceneDepth = texture(sceneDepthAttachment, fragTexCoord).r; vec4 sceneColor = texture(sceneColorAttachment, fragTexCoord); - if (entityColor.a <= .0 || (entityColor.r <= 0 && entityColor.g <= 0 && entityColor.b <= 0)) { + if (entityColor.a <= 0.0 || (entityColor.r <= 0 && entityColor.g <= 0 && entityColor.b <= 0)) { fragColor = sceneColor; return; } @@ -35,4 +40,4 @@ void main() { } else { fragColor = entityColor; } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh index 4bd0efd4..f2d56862 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/bloom/bloom_brightness_pass.fsh @@ -1,8 +1,16 @@ #version 150 core uniform sampler2D framebuffer;// Input texture from the previous pass -uniform float threshold;// Brightness threshold (e.g., 0.7) -uniform float intensity = 1.0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define bloomThreshold MatrixPostData0.x +#define bloomIntensity MatrixPostData0.y in vec2 fragTexCoord;// Texture coordinates from vertex shader @@ -38,14 +46,14 @@ void main() { // Determine the factor based on the threshold // step(edge, x) returns 0.0 if x < edge, and 1.0 if x >= edge - float factor = step(threshold, brightness); + float factor = step(bloomThreshold, brightness); // Output the final color: // If brightness is above threshold (factor = 1.0), keep the original color. // If brightness is below threshold (factor = 0.0), output black. - if (brightness < threshold) { - fragColor = vec4(0.0, 0.0, 0.0, .0); + if (brightness < bloomThreshold) { + fragColor = vec4(0.0, 0.0, 0.0, 0.0); } else { - fragColor = vec4(extractBloomSoft(color.rgb, threshold, 1.0), color.a); + fragColor = vec4(extractBloomSoft(color.rgb, bloomThreshold, 1.0), color.a); } } diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/blur_mask.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/blur_mask.fsh new file mode 100644 index 00000000..60e1fd8b --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/blur_mask.fsh @@ -0,0 +1,14 @@ +#version 330 core + +in vec2 fragTexCoord; + +uniform sampler2D framebuffer; + +out vec4 fragColor; + +void main() { + fragColor = texture(framebuffer, fragTexCoord); + if (fragColor.a < 0.1) { + discard; + } +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh index 6cf60a5d..bc39aa6b 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/gaussian_blur.fsh @@ -3,9 +3,44 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float kernel[49]; -uniform int kernelSize = 48; -uniform vec2 direction = vec2(1, 0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; + vec4 MatrixPostData4; + vec4 MatrixPostData5; + vec4 MatrixPostData6; + vec4 MatrixPostData7; + vec4 MatrixPostData8; + vec4 MatrixPostData9; + vec4 MatrixPostData10; + vec4 MatrixPostData11; + vec4 MatrixPostData12; + vec4 MatrixPostData13; +}; + +#define direction MatrixPostData0.xy +#define kernelSize int(MatrixPostData0.z) + +float kernelAt(int index) { + int block = index / 4; + int component = index - block * 4; + if (block == 0) return MatrixPostData1[component]; + if (block == 1) return MatrixPostData2[component]; + if (block == 2) return MatrixPostData3[component]; + if (block == 3) return MatrixPostData4[component]; + if (block == 4) return MatrixPostData5[component]; + if (block == 5) return MatrixPostData6[component]; + if (block == 6) return MatrixPostData7[component]; + if (block == 7) return MatrixPostData8[component]; + if (block == 8) return MatrixPostData9[component]; + if (block == 9) return MatrixPostData10[component]; + if (block == 10) return MatrixPostData11[component]; + if (block == 11) return MatrixPostData12[component]; + return MatrixPostData13[component]; +} out vec4 fragColor; @@ -15,14 +50,15 @@ void main() { fragColor = originalColor; return; } - vec4 color = originalColor * kernel[0]; + vec4 color = originalColor * kernelAt(0); vec2 offset = direction / vec2(textureSize(framebuffer, 0)); for (int i = 1; i <= kernelSize; ++i) { vec2 subOffset = offset * float(i); - color += texture(framebuffer, fragTexCoord + subOffset) * kernel[i]; - color += texture(framebuffer, fragTexCoord - subOffset) * kernel[i]; + float weight = kernelAt(i); + color += texture(framebuffer, fragTexCoord + subOffset) * weight; + color += texture(framebuffer, fragTexCoord - subOffset) * weight; } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh index 8bd418fb..fa005efa 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/kawase_blur.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 offset = vec2(1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define offset MatrixPostData0.xy out vec4 fragColor; @@ -16,4 +24,4 @@ void main() { color += texture(framebuffer, fragTexCoord + vec2(sampleOffset.x, -sampleOffset.y)); color += texture(framebuffer, fragTexCoord + vec2(-sampleOffset.x, -sampleOffset.y)); fragColor = color / 5; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh index b5610d4d..14939609 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/radial_blur.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float strength = 1.0; -uniform int samples = 10; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define strength MatrixPostData0.x +#define samples int(MatrixPostData0.y) out vec4 fragColor; @@ -19,4 +27,4 @@ void main() { } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh b/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh index 1c78de26..cc7a426a 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/blur/tent.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float lod = .0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define lod MatrixPostData0.x out vec4 fragColor; @@ -20,7 +28,11 @@ float luminance(vec3 color) { void main() { vec4 color = vec4(0); - vec2 texelSize = 1.0 / textureSize(framebuffer, 0); + // 1.21 sampled the full mip chain with FULL-RES texel offsets (the +-1 tent collapsed + // toward a bilinear fetch at deep lods — all spread came from the mip cascade). The + // 26.2 port feeds single-level views, whose textureSize is the LEVEL's size, so scale + // the offsets by exp2(-lod) to keep the original full-res-texel basis. + vec2 texelSize = exp2(-lod) / textureSize(framebuffer, 0); float weight = 0; for (int i = 0;i < 9; ++i) { @@ -33,4 +45,4 @@ void main() { color /= weight; fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/circle.fsh b/common/src/main/resources/assets/matrix/shaders/post/circle.fsh index 91b15a23..a609eb6b 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/circle.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/circle.fsh @@ -2,13 +2,19 @@ in vec2 fragTexCoord; -uniform mat4 modelViewMatrix; -uniform mat4 projectionMatrix; uniform sampler2D framebuffer; -uniform vec3 center = vec3(600.0); -uniform float radius = 300; -uniform vec2 resolution; // 必须正确设置为屏幕分辨率 -uniform float grayscaleIntensity = 1.0; + +layout(std140) uniform MatrixPostUniforms { + mat4 modelViewMatrix; + mat4 projectionMatrix; + vec4 circleParams0; + vec4 circleParams1; +}; + +#define center circleParams0.xyz +#define radius circleParams0.w +#define resolution circleParams1.xy +#define grayscaleIntensity circleParams1.z out vec4 fragColor; @@ -39,4 +45,4 @@ void main() { vec3 color = mix(framebufferColor.rgb, vec3(grayscale), grayscaleIntensity); fragColor = vec4(color, framebufferColor.a); } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh b/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh index 00bd592f..fa0d5549 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/collapse.fsh @@ -2,16 +2,19 @@ in vec2 fragTexCoord; +uniform sampler2D framebuffer; uniform sampler2D depthAttachment; -uniform mat4 inverseViewMatrix; -uniform mat4 inverseProjectionMatrix; -uniform vec2 resolution; -uniform vec3 playerPosition; +layout(std140) uniform MatrixPostUniforms { + mat4 inverseProjectionMatrix; + mat4 inverseViewMatrix; + vec4 MatrixPostData0; + vec4 MatrixPostData1; +}; -uniform sampler2D noiseTexture; - -uniform float dissolveFactor = 1.0; +#define playerPosition MatrixPostData0.xyz +#define dissolveFactor MatrixPostData0.w +#define resolution MatrixPostData1.xy out vec4 fragColor; @@ -19,7 +22,9 @@ vec3 worldAbsolutePosition(vec2 uv, float depth) { // Convert UV coordinates and depth to clip space coordinates. // UV is mapped from [0,1] to [-1,1]. // Depth is mapped from [0,1] (typically from a depth texture or depth buffer) to [-1,1] (clip space z). - vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); // Convert clip space coordinates to view space coordinates. // inverse projection matrix handles the perspective projection, bu the result is still a homogeneous coordinate. @@ -59,27 +64,44 @@ vec3 reconstructWorldNormal(vec2 uv, vec2 texelSize) { return worldNormal; } -vec4 triplanarMapping(vec3 worldPosition, vec3 worldNormal, sampler2D textureSampler, float scale) { - vec3 blendingWeights = abs(worldNormal); - blendingWeights = max(blendingWeights, 0.0001); - blendingWeights /= (blendingWeights.x + blendingWeights.y + blendingWeights.z); - - vec4 colorX = texture(textureSampler, worldPosition.yz * scale); - vec4 colorY = texture(textureSampler, worldPosition.xz * scale); - vec4 colorZ = texture(textureSampler, worldPosition.xy * scale); +float hash13(vec3 p) { + p = fract(p * 0.1031); + p += dot(p, p.yzx + 33.33); + return fract((p.x + p.y) * p.z); +} - return colorX * blendingWeights.x + - colorY * blendingWeights.y + - colorZ * blendingWeights.z; +float valueNoise(vec3 p) { + vec3 i = floor(p); + vec3 f = fract(p); + f = f * f * (3.0 - 2.0 * f); + + float n000 = hash13(i + vec3(0.0, 0.0, 0.0)); + float n100 = hash13(i + vec3(1.0, 0.0, 0.0)); + float n010 = hash13(i + vec3(0.0, 1.0, 0.0)); + float n110 = hash13(i + vec3(1.0, 1.0, 0.0)); + float n001 = hash13(i + vec3(0.0, 0.0, 1.0)); + float n101 = hash13(i + vec3(1.0, 0.0, 1.0)); + float n011 = hash13(i + vec3(0.0, 1.0, 1.0)); + float n111 = hash13(i + vec3(1.0, 1.0, 1.0)); + + float nx00 = mix(n000, n100, f.x); + float nx10 = mix(n010, n110, f.x); + float nx01 = mix(n001, n101, f.x); + float nx11 = mix(n011, n111, f.x); + float nxy0 = mix(nx00, nx10, f.y); + float nxy1 = mix(nx01, nx11, f.y); + return mix(nxy0, nxy1, f.z); } void main() { + vec4 sceneColor = texture(framebuffer, fragTexCoord); float nonLinearDepth = texture(depthAttachment, fragTexCoord).r; vec3 worldPosition = worldAbsolutePosition(fragTexCoord, nonLinearDepth); float dist = length(worldPosition - playerPosition); if (dist > 768.0) { - discard; + fragColor = sceneColor; + return; } vec3 worldNormal = reconstructWorldNormal(fragTexCoord, 1.0 / resolution); @@ -87,7 +109,8 @@ void main() { if (dot(worldNormal, cameraToPixel) > 0.0) { worldNormal = -worldNormal; } - vec4 noise = triplanarMapping(worldPosition, worldNormal, noiseTexture, 1.0F / 128.0F); - float alpha = step(noise.r, dissolveFactor); - fragColor = vec4(vec3(0.1, 0.5, 1.0) * 4, alpha); -} \ No newline at end of file + float noise = valueNoise(worldPosition / 16.0 + worldNormal * 2.0); + float alpha = step(noise, dissolveFactor); + vec3 collapseColor = vec3(0.1, 0.5, 1.0) * 4.0; + fragColor = sceneColor + vec4(collapseColor * alpha, 0.0); +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh b/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh index 04a71738..1be35d54 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color/colorful.fsh @@ -3,9 +3,17 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float brightness = 1.0; -uniform float saturation = 1.0; -uniform float contrast = 1.0; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define brightness MatrixPostData0.x +#define saturation MatrixPostData0.y +#define contrast MatrixPostData0.z out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { vec3 saturationColor = mix(intensityColor, brightnessColor, saturation); vec3 contrastColor = mix(color.rgb, saturationColor, contrast); fragColor = vec4(contrastColor, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh b/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh index 3dfca79b..7d27cd10 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color_filter.fsh @@ -3,11 +3,19 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define color MatrixPostData0 out vec4 fragColor; void main() { vec4 framebufferColor = texture(framebuffer, fragTexCoord); fragColor = framebufferColor * color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh b/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh index 9b4fb916..310e7373 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/color_fusion.fsh @@ -5,7 +5,14 @@ in vec2 fragTexCoord; uniform sampler2D primaryFramebuffer; uniform sampler2D secondaryFramebuffer; -uniform vec4 colorMultiplier = vec4(1.0, 1.0, 1.0, 1.0); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define colorMultiplier MatrixPostData0 out vec4 fragColor; @@ -16,4 +23,4 @@ void main() { // float alpha = (primaryFramebufferColor.a + secondaryFramebufferColor.a) / 2; fragColor = (primaryFramebufferColor + secondaryFramebufferColor) * colorMultiplier; // fragColor.a = alpha; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/dissolve/dissolve.fsh b/common/src/main/resources/assets/matrix/shaders/post/dissolve/dissolve.fsh index f7338b0b..12a51f37 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/dissolve/dissolve.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/dissolve/dissolve.fsh @@ -1,14 +1,21 @@ #version 410 core uniform sampler2D noiseTexture; -uniform float dissolveFactor = 0.5; -uniform float emissiveRange = 0.05; -uniform vec4 emissiveColor = vec4(0.1, 0.5, 1.0, 1.0); -uniform float emissiveStrength = 15.0; -uniform float pixelStrength = 16.0; -uniform float detialStrength = 1; -uniform float time; -uniform vec2 resolution = vec2(1.0, 1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 dissolveParams0; + vec4 dissolveParams1; + vec4 dissolveEmissiveColor; +}; + +#define dissolveFactor dissolveParams0.x +#define emissiveRange dissolveParams0.y +#define emissiveStrength dissolveParams0.z +#define pixelStrength dissolveParams0.w +#define detialStrength dissolveParams1.x +#define time dissolveParams1.y +#define resolution dissolveParams1.zw +#define emissiveColor dissolveEmissiveColor layout (location = 0) out vec4 fragColor; @@ -37,14 +44,14 @@ float border() { return (normalColor.b - offsetColor.b) * detialStrength; } -float clamp(float minValue, float maxValue, float value) { +float clampRange(float minValue, float maxValue, float value) { return min(max(value, minValue), maxValue); } void main() { fragColor = vertexColor; - float opacityMask = clamp(0, 1, pixelColor() - pixelAnimation()); + float opacityMask = clampRange(0.0, 1.0, pixelColor() - pixelAnimation()); fragColor.a *= ceil(opacityMask); fragColor.rgb = pow(1 - opacityMask, 10) * (emissiveColor.rgb * emissiveStrength); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_dissolve.fsh b/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_dissolve.fsh index 25dd99e7..29ced1cc 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_dissolve.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_dissolve.fsh @@ -4,11 +4,17 @@ layout (location = 0) in vec2 fragTexCoord; uniform sampler2D noiseTexture; uniform sampler2D colorAttachment; -uniform float dissolveFactor = 0.5; -uniform float emissiveRange = 0.05; -uniform vec4 emissiveColor = vec4(0, 0.5, 1.0, 1.0); -uniform float pixelStrength = 16.0; -uniform float detialStrength = 1; + +layout(std140) uniform MatrixPostUniforms { + vec4 dissolveParams0; + vec4 dissolveEmissiveColor; +}; + +#define dissolveFactor dissolveParams0.x +#define emissiveRange dissolveParams0.y +#define pixelStrength dissolveParams0.z +#define detialStrength dissolveParams0.w +#define emissiveColor dissolveEmissiveColor out vec4 fragColor; @@ -32,14 +38,14 @@ float border() { return (normalColor.b - offsetColor.b) * detialStrength; } -float clamp(float minValue, float maxValue, float value) { +float clampRange(float minValue, float maxValue, float value) { return min(max(value, minValue), maxValue); } void main() { fragColor = texture(colorAttachment, texCoord()); - float opacityMask = clamp(0, 1, (pixelColor() + border()) - pixelAnimation()); + float opacityMask = clampRange(0.0, 1.0, (pixelColor() + border()) - pixelAnimation()); fragColor.a *= ceil(opacityMask); fragColor.rgb = pow(1 - opacityMask, 10) * emissiveColor.rgb; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_pixel_dissolve.fsh b/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_pixel_dissolve.fsh new file mode 100644 index 00000000..89e80775 --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/post/dissolve/texture_pixel_dissolve.fsh @@ -0,0 +1,54 @@ +#version 330 core + +in vec2 fragTexCoord; + +uniform sampler2D noiseTexture; +uniform sampler2D normalTexture; + +layout(std140) uniform MatrixPostUniforms { + vec4 dissolveParams0; + vec4 dissolveEmissiveColor; +}; + +#define dissolveFactor dissolveParams0.x +#define emissiveRange dissolveParams0.y +#define pixelStrength dissolveParams0.z +#define detialStrength dissolveParams0.w +#define emissiveColor dissolveEmissiveColor + +out vec4 fragColor; + +vec2 texCoord() { + return fragTexCoord; +} + +float pixelColor() { + vec2 pixelTexCoord = ceil(texCoord() * pixelStrength) / pixelStrength; + return texture(noiseTexture, pixelTexCoord).b; +} + +float pixelAnimation() { + float pixelNoise = ceil(texCoord().x * pixelStrength) / pixelStrength; + return pixelNoise - mix(-1.5, 1.5, 1.0 - dissolveFactor); +} + +float border() { + vec4 normalColor = texture(noiseTexture, ceil(texCoord() * pixelStrength) / pixelStrength); + vec4 offsetColor = texture(noiseTexture, ceil((texCoord() + 0.01) * pixelStrength) / pixelStrength); + return (normalColor.b - offsetColor.b) * detialStrength; +} + +float clampRange(float minValue, float maxValue, float value) { + return min(max(value, minValue), maxValue); +} + +void main() { + fragColor = texture(normalTexture, fragTexCoord); + if (fragColor.a < 0.1) { + discard; + } + + float opacityMask = clampRange(0.0, 1.0, (pixelColor() + border()) - pixelAnimation()); + fragColor.a *= ceil(opacityMask); + fragColor.rgb = pow(1.0 - opacityMask, 10.0) * emissiveColor.rgb; +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh b/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh index 421f24cf..f7b6a2f2 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/edge_highlight.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float edgeThreshold = 0.5; -uniform vec4 edgeColor = vec4(1.0, 1.0, .0, 1.0); + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define edgeThreshold MatrixPostData0.x +#define edgeColor MatrixPostData1 out vec4 fragColor; diff --git a/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh b/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh index ba357f7a..8e0a571c 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/ghost.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float strength; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define strength MatrixPostData0.x out vec4 fragColor; @@ -30,4 +38,4 @@ void main() { float blendFactor = smoothstep(0.0, 1.0, length(centeredTexCoord) * strength * 2.0); fragColor = mix(original, blurColor, blendFactor); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh b/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh index 676d8ebc..7dafed79 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/hud/progress_ring.fsh @@ -2,18 +2,29 @@ in vec2 fragTexCoord; -uniform float progress = 1.0; -uniform float radius = 0.5; -uniform float thickness = 0.1; -uniform vec2 center = vec2(0.5, 0.5); -uniform vec4 color = vec4(1.0); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define progress MatrixPostData0.x +#define radius MatrixPostData0.y +#define thickness MatrixPostData0.z +#define aspectRatio MatrixPostData0.w +#define center MatrixPostData1.xy +#define color MatrixPostData2 out vec4 fragColor; #define PI 3.141592653589793 void main() { - vec2 direction = fragTexCoord - center; + // Height-normalized space: the fullscreen pass' texcoords are anisotropic, so scale + // the x distance by the aspect ratio to keep the ring circular (radius/thickness are + // height-normalized at the call site). + vec2 direction = (fragTexCoord - center) * vec2(aspectRatio, 1.0); float distance = length(direction); if (distance < radius - thickness || distance > radius) { discard; @@ -31,7 +42,7 @@ void main() { float end = start - sweep; bool inRange; - if (end < .0) { + if (end < 0.0) { inRange = angle <= start && angle >= 0.0 || angle >= end + 2.0 * PI && angle <= 2.0 * PI; } else { inRange = angle <= start && angle >= end; @@ -41,4 +52,4 @@ void main() { discard; } fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh index 4a10e49f..93148e53 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/lower_sampling/lod.fsh @@ -3,10 +3,18 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float levelOfDetail; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define levelOfDetail MatrixPostData0.x out vec4 fragColor; void main() { fragColor = textureLod(framebuffer, fragTexCoord, levelOfDetail); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/opacity_mask.fsh b/common/src/main/resources/assets/matrix/shaders/post/opacity_mask.fsh index 33f29624..5e1cd47c 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/opacity_mask.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/opacity_mask.fsh @@ -9,7 +9,7 @@ out vec4 fragColor; void main() { vec4 opacity = texture(opacityMask, fragTexCoord); - if (opacity.a == .0) { + if (opacity.a == 0.0) { discard; } fragColor = texture(colorAttachment, fragTexCoord); diff --git a/common/src/main/resources/assets/matrix/shaders/post/refraction/refraction.fsh b/common/src/main/resources/assets/matrix/shaders/post/refraction/refraction.fsh deleted file mode 100644 index 11e805d4..00000000 --- a/common/src/main/resources/assets/matrix/shaders/post/refraction/refraction.fsh +++ /dev/null @@ -1,7 +0,0 @@ -#version 330 core - -in vec2 fragTexCoord; - - - -out vec4 fragColor; \ No newline at end of file diff --git a/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh b/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh index 60e34560..671b35cc 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sampling/bilinear.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform vec2 sourceResolution; -uniform vec2 targetResolution; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define sourceResolution MatrixPostData0.xy +#define targetResolution MatrixPostData0.zw out vec4 fragColor; @@ -20,4 +28,4 @@ void main() { color /= 4; fragColor = color; -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh index 1f6a8c15..0ff36c8e 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/drop_shadow.fsh @@ -4,9 +4,16 @@ in vec2 fragTexCoord; uniform sampler2D signedDistanceField; -uniform vec2 shadowOffset = vec2(0.0, 0.0); -uniform float shadowSize = 8.0; -uniform vec4 shadowColor = vec4(0.0, 0.0, 0.0, 0.5); +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define shadowOffset MatrixPostData0.xy +#define shadowSize MatrixPostData0.z +#define shadowColor MatrixPostData1 out vec4 fragColor; @@ -23,4 +30,4 @@ void main() { float alpha = smoothstep(shadowSize, 0.0, denormalizedDist); fragColor = vec4(shadowColor.rgb, shadowColor.a * alpha); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh index 70733d9d..877c947b 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/jump_flooding.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float stepSize; + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define stepSize MatrixPostData0.x out vec4 fragColor; @@ -27,4 +35,4 @@ void main() { } fragColor = vec4(bestPos, 0.0, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/sdf_eval.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/sdf_eval.fsh index 85c1bd4a..c40e74d5 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/sdf_eval.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/sdf_eval.fsh @@ -13,7 +13,7 @@ void main() { float maxDistance = length(resolution); float dist = length((fragTexCoord - nearest) * resolution) / maxDistance; vec4 color = texture(originFramebuffer, fragTexCoord); - if (color.a != .0) { + if (color.a != 0.0) { dist = -dist; } diff --git a/common/src/main/resources/assets/matrix/shaders/post/sdf/seed_gen.fsh b/common/src/main/resources/assets/matrix/shaders/post/sdf/seed_gen.fsh index b6b5c1ad..34350a91 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/sdf/seed_gen.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/sdf/seed_gen.fsh @@ -8,7 +8,7 @@ out vec4 fragColor; void main() { vec4 color = texture(framebuffer, fragTexCoord); - if (color.a != .0) { + if (color.a != 0.0) { fragColor = vec4(fragTexCoord, 0.0, 1.0); } else { fragColor = vec4(-1.0, -1.0, 0.0, 0.0); diff --git a/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh b/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh index f2c36823..2308b088 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/shockwave.fsh @@ -2,15 +2,21 @@ in vec2 fragTexCoord; +uniform sampler2D framebuffer; uniform sampler2D depthAttachment; -uniform mat4 inverseViewMatrix; -uniform mat4 inverseProjectionMatrix; -// User uniforms -uniform vec3 wavePosition; -uniform vec4 waveColor; -uniform float waveSize; -uniform float waveRadius; +layout(std140) uniform MatrixPostUniforms { + mat4 inverseProjectionMatrix; + mat4 inverseViewMatrix; + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; +}; + +#define wavePosition MatrixPostData0.xyz +#define waveRadius MatrixPostData0.w +#define waveColor MatrixPostData1 +#define waveSize MatrixPostData2.x out vec4 fragColor; @@ -18,7 +24,9 @@ vec3 worldAbsolutePosition(vec2 uv, float depth) { // Convert UV coordinates and depth to clip space coordinates. // UV is mapped from [0,1] to [-1,1]. // Depth is mapped from [0,1] (typically from a depth texture or depth buffer) to [-1,1] (clip space z). - vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); // Convert clip space coordinates to view space coordinates. // inverse projection matrix handles the perspective projection, bu the result is still a homogeneous coordinate. @@ -42,11 +50,12 @@ vec3 worldAbsolutePosition(vec2 uv, float depth) { } void main() { + vec4 sceneColor = texture(framebuffer, fragTexCoord); float depth = texture(depthAttachment, fragTexCoord).r; vec3 worldPosition = worldAbsolutePosition(fragTexCoord, depth); float dist = length(worldPosition - wavePosition); // dist > waveRadius && dist < (waveRadius + waveSize) float insideWave = step(waveRadius, dist) * step(dist, waveRadius + waveSize); - fragColor = mix(vec4(0.0), waveColor, insideWave); -} \ No newline at end of file + fragColor = sceneColor + waveColor * insideWave; +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh b/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh index c807d6a0..56c1aaa7 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/the_world.fsh @@ -3,7 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D framebuffer; -uniform float grayscaleIntensity = 0.0; + +layout (std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define grayscaleIntensity MatrixPostData0.x out vec4 fragColor; @@ -12,4 +20,4 @@ void main() { float grayscale = dot(framebufferColor.rgb, vec3(0.299, 0.587, 0.114)); vec3 color = mix(framebufferColor.rgb, vec3(grayscale), grayscaleIntensity); fragColor = vec4(color, framebufferColor.a); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh b/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh index cfe8d465..3655283e 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/tone_mapping/aces_filmic.fsh @@ -3,8 +3,16 @@ in vec2 fragTexCoord; uniform sampler2D hdrScene; -uniform float exposure = 1.0; // Set from application. Interpreted as linear scale. -uniform float exposureEv = 0; // Optional: exposure in EV. If unused, set to 0. + +layout(std140) uniform MatrixPostUniforms { + vec4 MatrixPostData0; + vec4 MatrixPostData1; + vec4 MatrixPostData2; + vec4 MatrixPostData3; +}; + +#define exposure MatrixPostData0.x +#define exposureEv MatrixPostData0.y out vec4 fragColor; @@ -58,4 +66,4 @@ void main() { vec3 srgbColor = convertLinearToSrgb(mappedLinear); fragColor = vec4(srgbColor, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/velocity_map/velocity_map.fsh b/common/src/main/resources/assets/matrix/shaders/post/velocity_map/velocity_map.fsh index 28e76915..46b4a3ea 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/velocity_map/velocity_map.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/velocity_map/velocity_map.fsh @@ -9,5 +9,5 @@ void main() { vec2 currentNDC = currentClipPosition.xy / currentClipPosition.w; vec2 previousNDC = previousClipPosition.xy / previousClipPosition.w; vec2 velocity = currentNDC - previousNDC; - fragColor = vec4(velocity, .0, 1.0); + fragColor = vec4(velocity, 0.0, 1.0); } \ No newline at end of file diff --git a/common/src/main/resources/assets/matrix/shaders/post/volume_distortion.fsh b/common/src/main/resources/assets/matrix/shaders/post/volume_distortion.fsh new file mode 100644 index 00000000..429a4af4 --- /dev/null +++ b/common/src/main/resources/assets/matrix/shaders/post/volume_distortion.fsh @@ -0,0 +1,152 @@ +#version 330 core + +in vec2 fragTexCoord; + +uniform sampler2D sceneColorTexture; +uniform sampler2D depthAttachment; + +layout(std140) uniform MatrixPostUniforms { + mat4 inverseViewMatrix; + mat4 inverseProjectionMatrix; + vec4 volumeParams0; + vec4 volumeParams1; +}; + +#define volumePosition volumeParams0.xyz +#define volumeRadius volumeParams0.w +#define grayscaleIntensity volumeParams1.x +#define emissiveStrength volumeParams1.y + +out vec4 fragColor; + +vec3 computeCameraWorldPosition() +{ + return inverseViewMatrix[3].xyz; +} + +vec3 worldAbsolutePosition(vec2 uv, float depth) +{ + // 26.2 renders with zero-to-one depth on both backends (glClipControl GL_ZERO_TO_ONE / + // Vulkan native); the inverse projection encodes that convention, so use depth directly. + vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, depth, 1.0); + vec4 viewSpacePosition = inverseProjectionMatrix * clipSpacePosition; + vec3 nonHomogeneousViewSpacePosition = viewSpacePosition.xyz / viewSpacePosition.w; + vec4 worldSpacePosition = inverseViewMatrix * vec4(nonHomogeneousViewSpacePosition, 1.0); + return worldSpacePosition.xyz / worldSpacePosition.w; +} + +vec3 computeViewRayDirectionWorld(vec2 uv) +{ + float depth = texture(depthAttachment, uv).r; + vec3 worldPosition = worldAbsolutePosition(uv, depth); + return normalize(worldPosition - computeCameraWorldPosition()); +} + +bool computeRaySphereIntersectionInterval( + vec3 rayOriginWorldPosition, + vec3 rayDirectionWorld, + vec3 sphereCenterWorldPosition, + float sphereRadiusWorldUnits, + out float enterDistanceWorldUnits, + out float exitDistanceWorldUnits +) { + vec3 originToSphereCenter = rayOriginWorldPosition - sphereCenterWorldPosition; + float projectionLength = dot(originToSphereCenter, rayDirectionWorld); + float originToCenterDistanceSquared = dot(originToSphereCenter, originToSphereCenter); + float discriminant = projectionLength * projectionLength - (originToCenterDistanceSquared - sphereRadiusWorldUnits * sphereRadiusWorldUnits); + if (discriminant < 0.0) { + return false; + } + float sqrtDiscriminant = sqrt(discriminant); + float firstIntersection = -projectionLength - sqrtDiscriminant; + float secondIntersection = -projectionLength + sqrtDiscriminant; + enterDistanceWorldUnits = min(firstIntersection, secondIntersection); + exitDistanceWorldUnits = max(firstIntersection, secondIntersection); + return exitDistanceWorldUnits >= 0.0; +} + +float computeSceneDepthDistanceWorldUnits(vec2 uv, vec3 cameraPosition) +{ + float depth = texture(depthAttachment, uv).r; + vec3 sceneWorldPosition = worldAbsolutePosition(uv, depth); + return length(sceneWorldPosition - cameraPosition); +} + +vec3 computeGrayscaleColor(vec3 colorRgb) +{ + float grayscale = dot(colorRgb, vec3(0.299, 0.587, 0.114)); + return vec3(grayscale); +} + +vec3 remapColorToFixedBrightness(vec3 colorRgb, float targetBrightness) +{ + float currentBrightness = dot(colorRgb, vec3(0.2126, 0.7152, 0.0722)); + float safeBrightness = max(currentBrightness, 1e-4); + float brightnessScale = targetBrightness / safeBrightness; + return colorRgb * brightnessScale; +} + +float computeSphereEdgeGlowFactorFromSilhouette(float silhouetteSignedDistanceWorldUnits, float edgeWidthWorldUnits) +{ + return 1.0 - smoothstep(0.0, edgeWidthWorldUnits, -silhouetteSignedDistanceWorldUnits); +} + +float computeSphereSilhouetteSignedDistanceWorldUnits( + vec3 cameraWorldPosition, + vec3 viewRayDirectionWorld, + vec3 sphereCenterWorldPosition, + float sphereRadiusWorldUnits +) +{ + vec3 cameraToSphereCenter = sphereCenterWorldPosition - cameraWorldPosition; + float cameraToCenterDistance = length(cameraToSphereCenter); + vec3 cameraToCenterDirection = cameraToSphereCenter / cameraToCenterDistance; + + float perpendicularDistanceToRay = length(cross(viewRayDirectionWorld, cameraToCenterDirection)) * cameraToCenterDistance; + return perpendicularDistanceToRay - sphereRadiusWorldUnits; +} + +void main() +{ + vec3 cameraPosition = computeCameraWorldPosition(); + vec3 viewRayDirection = computeViewRayDirectionWorld(fragTexCoord); + + float enterDistance; + float exitDistance; + + bool intersectsSphere = computeRaySphereIntersectionInterval( + cameraPosition, + viewRayDirection, + volumePosition, + volumeRadius, + enterDistance, + exitDistance + ); + + float sceneDepthDistance = computeSceneDepthDistanceWorldUnits(fragTexCoord, cameraPosition); + float visibleMask = intersectsSphere && exitDistance > 0.0 && enterDistance < sceneDepthDistance ? 1.0 : 0.0; + float visibleEnterDistance = max(enterDistance, 0.0); + float travelDistanceWorldUnits = max(0.0, exitDistance - visibleEnterDistance); + float volumeDensity = (1.0 - exp(-travelDistanceWorldUnits * 0.6)) * visibleMask; + + vec4 originalColor = texture(sceneColorTexture, fragTexCoord); + + float silhouetteSignedDistanceWorldUnits = computeSphereSilhouetteSignedDistanceWorldUnits( + cameraPosition, + viewRayDirection, + volumePosition, + volumeRadius + ); + + float edgeGlowFactor = computeSphereEdgeGlowFactorFromSilhouette( + silhouetteSignedDistanceWorldUnits, + volumeRadius * 0.01 + ) * visibleMask; + vec3 edgeEnhancedColor = remapColorToFixedBrightness(originalColor.rgb, edgeGlowFactor * emissiveStrength); + + vec3 grayscaleColor = computeGrayscaleColor(originalColor.rgb); + vec3 colorWithInnerGrayscale = mix(originalColor.rgb, grayscaleColor, volumeDensity * grayscaleIntensity); + vec3 finalColorRgb = mix(colorWithInnerGrayscale, edgeEnhancedColor, edgeGlowFactor); + + fragColor = vec4(finalColorRgb, originalColor.a); +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/vortex/inverse_vortex.fsh b/common/src/main/resources/assets/matrix/shaders/post/vortex/inverse_vortex.fsh index fb70823b..b1286344 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/vortex/inverse_vortex.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/vortex/inverse_vortex.fsh @@ -3,10 +3,15 @@ in vec2 fragTexCoord; uniform sampler2D noiseTexture; -uniform float time; -uniform float innerRadius = 0.8; -uniform float outerRadius = 0.9; -uniform float feather = 0.02; + +layout(std140) uniform MatrixPostUniforms { + vec4 vortexParams; +}; + +#define time vortexParams.x +#define innerRadius vortexParams.y +#define outerRadius vortexParams.z +#define feather vortexParams.w out vec4 fragColor; @@ -88,8 +93,8 @@ void main() { float ringMask = smoothstep(gradientInner - feather, gradientInner + feather, blendedTex.r) - smoothstep(gradientOuter - feather, gradientOuter + feather, blendedTex.r); float opacityMask = radialGradientExponential(fragTexCoord, vec2(0.5), 0.4, 1.0, false); float alpha = 1.0 - step(blendedTex.r, gradientInner) + ringMask * opacityMask; - if (alpha == .0) { + if (alpha == 0.0) { discard; } fragColor = vec4(ringMask, ringMask, ringMask, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/shaders/post/vortex/vortex.fsh b/common/src/main/resources/assets/matrix/shaders/post/vortex/vortex.fsh index 6d12e00b..74bb7401 100644 --- a/common/src/main/resources/assets/matrix/shaders/post/vortex/vortex.fsh +++ b/common/src/main/resources/assets/matrix/shaders/post/vortex/vortex.fsh @@ -3,9 +3,14 @@ in vec2 fragTexCoord; uniform sampler2D noiseTexture; -uniform float time; -uniform float innerRadius = 0.4; -uniform float outerRadius = 0.5; + +layout(std140) uniform MatrixPostUniforms { + vec4 vortexParams; +}; + +#define time vortexParams.x +#define innerRadius vortexParams.y +#define outerRadius vortexParams.z out vec4 fragColor; @@ -87,8 +92,8 @@ void main() { float ringMask = step(blendedTex.r, gradientOuter) - step(blendedTex.r, gradientInner); float opacityMask = radialGradientExponential(fragTexCoord, vec2(0.5), 0.4, 1.0, false); float alpha = step(blendedTex.r, gradientInner) + ringMask * opacityMask; - if (alpha == .0) { + if (alpha == 0.0) { discard; } fragColor = vec4(ringMask, ringMask, ringMask, 1.0); -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/coal.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/coal.png new file mode 100644 index 00000000..516dcf52 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/coal.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/emerald.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/emerald.png new file mode 100644 index 00000000..1ca03356 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/emerald.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/lapis_lazuli.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/lapis_lazuli.png new file mode 100644 index 00000000..96d5fdf9 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/lapis_lazuli.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/redstone.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/redstone.png new file mode 100644 index 00000000..aa845a16 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/redstone.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/stone.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/stone.png new file mode 100644 index 00000000..f30e0e6f Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/stone.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/warden.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/warden.png new file mode 100644 index 00000000..11c961e8 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/warden.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wizard.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wizard.png new file mode 100644 index 00000000..5e4988e6 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wizard.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wooden.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wooden.png new file mode 100644 index 00000000..5a0c7d3a Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid/wooden.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/coal.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/coal.png new file mode 100644 index 00000000..b760914a Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/coal.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/emerald.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/emerald.png new file mode 100644 index 00000000..36b70366 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/emerald.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/lapis_lazuli.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/lapis_lazuli.png new file mode 100644 index 00000000..25abd4ac Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/lapis_lazuli.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/redstone.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/redstone.png new file mode 100644 index 00000000..7c99ff47 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/redstone.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/stone.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/stone.png new file mode 100644 index 00000000..18277267 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/stone.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/warden.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/warden.png new file mode 100644 index 00000000..526c7be1 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/warden.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wizard.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wizard.png new file mode 100644 index 00000000..5e4988e6 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wizard.png differ diff --git a/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wooden.png b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wooden.png new file mode 100644 index 00000000..ade80ef1 Binary files /dev/null and b/common/src/main/resources/assets/matrix/textures/entity/equipment/humanoid_leggings/wooden.png differ diff --git a/common/src/main/resources/fabric.mod.json b/common/src/main/resources/fabric.mod.json index 85759104..b7c122a2 100644 --- a/common/src/main/resources/fabric.mod.json +++ b/common/src/main/resources/fabric.mod.json @@ -14,7 +14,7 @@ "license": "CC0-1.0", "icon": "assets/matrix/icon.png", "environment": "*", - "accessWidener": "matrix.accesswidener", + "classTweaker": "matrix.classtweaker", "entrypoints": { "main": [ { @@ -30,7 +30,7 @@ ], "fabric-datagen": [ { - "value": "ModDataGenerator", + "value": "heckerpowered.matrix.ModDataGenerator", "adapter": "kotlin" } ] @@ -39,9 +39,9 @@ "matrix.mixins.json" ], "depends": { - "fabricloader": ">=0.15.7", - "minecraft": "~1.21", - "java": ">=21", + "fabricloader": ">=0.19.2", + "minecraft": "~26.2-", + "java": ">=25", "fabric-api": "*", "fabric-language-kotlin": ">=1.9.22" }, diff --git a/common/src/main/resources/matrix.classtweaker b/common/src/main/resources/matrix.classtweaker index b26561dc..9346cdef 100644 --- a/common/src/main/resources/matrix.classtweaker +++ b/common/src/main/resources/matrix.classtweaker @@ -1,43 +1,22 @@ classTweaker v1 official -# ServerTimeRatio.kt -accessible field net/minecraft/server/MinecraftServer waitingForNextTick Z -accessible field net/minecraft/server/MinecraftServer nextTickTimeNanos J -accessible field net/minecraft/world/TickRateManager nanosecondsPerTick J -inject-interface net/minecraft/server/MinecraftServer heckerpowered/matrix/extension/MatrixMinecraftServer +# Runtime member access goes through mixin @Accessor/@Invoker interfaces (see +# heckerpowered.matrix.mixin.*Accessor / *Invoker): the tweaker's accessible field/method +# entries widened the DEV jar but did NOT take effect in production (IllegalAccessError on +# first use), so no runtime-load-bearing accessible entries may live here. Interface +# injections and inner-class accessibility (compile-time / mixin-target needs) are fine. +inject-interface net/minecraft/server/MinecraftServer heckerpowered/matrix/extension/MatrixMinecraftServer +inject-interface net/minecraft/client/renderer/state/gui/GuiRenderState heckerpowered/matrix/extension/MatrixGuiRenderState inject-interface net/minecraft/world/entity/LivingEntity heckerpowered/matrix/extension/MatrixLivingEntity inject-interface net/minecraft/world/level/Level heckerpowered/matrix/extension/MatrixLevel +inject-interface net/minecraft/world/damagesource/DamageSource heckerpowered/matrix/extension/MatrixDamageSource -accessible field net/minecraft/world/level/entity/LevelEntityGetterAdapter sectionStorage Lnet/minecraft/world/level/entity/EntitySectionStorage; -accessible field net/minecraft/world/level/entity/EntitySectionStorage sectionIds Lit/unimi/dsi/fastutil/longs/LongSortedSet; -accessible field net/minecraft/world/level/entity/EntitySection storage Lnet/minecraft/util/ClassInstanceMultiMap; - -accessible method net/minecraft/world/entity/Entity isInvulnerableToBase (Lnet/minecraft/world/damagesource/DamageSource;)Z - -#accessible field net/minecraft/client/MinecraftClient renderTickCounter Lnet/minecraft/client/render/RenderTickCounter$Dynamic; -#accessible field net/minecraft/client/render/RenderTickCounter$Dynamic tickTime F -#accessible field net/minecraft/client/render/RenderTickCounter$Dynamic tickDelta F -#mutable field net/minecraft/client/render/RenderTickCounter$Dynamic tickTime F -#accessible method net/minecraft/client/gl/Framebuffer drawInternal (IIZ)V -accessible field net/minecraft/world/entity/Mob targetSelector Lnet/minecraft/world/entity/ai/goal/GoalSelector; -#accessible field net/minecraft/entity/passive/VillagerEntity gossip Lnet/minecraft/village/VillagerGossips; -#accessible field net/minecraft/entity/LivingEntity itemUseTimeLeft I -accessible field net/minecraft/world/entity/LivingEntity attackStrengthTicker I -#accessible method net/minecraft/client/render/GameRenderer updateFovMultiplier ()V -#accessible method net/minecraft/client/render/GameRenderer getFov (Lnet/minecraft/client/render/Camera;FZ)D -#accessible method net/minecraft/client/MinecraftClient handleInputEvents ()V -accessible method net/minecraft/world/entity/LivingEntity internalSetAbsorptionAmount (F)V -accessible method net/minecraft/world/entity/player/Player internalSetAbsorptionAmount (F)V -#accessible class net/minecraft/client/gui/hud/InGameHud$HeartType -#accessible class net/minecraft/entity/mob/SpellcastingIllagerEntity$CastSpellGoal -#accessible method net/minecraft/entity/mob/SpellcastingIllagerEntity$CastSpellGoal castSpell ()V -#accessible class net/minecraft/entity/mob/GuardianEntity$FireBeamGoal -#accessible method net/minecraft/world/World getEntityLookup ()Lnet/minecraft/world/entity/EntityLookup; - -accessible field net/minecraft/world/entity/LivingEntity lastHurtByPlayer Lnet/minecraft/world/entity/EntityReference; -accessible field net/minecraft/world/entity/LivingEntity lastHurtByPlayerMemoryTime I - -accessible field net/minecraft/world/entity/ai/Brain memories Ljava/util/Map; +# Inner-class visibility for mixin targets / compile-time references. +accessible class net/minecraft/client/gui/Hud$HeartType +accessible class net/minecraft/world/entity/monster/illager/SpellcasterIllager$SpellcasterUseSpellGoal +accessible class net/minecraft/world/entity/monster/Guardian$GuardianAttackGoal -inject-interface net/minecraft/world/damagesource/DamageSource heckerpowered/matrix/extension/MatrixDamageSource \ No newline at end of file +# Compile-time only: CastSpellGoalMixin's redirect body is merged INTO +# SpellcasterUseSpellGoal, so the call is self-access at runtime. +accessible method net/minecraft/world/entity/monster/illager/SpellcasterIllager$SpellcasterUseSpellGoal performSpellCasting ()V diff --git a/common/src/main/resources/matrix.mixins.json b/common/src/main/resources/matrix.mixins.json index 2f57e2da..66e91942 100644 --- a/common/src/main/resources/matrix.mixins.json +++ b/common/src/main/resources/matrix.mixins.json @@ -3,37 +3,48 @@ "package": "heckerpowered.matrix.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ + "BrainAccessor", "CastSpellGoalMixin", "DamageSourceMixin", "ElderGuardianEntityMixin", "EndermanEntityMixin", + "EntityInvoker", "EntityMixin", + "EntitySectionAccessor", + "EntitySectionStorageAccessor", "EntityTrackerEntryMixin", "FireBeamGoalMixin", "ItemStackMixin", + "LevelEntityGetterAdapterAccessor", "LevelMixin", + "LivingEntityAccessor", "LivingEntityMixin", + "MinecraftServerAccessor", "MinecraftServerMixin", - "PlayerEntityMixin", + "MobAccessor", "PlayerMixin", "ServerCommonNetworkHandlerMixin", "ServerPlayerEntityMixin", "ServerPlayNetworkHandlerMixin", "SonicBoomTaskMixin", "TargetPredicateMixin", + "TickRateManagerAccessor", "TridentEntityMixin", "TridentItemMixin", - "WitchEntityMixin", - "WorldMixin" + "WitchEntityMixin" ], "client": [ + "CameraMixin", "FramebufferMixin", "GameRendererMixin", "KeyboardMixin", "MinecraftClientMixin", "MixinInGameHud", "MouseMixin", - "WorldRendererMixin" + "WorldRendererMixin", + "GuiRenderStateAccessor", + "GuiRenderStateMixin", + "GuiRendererMixin" ], "injectors": { "defaultRequire": 1 @@ -41,4 +52,4 @@ "mixinextras": { "minVersion": "0.5.0" } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index eef9cd2e..94d4bbfb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,10 @@ # SPDX-License-Identifier: MIT # Copyright (c) 2026 heckerpowered # -org.gradle.jvmargs=-Xms1g -Xmx4g -XX:+UseParallelGC +# jdk.net.unixdomain.tmpdir: machine-local workaround, see ~/.gradle/gradle.properties — +# AF_UNIX sockets cannot be created in %TEMP% (blocked by security software), which breaks +# the java.nio Selector/Pipe used by Gradle and the Kotlin daemon. +org.gradle.jvmargs=-Xms1g -Xmx4g -XX:+UseParallelGC -Djdk.net.unixdomain.tmpdir=C:/Users/Zopiclone/.uds-tmp org.gradle.parallel=true org.gradle.daemon=true org.gradle.caching=true @@ -11,14 +14,14 @@ org.gradle.configuration-cache=false org.gradle.vfs.watch=true org.gradle.daemon.idletimeout=900000 # General Properties -minecraftVersion=26.2-snapshot-5 +minecraftVersion=26.2 kotlinVersion=2.3.20 # Fabric Properties # check these on https://fabricmc.net/develop yarnMappings=1.21+build.9 -loaderVersion=0.19.2 +loaderVersion=0.19.3 fabricKotlinVersion=1.13.10+kotlin.2.3.20 -fabricVersion=0.147.1+26.2 +fabricVersion=0.154.0+26.2 loomVersion=1.16-SNAPSHOT # Mod Properties modVersion=1.0.0 diff --git a/ledger/build.gradle.kts b/ledger/build.gradle.kts index f99b1da4..e95e93c7 100644 --- a/ledger/build.gradle.kts +++ b/ledger/build.gradle.kts @@ -19,7 +19,18 @@ dependencies { } kotlin { - jvmToolchain(25) + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_25 + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 +} + +tasks.withType().configureEach { + options.release = 25 } tasks.test { diff --git a/render-hardware-interface/build.gradle.kts b/render-hardware-interface/build.gradle.kts index f99b1da4..e95e93c7 100644 --- a/render-hardware-interface/build.gradle.kts +++ b/render-hardware-interface/build.gradle.kts @@ -19,7 +19,18 @@ dependencies { } kotlin { - jvmToolchain(25) + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_25 + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 +} + +tasks.withType().configureEach { + options.release = 25 } tasks.test {