diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5defad..42a53f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,30 +1,64 @@ -# Automatically build the project and run any configured tests for every push -# and submitted pull request. This can help catch issues that only occur on -# certain platforms or Java versions, and provides a first line of defence -# against bad commits. - name: build -on: [pull_request, push] +on: + push: + branches: + - master + pull_request: + branches: + - master jobs: build: runs-on: ubuntu-24.04 steps: - - name: checkout repository + - name: Checkout Repository uses: actions/checkout@v4 - - name: validate gradle wrapper + + - name: Validate Gradle Wrapper uses: gradle/actions/wrapper-validation@v4 - - name: setup jdk + + - name: Setup JDK uses: actions/setup-java@v4 with: java-version: '21' distribution: 'microsoft' - - name: make gradle wrapper executable + + - name: Make Gradle Wrapper Executable run: chmod +x ./gradlew - - name: build + + - name: Build Jar run: ./gradlew build - - name: capture build artifacts + + - name: Capture Build Artifacts uses: actions/upload-artifact@v4 with: - name: Artifacts - path: build/libs/ + name: mod-jar + path: build/libs/*.jar + + - name: Read gradle.properties Release Flags + id: release_props + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + run: | + SHOULD_RELEASE=$(grep -Po '^shouldRelease=.*' gradle.properties | cut -d= -f2 | xargs) + + if [ "$SHOULD_RELEASE" != "true" ]; then + echo "shouldRelease is false — skipping release" + exit 0 + fi + + MOD_VERSION=$(grep -Po '^modVersion=.*' gradle.properties | cut -d= -f2 | xargs) + + echo "SHOULD_RELEASE=$SHOULD_RELEASE" >> $GITHUB_OUTPUT + echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "MOD_VERSION=$MOD_VERSION" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + if: steps.release_props.outputs.SHOULD_RELEASE == 'true' + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.release_props.outputs.MOD_VERSION }}.${{ steps.release_props.outputs.SHA_SHORT }} + name: Cobalt v${{ steps.release_props.outputs.MOD_VERSION }} + files: build/libs/*.jar + body: ${{ github.event.head_commit.message }} + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/README.md b/README.md index c76728b..64eabfe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

Cobalt

![mod-loader](https://img.shields.io/badge/modloader-Fabric-4682b4?style=for-the-badge&logoColor=white) - ![minecraft-version](https://img.shields.io/badge/Minecraft-1.20.10-6BAA57?style=for-the-badge&logoColor=white) + ![minecraft-version](https://img.shields.io/badge/Minecraft-1.21.10-6BAA57?style=for-the-badge&logoColor=white) ![language](https://img.shields.io/badge/version-1.0.0-FF474C?style=for-the-badge&logoColor=white) diff --git a/build.gradle.kts b/build.gradle.kts index 284563f..b5f3641 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,7 +42,6 @@ dependencies { modImplementation("net.fabricmc.fabric-api:fabric-api:${property("fabric_api_version")}") modRuntimeOnly("me.djtheredstoner:DevAuth-fabric:1.2.1") - runtimeOnly("org.apache.httpcomponents:httpclient:4.5.14") modImplementation("org.lwjgl:lwjgl-nanovg:${lwjglVersion}") include("org.lwjgl:lwjgl-nanovg:${lwjglVersion}") diff --git a/gradle.properties b/gradle.properties index f1f733e..9ee9e0e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,10 +9,10 @@ shouldRelease=true lwjglVersion=3.3.3 # https://fabricmc.net/develop/ -minecraft_version=1.21.11 -loader_version=0.18.4 +minecraft_version=1.21.10 +loader_version=0.17.3 loom_version=1.13-SNAPSHOT -# Fabric API -fabric_api_version=0.141.1+1.21.11 -fabric_kotlin_version=1.13.8+kotlin.2.3.0 +# Dependency Versions +fabric_api_version=0.138.3+1.21.10 +fabric_kotlin_version=1.13.7+kotlin.2.2.21 diff --git a/src/main/java/org/cobalt/mixin/client/AddonList_CrashReportMixin.java b/src/main/java/org/cobalt/mixin/client/AddonList_CrashReportMixin.java index d85bf41..a7fe4ce 100644 --- a/src/main/java/org/cobalt/mixin/client/AddonList_CrashReportMixin.java +++ b/src/main/java/org/cobalt/mixin/client/AddonList_CrashReportMixin.java @@ -14,7 +14,7 @@ @Mixin(CrashReport.class) public abstract class AddonList_CrashReportMixin { - @Inject(method = "getDetails*", at = @At("HEAD")) + @Inject(method = "getDetails(Ljava/lang/StringBuilder;)V", at = @At("HEAD")) private void addAddonInfo(StringBuilder crashReportBuilder, CallbackInfo ci) { String addons = AddonLoader.INSTANCE.getAddons().stream() .map(info -> info.getFirst().getName() + " v" + info.getFirst().getVersion()) diff --git a/src/main/java/org/cobalt/mixin/render/WorldContext_LevelRendererMixin.java b/src/main/java/org/cobalt/mixin/render/WorldContext_LevelRendererMixin.java index 8dea518..925635f 100644 --- a/src/main/java/org/cobalt/mixin/render/WorldContext_LevelRendererMixin.java +++ b/src/main/java/org/cobalt/mixin/render/WorldContext_LevelRendererMixin.java @@ -29,7 +29,6 @@ public class WorldContext_LevelRendererMixin { @Unique private final WorldRenderContext ctx = new WorldRenderContext(); - @Shadow @Final private RenderBuffers renderBuffers; @@ -42,14 +41,9 @@ private void render(GraphicsResourceAllocator allocator, DeltaTracker tickCounte } - @ModifyExpressionValue(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;prepareCullFrustum(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/client/renderer/culling/Frustum;")) - private Frustum onSetupFrustum(Frustum frustum) { - ctx.setFrustum(frustum); - return frustum; - } - @Inject(method = "method_62214", at = @At("RETURN")) - private void postRender(GpuBufferSlice gpuBufferSlice, LevelRenderState levelRenderState, ProfilerFiller profilerFiller, Matrix4f matrix4f, ResourceHandle resourceHandle, ResourceHandle resourceHandle2, boolean bl, ResourceHandle resourceHandle3, ResourceHandle resourceHandle4, CallbackInfo ci) { + private void postRender(GpuBufferSlice gpuBufferSlice, LevelRenderState worldRenderState, ProfilerFiller profiler, Matrix4f matrix4f, ResourceHandle handle, ResourceHandle handle2, boolean bl, Frustum frustum, ResourceHandle handle3, ResourceHandle handle4, CallbackInfo ci) { + ctx.setFrustum(frustum); new WorldRenderEvent.Last(ctx).post(); } diff --git a/src/main/kotlin/org/cobalt/Cobalt.kt b/src/main/kotlin/org/cobalt/Cobalt.kt index 487ec71..fde274b 100644 --- a/src/main/kotlin/org/cobalt/Cobalt.kt +++ b/src/main/kotlin/org/cobalt/Cobalt.kt @@ -25,7 +25,7 @@ object Cobalt : ClientModInitializer { listOf( TickScheduler, MainCommand, NotificationManager, - RotationExecutor + RotationExecutor, ).forEach { EventBus.register(it) } Config.loadModulesConfig() diff --git a/src/main/kotlin/org/cobalt/api/command/CommandManager.kt b/src/main/kotlin/org/cobalt/api/command/CommandManager.kt index 8852c40..24fa915 100644 --- a/src/main/kotlin/org/cobalt/api/command/CommandManager.kt +++ b/src/main/kotlin/org/cobalt/api/command/CommandManager.kt @@ -22,11 +22,11 @@ import org.cobalt.api.command.annotation.SubCommand object CommandManager { - private val commandsList = mutableListOf() + private val commands = mutableListOf() @JvmStatic - fun register(vararg commands: Command) { - commands.forEach(commandsList::add) + fun register(command: Command) { + commands.add(command) } internal fun dispatchAll() { @@ -34,7 +34,7 @@ object CommandManager { } private fun dispatchAll(dispatcher: CommandDispatcher, access: CommandBuildContext) { - commandsList.forEach { command -> + commands.forEach { command -> val rootNames = listOf(command.name) + command.aliases rootNames.forEach { rootName -> diff --git a/src/main/kotlin/org/cobalt/api/util/ChatUtils.kt b/src/main/kotlin/org/cobalt/api/util/ChatUtils.kt index eabf1bf..089f817 100644 --- a/src/main/kotlin/org/cobalt/api/util/ChatUtils.kt +++ b/src/main/kotlin/org/cobalt/api/util/ChatUtils.kt @@ -13,6 +13,9 @@ object ChatUtils { private val mc: Minecraft = Minecraft.getInstance() + // used for sendDebug to prevent resending same message multiple times in a row + private var lastMessage: String = "" + /** * Function to display a message in Minecraft chat with the prefix "[Cobalt Debug]" * @@ -20,10 +23,15 @@ object ChatUtils { */ @JvmStatic fun sendDebug(message: String) { + if (mc.player == null || mc.level == null) return + if (message == lastMessage) return + mc.gui.chat.addMessage( Component.empty().append(debugPrefix) .append(Component.literal("${ChatFormatting.RESET}$message")) ) + + lastMessage = message } /** @@ -33,6 +41,8 @@ object ChatUtils { */ @JvmStatic fun sendMessage(message: String) { + if (mc.player == null || mc.level == null) return + mc.gui.chat.addMessage( Component.empty().append(prefix) .append(Component.literal("${ChatFormatting.RESET}$message")) diff --git a/src/main/kotlin/org/cobalt/api/util/render/Render3D.kt b/src/main/kotlin/org/cobalt/api/util/render/Render3D.kt index 6a1fca5..298cd15 100644 --- a/src/main/kotlin/org/cobalt/api/util/render/Render3D.kt +++ b/src/main/kotlin/org/cobalt/api/util/render/Render3D.kt @@ -1,12 +1,16 @@ package org.cobalt.api.util.render +import com.mojang.blaze3d.systems.RenderSystem import java.awt.Color -import net.minecraft.gizmos.Gizmos -import net.minecraft.gizmos.GizmoStyle -import net.minecraft.util.ARGB +import kotlin.math.max +import kotlin.math.min +import net.minecraft.client.renderer.MultiBufferSource +import net.minecraft.client.renderer.ShapeRenderer import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 import org.cobalt.api.event.impl.render.WorldRenderContext +import org.cobalt.internal.helper.RenderLayers +import org.joml.Vector3f object Render3D { @@ -16,15 +20,38 @@ object Render3D { return } - val strokeColor = ARGB.color(color.alpha, color.red, color.green, color.blue) - val fillColor = ARGB.color(150, color.red, color.green, color.blue) + val matrix = context.matrixStack ?: return + val bufferSource = context.consumers as? MultiBufferSource.BufferSource ?: return - val style = GizmoStyle.strokeAndFill(strokeColor, 2.5f, fillColor) - val props = Gizmos.cuboid(box, style) + val r = color.red / 255f + val g = color.green / 255f + val b = color.blue / 255f - if (esp) { - props.setAlwaysOnTop() - } + val fillLayer = if (esp) RenderLayers.TRIANGLE_STRIP_ESP else RenderLayers.TRIANGLE_STRIP + val lineLayer = if (esp) RenderLayers.LINE_LIST_ESP else RenderLayers.LINE_LIST + + matrix.pushPose() + with(context.camera.position) { matrix.translate(-x, -y, -z) } + + ShapeRenderer.addChainedFilledBoxVertices( + matrix, + bufferSource.getBuffer(fillLayer), + box.minX, box.minY, box.minZ, + box.maxX, box.maxY, box.maxZ, + r, g, b, 150 / 255F + ) + + ShapeRenderer.renderLineBox( + matrix.last(), + bufferSource.getBuffer(lineLayer), + box.minX, box.minY, box.minZ, + box.maxX, box.maxY, box.maxZ, + r, g, b, 1f + ) + + matrix.popPose() + bufferSource.endBatch(fillLayer) + bufferSource.endBatch(lineLayer) } @JvmStatic @@ -38,17 +65,32 @@ object Render3D { ) { if (!FrustumUtils.isVisible( context.frustum, - minOf(start.x, end.x), minOf(start.y, end.y), minOf(start.z, end.z), - maxOf(start.x, end.x), maxOf(start.y, end.y), maxOf(start.z, end.z) + min(start.x, end.x), min(start.y, end.y), min(start.z, end.z), + max(start.x, end.x), max(start.y, end.y), max(start.z, end.z) ) ) return - val argbColor = ARGB.color(color.alpha, color.red, color.green, color.blue) - val props = Gizmos.line(start, end, argbColor, thickness) + val matrix = context.matrixStack ?: return + val bufferSource = context.consumers as? MultiBufferSource.BufferSource ?: return + val layer = if (esp) RenderLayers.LINE_LIST_ESP else RenderLayers.LINE_LIST + RenderSystem.lineWidth(thickness) - if (esp) { - props.setAlwaysOnTop() - } + matrix.pushPose() + with(context.camera.position) { matrix.translate(-x, -y, -z) } + + val startOffset = Vector3f(start.x.toFloat(), start.y.toFloat(), start.z.toFloat()) + val direction = end.subtract(start) + + ShapeRenderer.renderVector( + matrix, + bufferSource.getBuffer(layer), + startOffset, + direction, + color.rgb + ) + + matrix.popPose() + bufferSource.endBatch(layer) } } diff --git a/src/main/kotlin/org/cobalt/internal/helper/RenderLayers.kt b/src/main/kotlin/org/cobalt/internal/helper/RenderLayers.kt new file mode 100644 index 0000000..7c403cb --- /dev/null +++ b/src/main/kotlin/org/cobalt/internal/helper/RenderLayers.kt @@ -0,0 +1,39 @@ +package org.cobalt.internal.helper + +import net.minecraft.client.renderer.RenderStateShard +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.RenderType.CompositeRenderType + +internal object RenderLayers { + + val LINE_LIST: RenderType = RenderType.create( + "line-list", RenderType.TRANSIENT_BUFFER_SIZE, + RenderPipelines.LINE_LIST, + RenderType.CompositeState.builder() + .setLayeringState(RenderStateShard.VIEW_OFFSET_Z_LAYERING) + .createCompositeState(false) + ) + + val LINE_LIST_ESP: RenderType = RenderType.create( + "line-list-esp", RenderType.TRANSIENT_BUFFER_SIZE, + RenderPipelines.LINE_LIST_ESP, + RenderType.CompositeState.builder().createCompositeState(false) + ) + + val TRIANGLE_STRIP: CompositeRenderType = RenderType.create( + "triangle_strip", RenderType.TRANSIENT_BUFFER_SIZE, + false, true, + RenderPipelines.TRIANGLE_STRIP, + RenderType.CompositeState.builder() + .setLayeringState(RenderStateShard.VIEW_OFFSET_Z_LAYERING) + .createCompositeState(false) + ) + + val TRIANGLE_STRIP_ESP: CompositeRenderType = RenderType.create( + "triangle_strip_esp", RenderType.TRANSIENT_BUFFER_SIZE, + false, true, + RenderPipelines.TRIANGLE_STRIP_ESP, + RenderType.CompositeState.builder().createCompositeState(false) + ) + +} diff --git a/src/main/kotlin/org/cobalt/internal/helper/RenderPipelines.kt b/src/main/kotlin/org/cobalt/internal/helper/RenderPipelines.kt new file mode 100644 index 0000000..0da3ce9 --- /dev/null +++ b/src/main/kotlin/org/cobalt/internal/helper/RenderPipelines.kt @@ -0,0 +1,57 @@ +package org.cobalt.internal.helper + +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.platform.DepthTestFunction +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import com.mojang.blaze3d.vertex.VertexFormat.Mode +import net.minecraft.client.renderer.RenderPipelines + +internal object RenderPipelines { + + val LINE_LIST: RenderPipeline = RenderPipelines.register( + RenderPipeline.builder(*arrayOf(RenderPipelines.LINES_SNIPPET)) + .withLocation("pipeline/lines") + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR_NORMAL, Mode.LINES) + .withCull(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(true) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .build() + ) + + val LINE_LIST_ESP: RenderPipeline = RenderPipelines.register( + RenderPipeline.builder(*arrayOf(RenderPipelines.LINES_SNIPPET)) + .withLocation("pipeline/lines") + .withShaderDefine("shad") + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR_NORMAL, Mode.LINES) + .withCull(false) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .build() + ) + + val TRIANGLE_STRIP: RenderPipeline = RenderPipelines.register( + RenderPipeline.builder(*arrayOf(RenderPipelines.DEBUG_FILLED_SNIPPET)) + .withLocation("pipeline/debug_filled_box") + .withCull(false) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, Mode.TRIANGLE_STRIP) + .withDepthWrite(true) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) + .build() + ) + + val TRIANGLE_STRIP_ESP: RenderPipeline = RenderPipelines.register( + RenderPipeline.builder(*arrayOf(RenderPipelines.DEBUG_FILLED_SNIPPET)) + .withLocation("pipeline/debug_filled_box") + .withCull(false) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, Mode.TRIANGLE_STRIP) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) + .build() + ) + +} diff --git a/src/main/kotlin/org/cobalt/internal/loader/AddonLoader.kt b/src/main/kotlin/org/cobalt/internal/loader/AddonLoader.kt index 2503396..fc6603d 100644 --- a/src/main/kotlin/org/cobalt/internal/loader/AddonLoader.kt +++ b/src/main/kotlin/org/cobalt/internal/loader/AddonLoader.kt @@ -52,8 +52,8 @@ object AddonLoader { Files.newDirectoryStream(addonsDir, "*.jar").use { stream -> for (jarPath in stream) { try { - loadAddon(jarPath) FabricLauncherBase.getLauncher().addToClassPath(jarPath) + loadAddon(jarPath) } catch (e: Exception) { e.printStackTrace() } @@ -92,7 +92,7 @@ object AddonLoader { ) } - val instance = Class.forName(entrypoint, true, jarPath.javaClass.classLoader).let { + val instance = Class.forName(entrypoint).let { try { it.getField("INSTANCE").get(null) } catch (_: NoSuchFieldException) { diff --git a/src/main/kotlin/org/cobalt/internal/ui/components/UIAddonEntry.kt b/src/main/kotlin/org/cobalt/internal/ui/components/UIAddonEntry.kt index ee67f21..e0f1b78 100644 --- a/src/main/kotlin/org/cobalt/internal/ui/components/UIAddonEntry.kt +++ b/src/main/kotlin/org/cobalt/internal/ui/components/UIAddonEntry.kt @@ -37,7 +37,7 @@ internal class UIAddonEntry( NVGRenderer.image( addonIcon, x + 20F, y + height / 2F - 15F, 30F, 30F, - colorMask = Color(42, 42, 42).rgb + colorMask = if (addonIcon == boxIcon) Color(42, 42, 42).rgb else 0 ) NVGRenderer.text( diff --git a/src/main/kotlin/org/cobalt/internal/ui/panel/panels/UISidebar.kt b/src/main/kotlin/org/cobalt/internal/ui/panel/panels/UISidebar.kt index f9784d4..6c3a2bc 100644 --- a/src/main/kotlin/org/cobalt/internal/ui/panel/panels/UISidebar.kt +++ b/src/main/kotlin/org/cobalt/internal/ui/panel/panels/UISidebar.kt @@ -24,7 +24,7 @@ internal class UISidebar : UIPanel( private val steveIcon = NVGRenderer.createImage("/assets/cobalt/steve.png") private val userIcon = try { - NVGRenderer.createImage("https://mc-heads.net/avatar/${Minecraft.getInstance().user.profileId}/100/face.png") + NVGRenderer.createImage("https://mc-heads.net/avatar/${Minecraft.getInstance().user.profileId ?: "a"}/100/face.png") } catch (_: Exception) { steveIcon }