diff --git a/README.md b/README.md index 5da7d3e1..a0a303a2 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,29 @@ ![Infinite Client Icon](src/main/resources/assets/infinite/icon.svg) -**Infinite Client** is a simple Minecraft hack client designed for ease of use and a clean interface. +Infinite Client is a Fabric-based Minecraft client focused on a clean UI and lightweight feature set. -## Features +## Highlights +- Clean, simple interface with intuitive controls. +- Core feature categories (movement, rendering, fighting, automatic, server, utils) kept lean. +- Built-in theme system with several presets and easy user customization. -- **Simple Interface** — Clean and easy to navigate. -- **Intuitive Controls** — User-friendly design that’s easy to understand. -- **Minimal Features** — Lightweight with only the essentials (for now :) ). - -## 🌐 Links - -- [GitHub Repositories](https://github.com/Infinite-Client/) -- [Official Homepage](https://infinite-client.infinityon.com/) - ---- - -<<<<<<< HEAD -> **Disclaimer:** This client is intended for educational or personal use. Use it responsibly and follow the rules of the servers you join. -======= -> **Disclaimer:** This client is intended for educational or personal use. Use it responsibly and follow the rules of the servers you join. +## Getting Started +1) Prerequisites: JDK 21 (Adoptium or similar) and Git. +2) Clone: `git clone https://github.com/Infinite-Client/infinite-client.git` +3) Run the client in dev: `./gradlew runClient` +4) Build a mod jar: `./gradlew build` (output in `build/libs`). ## Custom Themes - -- Open in-game: `Options` → `Infinite Client Settings` → **Themes** tab → enable **Theme** and pick from the list. -- Built-in presets include: infinite, SME Clan, Hacker, Pastel, Minecraft, Cyber, plus bundled JSONs (ocean, sunset, modern, neon, forest). -- Add your own by dropping a JSON into `/infinite/themes/` (example files ship in `themes/` and are bundled in the mod). +- In-game: `Options` → `Infinite Client Settings` → `Themes` tab → enable **Theme** and pick from the list. +- Built-in presets: infinite, SME Clan, Hacker, Pastel, Minecraft, Cyber, plus bundled JSONs (ocean, sunset, modern, neon, forest). +- Add your own by placing a JSON in `/infinite/themes/`; sample files live in the repo `themes/` folder. - JSON fields: `name`, `backgroundColor`, `foregroundColor`, `primaryColor`, `secondaryColor`, optional `icon` (`namespace:path`). -- Restart the client to pick new themes from the Theme setting. ->>>>>>> dev/noobyetpro +- Restart the client after adding a theme to load it. + +## Links +- GitHub: https://github.com/Infinite-Client/ +- Homepage: https://infinite-client.infinityon.com/ + +## Disclaimer +This client is intended for educational or personal use. Use it responsibly and respect the rules of any servers you join. diff --git a/build.gradle.kts b/build.gradle.kts index 7f276f46..665a3f37 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,7 +45,8 @@ dependencies { modImplementation("maven.modrinth:modmenu:${property("mod_menu_version")}") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") implementation("dev.babbaj:nether-pathfinder:${property("nether_pathfinder_version")}") - modImplementation("meteordevelopment:baritone:${property("baritone_version")}") + // Keep compile-only so sources still build, but do not ship or run Baritone until 1.21.11 is available. + modCompileOnly("meteordevelopment:baritone:${property("baritone_version")}") implementation("org.lwjgl:lwjgl-stb:${property("lwjgl_version")}") implementation("com.squareup.okhttp3:okhttp:${property("ok_http_version")}") implementation("org.apache.maven:maven-artifact:${property("maven_artifact_version")}") diff --git a/gradle.properties b/gradle.properties index 639b550b..21430a95 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,21 +4,21 @@ org.gradle.parallel=true kotlin.code.style=official # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.10 -yarn_mappings=1.21.10+build.2 +minecraft_version=1.21.11 +yarn_mappings=1.21.11+build.3 loader_version=0.17.3 # Fabric API loomVersion=1.13-SNAPSHOT -fabric_api_version=0.136.0+1.21.10 +fabric_api_version=0.140.2+1.21.11 fabric_kotlin_version=1.13.6+kotlin.2.2.20 # Mod Properties -mod_version=1.21.10-7-beta4 +mod_version=1.21.11-7-beta4 maven_group=org.infinite archives_base_name=infinite # Thank you for meteor! baritone_version=1.21.10-SNAPSHOT nether_pathfinder_version=1.4.1 lwjgl_version=3.3.3 -mod_menu_version=16.0.0-rc.1 +mod_menu_version=17.0.0-beta.1 ok_http_version=5.3.0 -maven_artifact_version=4.0.0-rc-5 \ No newline at end of file +maven_artifact_version=4.0.0-rc-5 diff --git a/src/client/java/org/infinite/libs/graphics/TextRenderState.java b/src/client/java/org/infinite/libs/graphics/TextRenderState.java deleted file mode 100644 index 19138eff..00000000 --- a/src/client/java/org/infinite/libs/graphics/TextRenderState.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.infinite.libs.graphics; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.ScreenRect; -import net.minecraft.client.gui.render.state.GuiElementRenderState; -import net.minecraft.client.gui.render.state.TextGuiElementRenderState; -import net.minecraft.text.OrderedText; -import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2f; - -@Environment(EnvType.CLIENT) -public final class TextRenderState extends TextGuiElementRenderState - implements GuiElementRenderState { - public final TextRenderer textRenderer; - public final OrderedText orderedText; - public final Matrix3x2f matrix; - public final float x; // int から float に変更 - public final float y; // int から float に変更 - public final int color; - public final int backgroundColor; - public final boolean shadow; - @Nullable public final ScreenRect clipBounds; - @Nullable private TextRenderer.GlyphDrawable preparation; - @Nullable private ScreenRect bounds; - - // コンストラクタのシグネチャを変更 - public TextRenderState( - TextRenderer textRenderer, - OrderedText orderedText, - Matrix3x2f matrix, - float x, - float y, - int color, - int backgroundColor, - boolean shadow, - @Nullable ScreenRect clipBounds) { - super( - textRenderer, - orderedText, - matrix, - (int) x, - (int) y, - color, - backgroundColor, - shadow, - clipBounds); - this.textRenderer = textRenderer; - this.orderedText = orderedText; - this.matrix = matrix; - this.x = x; - this.y = y; - this.color = color; - this.backgroundColor = backgroundColor; - this.shadow = shadow; - this.clipBounds = clipBounds; - } - - public TextRenderer.GlyphDrawable prepare() { - if (this.preparation == null) { - // xとyがfloatになったため、キャストを削除 - this.preparation = - this.textRenderer.prepare( - this.orderedText, this.x, this.y, this.color, this.shadow, this.backgroundColor); - ScreenRect screenRect = this.preparation.getScreenRect(); - if (screenRect != null) { - screenRect = screenRect.transformEachVertex(this.matrix); - this.bounds = - this.clipBounds != null ? this.clipBounds.intersection(screenRect) : screenRect; - } - } - - return this.preparation; - } - - @Nullable - public ScreenRect bounds() { - this.prepare(); - return this.bounds; - } -} diff --git a/src/client/java/org/infinite/mixin/features/movement/supersprint/SuperSprintMixin.java b/src/client/java/org/infinite/mixin/features/movement/supersprint/SuperSprintMixin.java index 6ce9c070..7ebd52ef 100644 --- a/src/client/java/org/infinite/mixin/features/movement/supersprint/SuperSprintMixin.java +++ b/src/client/java/org/infinite/mixin/features/movement/supersprint/SuperSprintMixin.java @@ -38,7 +38,7 @@ private boolean wrapHasForwardMovement(Input input, Operation original) } /** This mixin allows AutoSprint to enable sprinting even when the player is too hungry. */ - @Inject(at = @At("HEAD"), method = "canSprint()Z", cancellable = true) + @Inject(at = @At("HEAD"), method = "canSprint", cancellable = true) private void onCanSprint(CallbackInfoReturnable cir) { // Feature: SuperSprint (Setting: EvenIfHungry) if (InfiniteClient.INSTANCE.isSettingEnabled(SuperSprint.class, "EvenIfHungry")) diff --git a/src/client/java/org/infinite/mixin/features/rendering/antioverlay/NoFogMixin.java b/src/client/java/org/infinite/mixin/features/rendering/antioverlay/NoFogMixin.java index b27a12b1..c013cbb8 100644 --- a/src/client/java/org/infinite/mixin/features/rendering/antioverlay/NoFogMixin.java +++ b/src/client/java/org/infinite/mixin/features/rendering/antioverlay/NoFogMixin.java @@ -14,7 +14,7 @@ public class NoFogMixin { @WrapOperation( method = - "applyFog(Lnet/minecraft/client/render/Camera;IZLnet/minecraft/client/render/RenderTickCounter;FLnet/minecraft/client/world/ClientWorld;)Lorg/joml/Vector4f;", + "applyFog(Lnet/minecraft/client/render/Camera;ILnet/minecraft/client/render/RenderTickCounter;FLnet/minecraft/client/world/ClientWorld;)Lorg/joml/Vector4f;", at = @At( value = "INVOKE", diff --git a/src/client/java/org/infinite/mixin/features/rendering/hyperui/CancelRenderWorldMixin.java b/src/client/java/org/infinite/mixin/features/rendering/hyperui/CancelRenderWorldMixin.java index 0752f896..8edba517 100644 --- a/src/client/java/org/infinite/mixin/features/rendering/hyperui/CancelRenderWorldMixin.java +++ b/src/client/java/org/infinite/mixin/features/rendering/hyperui/CancelRenderWorldMixin.java @@ -2,9 +2,11 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.render.Camera; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.state.OutlineRenderState; +import net.minecraft.client.render.state.WorldRenderState; import net.minecraft.client.util.math.MatrixStack; import org.infinite.InfiniteClient; import org.infinite.features.rendering.ui.HyperUi; @@ -27,7 +29,7 @@ private boolean shouldCancel() { @At( value = "INVOKE", target = - "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDLnet/minecraft/client/render/state/OutlineRenderState;I)V"), + "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDLnet/minecraft/client/render/state/OutlineRenderState;IF)V"), method = "renderTargetBlockOutline(Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/util/math/MatrixStack;ZLnet/minecraft/client/render/state/WorldRenderState;)V") private void cancelBlockOutline( @@ -39,18 +41,20 @@ private void cancelBlockOutline( double z, OutlineRenderState state, int i, + float lineWidth, Operation original) { if (shouldCancel()) { InfiniteClient inf = InfiniteClient.INSTANCE; int modifyColor = inf.theme(inf.getCurrentTheme()).getColors().getPrimaryColor(); - original.call(instance, matrices, vertexConsumer, x, y, z, state, modifyColor); + original.call(instance, matrices, vertexConsumer, x, y, z, state, modifyColor, lineWidth); } else { - original.call(instance, matrices, vertexConsumer, x, y, z, state, i); + original.call(instance, matrices, vertexConsumer, x, y, z, state, i, lineWidth); } } @Inject(method = "fillBlockBreakingProgressRenderState", at = @At("HEAD"), cancellable = true) - private void cancelBlockBreakingProgress(CallbackInfo ci) { + private void cancelBlockBreakingProgress( + Camera camera, WorldRenderState worldRenderState, CallbackInfo ci) { if (shouldCancel()) { ci.cancel(); // 描画メソッドの実行をキャンセル } diff --git a/src/client/kotlin/org/infinite/global/rendering/theme/overlay/InfiniteLoadingScreenRenderer.kt b/src/client/kotlin/org/infinite/global/rendering/theme/overlay/InfiniteLoadingScreenRenderer.kt index 97a74c5e..0a346870 100644 --- a/src/client/kotlin/org/infinite/global/rendering/theme/overlay/InfiniteLoadingScreenRenderer.kt +++ b/src/client/kotlin/org/infinite/global/rendering/theme/overlay/InfiniteLoadingScreenRenderer.kt @@ -5,6 +5,7 @@ import net.minecraft.text.Text import net.minecraft.util.Identifier import net.minecraft.util.Util import net.minecraft.util.math.ColorHelper +import org.infinite.InfiniteClient import org.infinite.libs.graphics.Graphics2D import kotlin.math.min import kotlin.math.roundToInt @@ -33,9 +34,11 @@ object InfiniteLoadingScreenRenderer { reloadCompleteTime: Long, reloading: Boolean, ) { - val g2d = Graphics2D(context) // Graphics2Dインスタンスを作成 + val g2d = Graphics2D(context) // wrapper for common drawing helpers + val colors = InfiniteClient.currentColors() val now = Util.getMeasuringTimeMs() + // Track completion moment even when vanilla reloadCompleteTime is missing val completeMark = if (reloadCompleteTime > -1) { fallbackCompleteTime = -1 @@ -54,17 +57,15 @@ object InfiniteLoadingScreenRenderer { val alpha = (fadeIn * fadeOut).coerceIn(0f, 1f) if (alpha <= 0f) return - val width = g2d.width // Graphics2Dから取得 - val height = g2d.height // Graphics2Dから取得 + val width = g2d.width + val height = g2d.height - // 1. 背景のグラデーション塗りつぶし - // Graphics2DにはfillGradientがないため、DrawContextのメソッドを直接使用するか、 - // Graphics2D内にfillGradientを実装する必要があります。ここではDrawContextをラップしているため、直接使用します。 - val topColor = ColorHelper.getArgb((255 * alpha).roundToInt(), 8, 10, 14) - val bottomColor = ColorHelper.getArgb((255 * alpha).roundToInt(), 0, 0, 0) + // Background gradient using themed colors + val topColor = withAlpha(colors.backgroundColor, (220 * alpha).roundToInt()) + val bottomColor = withAlpha(colors.primaryColor, (140 * alpha).roundToInt()) context.fillGradient(0, 0, width, height, topColor, bottomColor) - // 2. アニメーション画像の描画 + // Animated spinner frames val currentFrameIndex = ((now / ANIMATION_FRAME_DURATION_MS) % ANIMATION_FRAMES_COUNT).toInt() val texture = animationTextures[currentFrameIndex] @@ -78,8 +79,8 @@ object InfiniteLoadingScreenRenderer { y = textureY.toFloat(), width = displaySize.toFloat(), height = displaySize.toFloat(), - rotation = 0f, // 回転なし - color = ColorHelper.getArgb((255 * alpha).roundToInt(), 255, 255, 255), // アルファ値を適用 + rotation = 0f, + color = ColorHelper.getArgb((255 * alpha).roundToInt(), 255, 255, 255), u = 0f, v = 0f, uWidth = TEXTURE_SIZE.toFloat(), @@ -88,8 +89,7 @@ object InfiniteLoadingScreenRenderer { textureHeight = TEXTURE_SIZE.toFloat(), ) val fontHeight = g2d.fontHeight() - // 3. タイトルテキストの描画 - val titleAlpha = ColorHelper.getArgb((255 * alpha).roundToInt(), 255, 255, 255) + val titleAlpha = withAlpha(colors.foregroundColor, (255 * alpha).roundToInt()) val title = Text.literal("Infinite Client") g2d.centeredText( text = title, @@ -99,14 +99,13 @@ object InfiniteLoadingScreenRenderer { shadow = true, ) - // 4. サブタイトルテキストの描画 (Y座標を +26 から +38 に変更) val subtitleText = if (reloading) { Text.literal("Loading resources...") } else { Text.literal("Finishing setup...") } - val subtitleAlpha = ColorHelper.getArgb((210 * alpha).roundToInt(), 180, 180, 180) + val subtitleAlpha = withAlpha(colors.secondaryColor, (210 * alpha).roundToInt()) g2d.centeredText( text = subtitleText, x = width / 2, @@ -115,13 +114,12 @@ object InfiniteLoadingScreenRenderer { shadow = true, ) - // 5. プログレスバーの描画 + // Progress bar val progressBarWidth = (width * 0.55f).roundToInt() val progressBarX = (width - progressBarWidth) / 2 val progressBarY = (height * 0.68f).roundToInt() - // ベースバーの描画 (rect) - val baseBarColor = ColorHelper.getArgb((80 * alpha).roundToInt(), 255, 255, 255) + val baseBarColor = withAlpha(colors.foregroundColor, (80 * alpha).roundToInt()) g2d.rect( x1 = progressBarX.toFloat(), y1 = progressBarY.toFloat(), @@ -130,10 +128,9 @@ object InfiniteLoadingScreenRenderer { color = baseBarColor, ) - // フィル部分の描画 (rect) val clampedProgress = progress.coerceIn(0f, 1f) val filledWidth = (progressBarWidth * clampedProgress).roundToInt() - val fillColor = ColorHelper.getArgb((230 * alpha).roundToInt(), 255, 255, 255) + val fillColor = withAlpha(colors.primaryColor, (230 * alpha).roundToInt()) if (filledWidth > 0) { g2d.rect( @@ -144,17 +141,24 @@ object InfiniteLoadingScreenRenderer { color = fillColor, ) } - // 6. パーセンテージテキストの描画 (Y座標は変更なし) val percentText = "${(clampedProgress * 100f).roundToInt()}%" - val percentTitle = Text.literal("$percentText • Infinite") - val percentAlpha = ColorHelper.getArgb((200 * alpha).roundToInt(), 210, 210, 210) + val percentTitle = Text.literal("$percentText - Infinite") + val percentAlpha = withAlpha(colors.foregroundColor, (200 * alpha).roundToInt()) g2d.centeredText( text = percentTitle, x = width / 2, - y = progressBarY + 4 * fontHeight, // 変更なし + y = progressBarY + 4 * fontHeight, color = percentAlpha, shadow = true, ) } + + private fun withAlpha( + color: Int, + alpha: Int, + ): Int { + val clampedAlpha = alpha.coerceIn(0, 255) + return (clampedAlpha shl 24) or (color and 0x00FFFFFF) + } } diff --git a/src/client/kotlin/org/infinite/global/rendering/theme/widget/PressableWidgetRenderer.kt b/src/client/kotlin/org/infinite/global/rendering/theme/widget/PressableWidgetRenderer.kt index 27616e16..88890ec7 100644 --- a/src/client/kotlin/org/infinite/global/rendering/theme/widget/PressableWidgetRenderer.kt +++ b/src/client/kotlin/org/infinite/global/rendering/theme/widget/PressableWidgetRenderer.kt @@ -5,7 +5,6 @@ import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.widget.CheckboxWidget import net.minecraft.client.gui.widget.LockButtonWidget import net.minecraft.client.gui.widget.PageTurnWidget -import net.minecraft.client.gui.widget.PressableTextWidget import net.minecraft.client.gui.widget.PressableWidget import net.minecraft.client.gui.widget.TextIconButtonWidget import net.minecraft.client.gui.widget.TexturedButtonWidget @@ -56,15 +55,8 @@ class PressableWidgetRenderer( graphics2D.drawBorder(x, y, width, height, borderColor, borderWidth) // ------------------------------------------------- - // ⭐ テキスト描画の制御部分 val shouldRenderText = when (widget) { - // テキストを表示するウィジェット - is PressableTextWidget, // 標準的なテキストボタン - is TextIconButtonWidget.WithText, - -> true - - // テキスト表示が主目的ではないウィジェット is CheckboxWidget, is LockButtonWidget, is PageTurnWidget, @@ -72,12 +64,14 @@ class PressableWidgetRenderer( is TexturedButtonWidget, -> false - // その他の PressableWidget の派生クラスは、デフォルトでテキストを表示する(安全策) else -> true } if (shouldRenderText) { - widget.drawMessage(context, MinecraftClient.getInstance().textRenderer, textColor) + val textRenderer = MinecraftClient.getInstance().textRenderer + val textX = x + width / 2 + val textY = y + (height - textRenderer.fontHeight) / 2 + context.drawCenteredTextWithShadow(textRenderer, widget.message, textX, textY, textColor) } } } diff --git a/src/client/kotlin/org/infinite/global/rendering/theme/widget/SliderWidgetRenderer.kt b/src/client/kotlin/org/infinite/global/rendering/theme/widget/SliderWidgetRenderer.kt index 75e89873..9f702f3c 100644 --- a/src/client/kotlin/org/infinite/global/rendering/theme/widget/SliderWidgetRenderer.kt +++ b/src/client/kotlin/org/infinite/global/rendering/theme/widget/SliderWidgetRenderer.kt @@ -66,12 +66,10 @@ class SliderWidgetRenderer( // バニラの描画コード (this.drawScrollableText) の挙動を再現するため、 // centeredText ではなく、通常は左端に少しオフセットをかけて描画します。 - // 💡 テキストの描画色を決定 (バニラコードを参照) - // バニラコードの i = ColorHelper.withAlpha(this.alpha, this.active ? -1 : -6250336) を再現 val textColor = if (active) colors.foregroundColor else colors.secondaryColor - - // 💡 drawScrollableText の引数 (context, textRenderer, xOffset, color) に基づき、 - // x + 2 の位置にメッセージを描画します。 - widget.drawScrollableText(context, minecraftClient.textRenderer, 2, textColor) + val textRenderer = minecraftClient.textRenderer + val textX = x + 2 + val textY = y + (height - textRenderer.fontHeight) / 2 + context.drawTextWithShadow(textRenderer, widget.message, textX, textY, textColor) } } diff --git a/src/client/kotlin/org/infinite/global/rendering/theme/widget/TextFieldWidgetRenderer.kt b/src/client/kotlin/org/infinite/global/rendering/theme/widget/TextFieldWidgetRenderer.kt index af603d6c..1f63fe9c 100644 --- a/src/client/kotlin/org/infinite/global/rendering/theme/widget/TextFieldWidgetRenderer.kt +++ b/src/client/kotlin/org/infinite/global/rendering/theme/widget/TextFieldWidgetRenderer.kt @@ -7,6 +7,7 @@ import net.minecraft.client.gui.cursor.StandardCursors import net.minecraft.client.gui.widget.TextFieldWidget import net.minecraft.text.OrderedText import net.minecraft.util.Util +import net.minecraft.util.math.ColorHelper import net.minecraft.util.math.MathHelper import org.infinite.InfiniteClient import org.infinite.libs.graphics.Graphics2D @@ -27,63 +28,72 @@ class TextFieldWidgetRenderer( ) { if (widget.isVisible) { val graphics2D = Graphics2D(context) - // テーマ色を取得 val colors = InfiniteClient.currentColors() val backgroundColor = colors.backgroundColor - val primaryColor = colors.primaryColor // 枠線に適用 + val primaryColor = colors.primaryColor val foregroundColor = colors.foregroundColor val secondaryColor = colors.secondaryColor - val infoColor = colors.infoColor // 提案テキスト(Suggestion)に適用(元のコードは-8355712) + val infoColor = colors.infoColor // color used for suggestion text - // 1. 背景と枠線の描画 + // Draw background/border with subtle hover/focus emphasis if (widget.drawsBackground()) { + val hovered = widget.isHovered + val focused = widget.isFocused + val baseAlpha = + if (focused) { + 210 + } else if (hovered) { + 180 + } else { + 150 + } + val borderAlpha = + if (focused) { + 255 + } else if (hovered) { + 220 + } else { + 180 + } graphics2D.fill( widget.x, widget.y, widget.getWidth(), widget.getHeight(), - backgroundColor, + withAlpha(backgroundColor, baseAlpha), ) graphics2D.drawBorder( widget.x, widget.y, widget.width, widget.height, - primaryColor, // アクセントカラーとしてprimaryColorを使用 + withAlpha(primaryColor, borderAlpha), 1, ) } - // 2. テキストの色設定 + // Text styling swaps when field is disabled val textColor: Int = if (widget.isEditable) foregroundColor else secondaryColor - // 3. 描画するテキストの準備 - // カーソル(キャレット)の描画位置(stringの先頭からのインデックス) val startCursorIndexInScreenString: Int = widget.selectionStart - widget.firstCharacterIndex - // 画面幅に収まるように切り詰められたテキスト val screenVisibleText: String = textRenderer.trimToWidth( widget.text.substring(widget.firstCharacterIndex), widget.innerWidth, ) - // 選択開始インデックスが画面上の表示範囲内にあるか val isSelectionStartVisible = startCursorIndexInScreenString >= 0 && startCursorIndexInScreenString <= screenVisibleText.length - // カーソル点滅ロジック: フォーカスがあり、時間で点滅、かつ選択開始位置が表示されているか val shouldDrawBlinkingCursor = widget.isFocused && (Util.getMeasuringTimeMs() - widget.lastSwitchFocusTime) / 300L % 2L == 0L && isSelectionStartVisible - // 選択終了インデックス(画面上の表示範囲にクランプ) val endCursorIndexInScreenString = MathHelper.clamp(widget.selectionEnd - widget.firstCharacterIndex, 0, screenVisibleText.length) - // 現在のテキスト描画X座標 var textRenderX: Int = widget.textX - // 4. 選択範囲の前のテキストの描画 if (!screenVisibleText.isEmpty()) { val textBeforeCursor = if (isSelectionStartVisible) screenVisibleText.take(startCursorIndexInScreenString) else screenVisibleText @@ -100,24 +110,18 @@ class TextFieldWidgetRenderer( textRenderX += textRenderer.getWidth(orderedTextBeforeCursor) + 1 } - // 5. カーソル(キャレット)の位置計算 - // テキストの末尾(最大長)に達していない、または最大長に達しているか val isCursorAtEndOrMaximized = widget.selectionStart < widget.text.length || widget.text.length >= widget.maxLength - // カーソル描画X座標の初期値 var cursorRenderX = textRenderX if (!isSelectionStartVisible) { - // カーソルが画面外(左側)の場合 cursorRenderX = if (startCursorIndexInScreenString > 0) widget.textX + widget.width else widget.textX } else if (isCursorAtEndOrMaximized) { - // カーソルが選択範囲の前のテキストの直後(文字と文字の間) cursorRenderX = textRenderX - 1 - --textRenderX // 次のテキスト描画X座標を1戻す + --textRenderX } - // 6. 選択範囲の後ろのテキストの描画 if (!screenVisibleText.isEmpty() && isSelectionStartVisible && startCursorIndexInScreenString < screenVisibleText.length) { context.drawText( textRenderer, @@ -129,55 +133,50 @@ class TextFieldWidgetRenderer( ) } - // 7. プレースホルダーテキストの描画 if (widget.placeholder != null && screenVisibleText.isEmpty() && !widget.isFocused) { - // プレースホルダーの描画位置は、テキストの描画が始まる位置 (k) から + // Show placeholder when empty/unfocused context.drawTextWithShadow( textRenderer, widget.placeholder, textRenderX, widget.textY, secondaryColor, - ) // secondaryColorで目立たなく + ) } - // 8. 提案テキスト(Suggestion)の描画 if (!isCursorAtEndOrMaximized && widget.suggestion != null) { + // Render inline suggestion context.drawText( textRenderer, widget.suggestion, - cursorRenderX - 1, // カーソル位置から + cursorRenderX - 1, widget.textY, infoColor, widget.textShadow, ) } - // 9. 選択範囲(ハイライト)の描画 if (endCursorIndexInScreenString != startCursorIndexInScreenString) { val endSelectionX: Int = widget.textX + textRenderer.getWidth(screenVisibleText.take(endCursorIndexInScreenString)) - // 描画範囲のクランプ処理を分かりやすい変数名に val selectionStartXClamped = min(cursorRenderX, widget.x + widget.width) val selectionEndXClamped = min(endSelectionX - 1, widget.x + widget.width) - // 選択範囲のY座標 val selectionYStart: Int = widget.textY - 1 Objects.requireNonNull(textRenderer) - val selectionYEnd: Int = selectionYStart + 1 + 9 // テキストの高さに依存 + val selectionYEnd: Int = selectionYStart + 1 + 9 - context.drawSelection(selectionStartXClamped, selectionYStart, selectionEndXClamped, selectionYEnd) + context.drawSelection(selectionStartXClamped, selectionYStart, selectionEndXClamped, selectionYEnd, false) } - // 10. ブリンキングカーソル(キャレット)の描画 if (shouldDrawBlinkingCursor) { if (isCursorAtEndOrMaximized) { - // カーソルが文字の間にある場合(縦棒) + // Filled caret when cursor sits at end val caretYStart: Int = widget.textY - 1 val caretXEnd = cursorRenderX + 1 Objects.requireNonNull(textRenderer) - val caretYEnd: Int = caretYStart + 1 + 9 // テキストの高さに依存 + val caretYEnd: Int = caretYStart + 1 + 9 context.fill( cursorRenderX, @@ -185,17 +184,24 @@ class TextFieldWidgetRenderer( caretXEnd, caretYEnd, foregroundColor, - ) // foregroundColorで描画 + ) } else { - // カーソルがテキストの末尾の後の場合(アンダースコア) + // Underscore caret when mid-string context.drawText(textRenderer, "_", cursorRenderX, widget.textY, foregroundColor, widget.textShadow) } } - // 11. マウスカーソルの設定 if (widget.isHovered) { context.setCursor(if (widget.isEditable) StandardCursors.IBEAM else StandardCursors.NOT_ALLOWED) } } } + + private fun withAlpha( + color: Int, + alpha: Int, + ): Int { + val clampedAlpha = alpha.coerceIn(0, 255) + return (clampedAlpha shl 24) or (color and 0x00FFFFFF) + } } diff --git a/src/client/kotlin/org/infinite/gui/screen/InfiniteScreen.kt b/src/client/kotlin/org/infinite/gui/screen/InfiniteScreen.kt index 6ca47489..b27eb430 100644 --- a/src/client/kotlin/org/infinite/gui/screen/InfiniteScreen.kt +++ b/src/client/kotlin/org/infinite/gui/screen/InfiniteScreen.kt @@ -55,9 +55,13 @@ class InfiniteScreen( val dynamicSections = mutableListOf() dynamicSections.add(UISection("main", this)) - InfiniteClient.featureCategories.forEach { category -> - dynamicSections.add(UISection(category.name.lowercase() + "-settings", this, category.features)) - } + InfiniteClient.featureCategories + .filterNot { category -> + category.name.equals("Rendering", ignoreCase = true) || + category.name.equals("Accessibility", ignoreCase = true) + }.forEach { category -> + dynamicSections.add(UISection(category.name.lowercase() + "-settings", this, category.features)) + } sections = dynamicSections diff --git a/src/client/kotlin/org/infinite/gui/screen/UISection.kt b/src/client/kotlin/org/infinite/gui/screen/UISection.kt index 021e96f8..846b089b 100644 --- a/src/client/kotlin/org/infinite/gui/screen/UISection.kt +++ b/src/client/kotlin/org/infinite/gui/screen/UISection.kt @@ -74,15 +74,22 @@ class UISection( alpha: Int, renderContent: Boolean, ) { - // Draw the icon in the center of the panel + val backgroundColor = + InfiniteClient + .theme() + .colors.backgroundColor + .transparent(alpha) + context.drawBorder(x, y, width, height, borderColor) + context.fill(x, y, x + width, y + height, backgroundColor) + + // Draw the icon in the center of the panel after the background so it stays visible val icon = InfiniteClient.theme().icon if (icon != null) { val iconWidth = if (icon.width > icon.height) 256 else 256 * icon.width / icon.height val iconHeight = if (icon.width < icon.height) 256 else 256 * icon.height / icon.width val iconX = x + (width - iconWidth) / 2 val iconY = y + (height - iconHeight) / 2 - val iconColor = - borderColor.transparent(128) + val iconColor = borderColor.transparent(128) context.drawTexture( RenderPipelines.GUI_TEXTURED, icon.identifier, @@ -99,13 +106,6 @@ class UISection( iconColor, ) } - val backgroundColor = - InfiniteClient - .theme() - .colors.backgroundColor - .transparent(alpha) - context.drawBorder(x, y, width, height, borderColor) - context.fill(x, y, x + width, y + height, backgroundColor) val titleText = when (id) { diff --git a/src/client/kotlin/org/infinite/gui/widget/FeatureSearchWidget.kt b/src/client/kotlin/org/infinite/gui/widget/FeatureSearchWidget.kt index f0352a89..017c31dc 100644 --- a/src/client/kotlin/org/infinite/gui/widget/FeatureSearchWidget.kt +++ b/src/client/kotlin/org/infinite/gui/widget/FeatureSearchWidget.kt @@ -168,7 +168,7 @@ class FeatureSearchWidget( GLFW.GLFW_KEY_ENTER -> { if (selectedIndex != -1) { val selectedToggle = scrollableContainer.widgets[selectedIndex] as? InfiniteFeatureToggle - selectedToggle?.toggleButton?.onPress(input) // Simulate button press + selectedToggle?.toggleButton?.press() return true } } diff --git a/src/client/kotlin/org/infinite/gui/widget/InfiniteButton.kt b/src/client/kotlin/org/infinite/gui/widget/InfiniteButton.kt index 1b23aa2b..0887bb61 100644 --- a/src/client/kotlin/org/infinite/gui/widget/InfiniteButton.kt +++ b/src/client/kotlin/org/infinite/gui/widget/InfiniteButton.kt @@ -1,8 +1,10 @@ package org.infinite.gui.widget import net.minecraft.client.MinecraftClient +import net.minecraft.client.gui.Click import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.widget.ButtonWidget +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder +import net.minecraft.client.gui.widget.ClickableWidget import net.minecraft.text.Text import org.infinite.InfiniteClient import org.infinite.libs.graphics.Graphics2D @@ -13,8 +15,8 @@ class InfiniteButton( width: Int, height: Int, message: Text, - onPress: PressAction, -) : ButtonWidget(x, y, width, height, message, onPress, DEFAULT_NARRATION_SUPPLIER) { + private val onPress: () -> Unit, +) : ClickableWidget(x, y, width, height, message) { override fun renderWidget( context: DrawContext, mouseX: Int, @@ -24,58 +26,48 @@ class InfiniteButton( val graphics2D = Graphics2D(context, MinecraftClient.getInstance().renderTickCounter) val borderWidth = 1 // 1px border + val colors = InfiniteClient.currentColors() - // Animation colors (same as InfiniteScreen) - val interpolatedColor = - InfiniteClient - .currentColors() - .primaryColor - - // Button rendering logic (similar to InfiniteScreen) - // 1. Outer background - context.fill( - x, - y, - x + width, - y + height, - InfiniteClient - .currentColors() - .backgroundColor, - ) - - // 2. Animated border + // Outer background + context.fill(x, y, x + width, y + height, colors.backgroundColor) + // Animated border context.fill( x + borderWidth, y + borderWidth, x + width - borderWidth, y + height - borderWidth, - interpolatedColor, + colors.primaryColor, ) - - // 3. Inner background + // Inner background context.fill( x + borderWidth * 2, y + borderWidth * 2, x + width - borderWidth * 2, y + height - borderWidth * 2, - InfiniteClient - .currentColors() - .backgroundColor, + colors.backgroundColor, ) - // Draw button text - val textColor = - if (isHovered) { - InfiniteClient.currentColors().primaryColor - } else { - InfiniteClient.currentColors().foregroundColor // Darker foreground when hovered, foreground otherwise - } + val textColor = if (isHovered) colors.primaryColor else colors.foregroundColor graphics2D.centeredText( message, x + width / 2, y + height / 2, textColor, - true, // shadow = true + true, ) } + + override fun mouseClicked( + click: Click, + doubled: Boolean, + ): Boolean { + if (!isMouseOver(click.x, click.y) || !active) return false + playDownSound(MinecraftClient.getInstance().soundManager) + onPress() + return true + } + + override fun appendClickableNarrations(builder: NarrationMessageBuilder) { + appendDefaultNarrations(builder) + } } diff --git a/src/client/kotlin/org/infinite/gui/widget/InfiniteToggleButton.kt b/src/client/kotlin/org/infinite/gui/widget/InfiniteToggleButton.kt index 832413c3..82a2d123 100644 --- a/src/client/kotlin/org/infinite/gui/widget/InfiniteToggleButton.kt +++ b/src/client/kotlin/org/infinite/gui/widget/InfiniteToggleButton.kt @@ -1,8 +1,10 @@ package org.infinite.gui.widget +import net.minecraft.client.MinecraftClient +import net.minecraft.client.gui.Click import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.widget.ButtonWidget -import net.minecraft.client.input.AbstractInput +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder +import net.minecraft.client.gui.widget.ClickableWidget import net.minecraft.text.Text import org.infinite.InfiniteClient import kotlin.math.sin @@ -15,25 +17,9 @@ class InfiniteToggleButton( private var state: Boolean, private var isEnabled: Boolean, private val onToggle: (Boolean) -> Unit, -) : ButtonWidget( - x, - y, - width, - height, - Text.literal(""), - { _ -> }, - DEFAULT_NARRATION_SUPPLIER, - ) { +) : ClickableWidget(x, y, width, height, Text.empty()) { private var animationStartTime: Long = -1L - private val animationDuration = 200L // アニメーションにかける時間(ミリ秒) - - override fun onPress(input: AbstractInput?) { - if (isEnabled) { - state = !state - onToggle(state) - animationStartTime = System.currentTimeMillis() // アニメーション開始時間を記録 - } - } + private val animationDuration = 200L override fun renderWidget( context: DrawContext, @@ -41,56 +27,24 @@ class InfiniteToggleButton( mouseY: Int, delta: Float, ) { - // レインボーアニメーションのロジック - val interpolatedColor = - InfiniteClient - .currentColors() - .primaryColor + val colors = InfiniteClient.currentColors() + val interpolatedColor = colors.primaryColor val backgroundColor = when { - !isEnabled -> { - InfiniteClient - .currentColors() - .backgroundColor - } - - state -> { - if (isHovered) { - InfiniteClient - .currentColors() - .greenAccentColor - } else { - InfiniteClient - .currentColors() - .primaryColor // ON state - } - } - - else -> { - if (isHovered) { - InfiniteClient - .currentColors() - .secondaryColor - } else { - InfiniteClient - .currentColors() - .backgroundColor // OFF state - } - } + !isEnabled -> colors.backgroundColor + state -> if (isHovered) colors.greenAccentColor else colors.primaryColor + else -> if (isHovered) colors.secondaryColor else colors.backgroundColor } - // ノブのサイズを基準にバーの幅を決定 val knobSize = height - 4 val barWidth = (knobSize * 2).toFloat() val barHeight = height.toFloat() / 2.5f val barY = y + (height - barHeight.toInt()) / 2 val barX = x + (width - barWidth.toInt()) / 2 - // 背景バーの描画 context.fill(barX, barY, (barX + barWidth).toInt(), (barY + barHeight).toInt(), backgroundColor) - // **ノブのアニメーションロジック** val knobBorder = 2 val startKnobX = if (!state) barX + barWidth.toInt() - knobSize - 2 else barX + 2 val endKnobX = if (state) barX + barWidth.toInt() - knobSize - 2 else barX + 2 @@ -100,38 +54,19 @@ class InfiniteToggleButton( val currentTime = System.currentTimeMillis() val animProgress = (currentTime - animationStartTime).toFloat() / animationDuration.toFloat() if (animProgress < 1.0f) { - // スムーズなアニメーションのためにsin関数を使用 val easedProgress = sin(animProgress * Math.PI / 2).toFloat() currentKnobX = startKnobX + (endKnobX - startKnobX) * easedProgress } else { - animationStartTime = -1L // アニメーション終了 + animationStartTime = -1L currentKnobX = endKnobX.toFloat() } } val knobY = y + 2 - // ノブの縁 (有効時のみレインボーアニメーション) - val knobBorderColor = - if (isEnabled) { - interpolatedColor - } else { - InfiniteClient - .currentColors() - .backgroundColor - } + val knobBorderColor = if (isEnabled) interpolatedColor else colors.backgroundColor context.fill(currentKnobX.toInt(), knobY, currentKnobX.toInt() + knobSize, knobY + knobSize, knobBorderColor) - // ノブの内側 - val knobInnerColor = - if (isHovered) { - InfiniteClient - .currentColors() - .primaryColor - } else { - InfiniteClient - .currentColors() - .foregroundColor - } + val knobInnerColor = if (isHovered) colors.primaryColor else colors.foregroundColor context.fill( currentKnobX.toInt() + knobBorder, knobY + knobBorder, @@ -141,7 +76,31 @@ class InfiniteToggleButton( ) } + override fun mouseClicked( + click: Click, + doubled: Boolean, + ): Boolean { + if (!isMouseOver(click.x, click.y) || !active || !isEnabled) return false + playDownSound(MinecraftClient.getInstance().soundManager) + state = !state + onToggle(state) + animationStartTime = System.currentTimeMillis() + return true + } + fun setState(newState: Boolean) { state = newState } + + fun press() { + if (!active || !isEnabled) return + playDownSound(MinecraftClient.getInstance().soundManager) + state = !state + onToggle(state) + animationStartTime = System.currentTimeMillis() + } + + override fun appendClickableNarrations(builder: NarrationMessageBuilder) { + appendDefaultNarrations(builder) + } } diff --git a/src/client/kotlin/org/infinite/gui/widget/TabButton.kt b/src/client/kotlin/org/infinite/gui/widget/TabButton.kt index 82293810..a0154c2d 100644 --- a/src/client/kotlin/org/infinite/gui/widget/TabButton.kt +++ b/src/client/kotlin/org/infinite/gui/widget/TabButton.kt @@ -1,8 +1,10 @@ package org.infinite.gui.widget import net.minecraft.client.MinecraftClient +import net.minecraft.client.gui.Click import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.widget.ButtonWidget +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder +import net.minecraft.client.gui.widget.ClickableWidget import net.minecraft.text.Text import org.infinite.InfiniteClient import org.infinite.libs.graphics.Graphics2D @@ -13,8 +15,8 @@ class TabButton( width: Int, height: Int, message: Text, - onPress: PressAction, -) : ButtonWidget(x, y, width, height, message, onPress, DEFAULT_NARRATION_SUPPLIER) { + private val onPress: () -> Unit, +) : ClickableWidget(x, y, width, height, message) { var isHighlighted: Boolean = false override fun renderWidget( @@ -25,8 +27,8 @@ class TabButton( ) { val graphics2D = Graphics2D(context, MinecraftClient.getInstance().renderTickCounter) val colors = InfiniteClient.currentColors() - val textColor = if (isSelected || isHighlighted) colors.primaryColor else colors.foregroundColor - val backgroundColor = if (isSelected || isHighlighted) colors.backgroundColor else colors.secondaryColor + val textColor = if (isHovered || isHighlighted) colors.primaryColor else colors.foregroundColor + val backgroundColor = if (isHovered || isHighlighted) colors.backgroundColor else colors.secondaryColor graphics2D.fill(x, y, width, height, backgroundColor) graphics2D.drawBorder(x, y, width, height, colors.primaryColor) graphics2D.centeredText( @@ -36,4 +38,18 @@ class TabButton( textColor, ) } + + override fun mouseClicked( + click: Click, + doubled: Boolean, + ): Boolean { + if (!isMouseOver(click.x, click.y) || !active) return false + playDownSound(MinecraftClient.getInstance().soundManager) + onPress() + return true + } + + override fun appendClickableNarrations(builder: NarrationMessageBuilder) { + appendDefaultNarrations(builder) + } } diff --git a/src/client/kotlin/org/infinite/libs/graphics/Graphics2D.kt b/src/client/kotlin/org/infinite/libs/graphics/Graphics2D.kt index 7953c816..5ce34f73 100644 --- a/src/client/kotlin/org/infinite/libs/graphics/Graphics2D.kt +++ b/src/client/kotlin/org/infinite/libs/graphics/Graphics2D.kt @@ -1,6 +1,7 @@ package org.infinite.libs.graphics import net.minecraft.client.MinecraftClient +import net.minecraft.client.gl.GpuSampler import net.minecraft.client.gl.RenderPipelines import net.minecraft.client.gui.DrawContext import net.minecraft.client.render.RenderTickCounter @@ -25,7 +26,9 @@ import org.joml.Matrix3x2f import org.joml.Matrix3x2fStack import org.joml.Vector2d import kotlin.math.PI +import kotlin.math.cos import kotlin.math.roundToInt +import kotlin.math.sin /** * MinecraftのGUI描画コンテキストを保持し、カスタム2Dレンダリングを実行するためのクラス。 @@ -239,22 +242,13 @@ class Graphics2D( color: Int, shadow: Boolean = true, ) { - val orderedText = Language.getInstance().reorder(StringVisitable.plain(text)) - val backgroundColor = 0 - val clipBounds = context.scissorStack.peekLast() - val state = - TextRenderState( - client.textRenderer, - orderedText, - matrixStack, - x, - y, - color, - backgroundColor, - shadow, - clipBounds, - ) - context.state.addText(state) + val tx = x.toInt() + val ty = y.toInt() + if (shadow) { + context.drawTextWithShadow(client.textRenderer, text, tx, ty, color) + } else { + context.drawText(client.textRenderer, text, tx, ty, color, false) + } } fun drawText( @@ -460,19 +454,19 @@ class Graphics2D( // 2セグメントごとに1つの四角形を順次描画 for (i in 0 until segments step 2) { - val angle1 = (i.toFloat() / segments.toFloat() * twoPi).toFloat() - val angle2 = ((i.toFloat() + 1f) / segments.toFloat() * twoPi).toFloat() - val angle3 = ((i.toFloat() + 2f) / segments.toFloat() * twoPi).toFloat() + val angle1 = i.toDouble() / segments.toDouble() * twoPi + val angle2 = (i.toDouble() + 1.0) / segments.toDouble() * twoPi + val angle3 = (i.toDouble() + 2.0) / segments.toDouble() * twoPi // 頂点1 (円周上) - val p1X = MathHelper.cos(angle1) * radius - val p1Y = MathHelper.sin(angle1) * radius + val p1X = (cos(angle1) * radius).toFloat() + val p1Y = (sin(angle1) * radius).toFloat() // 頂点2 (円周上) - val p2X = MathHelper.cos(angle2) * radius - val p2Y = MathHelper.sin(angle2) * radius + val p2X = (cos(angle2) * radius).toFloat() + val p2Y = (sin(angle2) * radius).toFloat() // 頂点3 (円周上) - val p3X = MathHelper.cos(angle3) * radius - val p3Y = MathHelper.sin(angle3) * radius + val p3X = (cos(angle3) * radius).toFloat() + val p3Y = (sin(angle3) * radius).toFloat() quad( p1X, @@ -518,11 +512,13 @@ class Graphics2D( var prevInnerX = cx + innerRadius var prevInnerY = cy for (i in 1..segments) { - val angle = (i.toFloat() / segments.toFloat() * twoPi).toFloat() - val outerX = cx + MathHelper.cos(angle) * outerRadius - val outerY = cy + MathHelper.sin(angle) * outerRadius - val innerX = cx + MathHelper.cos(angle) * innerRadius - val innerY = cy + MathHelper.sin(angle) * innerRadius + val angle = i.toDouble() / segments.toDouble() * twoPi + val cosV = cos(angle).toFloat() + val sinV = sin(angle).toFloat() + val outerX = cx + cosV * outerRadius + val outerY = cy + sinV * outerRadius + val innerX = cx + cosV * innerRadius + val innerY = cy + sinV * innerRadius quad( prevOuterX, prevOuterY, @@ -688,31 +684,17 @@ class Graphics2D( translate(-centerX, -centerY) } - // 現在の変換行列を取得し、描画状態として登録 - val pose = Matrix3x2f(context.matrices) - val scissor = context.scissorStack.peekLast() - val gpuTextureView = - this.client.textureManager - .getTexture(identifier) - .getGlTextureView() - - // TexturedQuadRenderState を使用して描画要素を追加 - context.state.addSimpleElement( - TexturedQuadRenderState( - RenderPipelines.GUI_TEXTURED, - TextureSetup.of(gpuTextureView), - pose, - x, - y, - x + width, - y + height, - uNormalized1, - uNormalized2, - vNormalized1, - vNormalized2, - color, - scissor, - ), + context.drawTexture( + RenderPipelines.GUI_TEXTURED, + identifier, + x.toInt(), + y.toInt(), + u, + v, + width.toInt(), + height.toInt(), + textureWidth.toInt(), + textureHeight.toInt(), ) popState() @@ -928,8 +910,8 @@ class Graphics2D( var currentAngle = startAngle // 最初の点を追加 - val startX = cx + MathHelper.cos(currentAngle) * radius - val startY = cy + MathHelper.sin(currentAngle) * radius + val startX = (cx + cos(currentAngle.toDouble()) * radius).toFloat() + val startY = (cy + sin(currentAngle.toDouble()) * radius).toFloat() arcPoints.add(startX to startY) // 中間点を計算し、リストに追加 @@ -937,8 +919,8 @@ class Graphics2D( currentAngle = startAngle + i * angleStep // 描画する円弧上の頂点の座標を計算 - val x = cx + MathHelper.cos(currentAngle) * radius - val y = cy + MathHelper.sin(currentAngle) * radius + val x = (cx + cos(currentAngle.toDouble()) * radius).toFloat() + val y = (cy + sin(currentAngle.toDouble()) * radius).toFloat() arcPoints.add(x to y) } diff --git a/src/client/kotlin/org/infinite/libs/graphics/Graphics3D.kt b/src/client/kotlin/org/infinite/libs/graphics/Graphics3D.kt index 6a9ec5a7..2eb05ff5 100644 --- a/src/client/kotlin/org/infinite/libs/graphics/Graphics3D.kt +++ b/src/client/kotlin/org/infinite/libs/graphics/Graphics3D.kt @@ -150,9 +150,10 @@ class Graphics3D( val scaledHeight = window.scaledHeight.toDouble() // 1. ワールド座標から相対座標 (View Space) へ - val relX = (targetPos.x - camera.pos.x).toFloat() - val relY = (targetPos.y - camera.pos.y).toFloat() - val relZ = (targetPos.z - camera.pos.z).toFloat() + val camPos = RenderUtils.cameraPos() + val relX = (targetPos.x - camPos.x).toFloat() + val relY = (targetPos.y - camPos.y).toFloat() + val relZ = (targetPos.z - camPos.z).toFloat() // 4Dベクトル (x, y, z, w=1.0) val targetVector = Vector4f(relX, relY, relZ, 1.0f) diff --git a/src/client/kotlin/org/infinite/libs/graphics/render/RenderResources.kt b/src/client/kotlin/org/infinite/libs/graphics/render/RenderResources.kt index 94ef9fdb..c761a10b 100644 --- a/src/client/kotlin/org/infinite/libs/graphics/render/RenderResources.kt +++ b/src/client/kotlin/org/infinite/libs/graphics/render/RenderResources.kt @@ -1,147 +1,20 @@ package org.infinite.libs.graphics.render -import com.mojang.blaze3d.pipeline.BlendFunction -import com.mojang.blaze3d.pipeline.RenderPipeline -import com.mojang.blaze3d.platform.DepthTestFunction -import com.mojang.blaze3d.vertex.VertexFormat import net.minecraft.client.gl.RenderPipelines import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.VertexFormats -import net.minecraft.util.Identifier -import java.util.OptionalDouble +import net.minecraft.client.render.RenderSetup object RenderResources { - // --- Line Rendering Resources (Existing) --- - - val lineSnippet: RenderPipeline.Snippet = - RenderPipeline - .builder( - RenderPipelines.TRANSFORMS_PROJECTION_FOG_SNIPPET, - RenderPipelines.GLOBALS_SNIPPET, - ).withVertexShader(Identifier.of("infinite:core/lines")) - .withFragmentShader(Identifier.of("infinite:core/lines")) - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) - // Lined rendering often uses POSITION_COLOR_NORMAL to get proper MatrixStack transformation - .withVertexFormat(VertexFormats.POSITION_COLOR_NORMAL, VertexFormat.DrawMode.LINES) - .buildSnippet() - - val depthTestPipeline: RenderPipeline = - RenderPipelines.register( - RenderPipeline - .builder(lineSnippet) - .withLocation( - Identifier.of("infinite:pipeline/normal_lines"), - ).build(), - ) - val normalLayer: RenderLayer.MultiPhase = - RenderLayer.of( - "infinite:lines", - 1536, - depthTestPipeline, - RenderLayer.MultiPhaseParameters - .builder() - .lineWidth(RenderPhase.LineWidth(OptionalDouble.of(2.0))) - .layering(RenderLayer.VIEW_OFFSET_Z_LAYERING) - .target(RenderLayer.ITEM_ENTITY_TARGET) - .build(false), - ) - val espLines: RenderPipeline = - RenderPipelines.register( - RenderPipeline - .builder(lineSnippet) - .withLocation(Identifier.of("infinite:pipeline/esp_lines")) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .build(), - ) - val espLayer: RenderLayer.MultiPhase = - RenderLayer.of( - "infinite:esp_lines", - 1536, - espLines, - RenderLayer.MultiPhaseParameters - .builder() - .lineWidth(RenderPhase.LineWidth(OptionalDouble.of(2.0))) - .layering(RenderLayer.VIEW_OFFSET_Z_LAYERING) - .target(RenderLayer.ITEM_ENTITY_TARGET) - .build(false), - ) - - /** - * Returns either {@link #normalLayer} (depth test) or {@link #espLayer} (no depth test). - */ - fun renderLinedLayer(isOverDraw: Boolean): RenderLayer.MultiPhase = - if (isOverDraw) { - espLayer - } else { - normalLayer - } - - // --- Solid (Quad) Rendering Resources (New) --- - - val solidSnippet: RenderPipeline.Snippet = - RenderPipeline - .builder( - RenderPipelines.TRANSFORMS_PROJECTION_FOG_SNIPPET, - RenderPipelines.GLOBALS_SNIPPET, - ).withVertexShader(Identifier.of("infinite:core/solid")) // Assuming a solid shader is available - .withFragmentShader(Identifier.of("infinite:core/solid")) // Assuming a solid shader is available - .withBlend(BlendFunction.TRANSLUCENT) - .withCull(false) // Solid faces usually cull the back face - // Using POSITION_COLOR_NORMAL and TRIANGLES to render quads, resolving the missing Normal error. - .withVertexFormat(VertexFormats.POSITION_COLOR_NORMAL, VertexFormat.DrawMode.TRIANGLES) - .buildSnippet() - - // 1. Depth-tested Solid Layer (Similar to WurstRenderLayers.QUADS) - val quadsPipeline: RenderPipeline = - RenderPipelines.register( - RenderPipeline - .builder(solidSnippet) - .withLocation(Identifier.of("infinite:pipeline/normal_quads")) - // Depth Test is implicitly enabled by default - .build(), - ) - val quadsLayer: RenderLayer.MultiPhase = - RenderLayer.of( - "infinite:quads", - 1536, - quadsPipeline, - RenderLayer.MultiPhaseParameters - .builder() - .layering(RenderLayer.VIEW_OFFSET_Z_LAYERING) - .target(RenderLayer.ITEM_ENTITY_TARGET) - .build(false), - ) - - // 2. No-depth-tested Solid Layer (Similar to WurstRenderLayers.ESP_QUADS) - val espQuadsPipeline: RenderPipeline = - RenderPipelines.register( - RenderPipeline - .builder(solidSnippet) - .withLocation(Identifier.of("infinite:pipeline/esp_quads")) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .build(), - ) - val espQuadsLayer: RenderLayer.MultiPhase = - RenderLayer.of( - "infinite:esp_quads", - 1536, - espQuadsPipeline, - RenderLayer.MultiPhaseParameters - .builder() - .layering(RenderLayer.VIEW_OFFSET_Z_LAYERING) - .target(RenderLayer.ITEM_ENTITY_TARGET) - .build(false), - ) - - /** - * Returns either {@link #quadsLayer} (depth test) or {@link #espQuadsLayer} (no depth test). - */ - fun renderSolidLayer(isOverDraw: Boolean): RenderLayer.MultiPhase = - if (isOverDraw) { - espQuadsLayer - } else { - quadsLayer - } + private val normalLines: RenderLayer = + RenderLayer.of("infinite:lines", RenderSetup.builder(RenderPipelines.LINES).build()) + private val espLines: RenderLayer = + RenderLayer.of("infinite:esp_lines", RenderSetup.builder(RenderPipelines.LINES_TRANSLUCENT).translucent().build()) + private val solidLayer: RenderLayer = + RenderLayer.of("infinite:solid", RenderSetup.builder(RenderPipelines.GUI).translucent().build()) + + fun renderLinedLayer(isOverDraw: Boolean): RenderLayer = if (isOverDraw) espLines else normalLines + + fun renderSolidLayer( + @Suppress("UNUSED_PARAMETER") isOverDraw: Boolean, + ): RenderLayer = solidLayer } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index ec812f99..99418ce2 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -36,7 +36,7 @@ "accessWidener": "infinite.accesswidener", "depends": { "fabricloader": ">=0.16", - "minecraft": "~1.21.8", + "minecraft": "~1.21.11", "java": ">=21", "fabric-api": "*", "fabric-language-kotlin": "*" @@ -53,7 +53,6 @@ } }, "suggests": { - "baritone": "~1.21.10", "modmenu": "~16" } } diff --git a/src/main/resources/infinite.accesswidener b/src/main/resources/infinite.accesswidener index 849aa729..00747d54 100644 --- a/src/main/resources/infinite.accesswidener +++ b/src/main/resources/infinite.accesswidener @@ -72,7 +72,6 @@ accessible method net/minecraft/client/gui/widget/ScrollableWidget isInScrollbar accessible field net/minecraft/client/gui/widget/ScrollableWidget scrollbarDragged Z accessible class net/minecraft/client/gui/widget/ScrollableLayoutWidget$Container accessible field net/minecraft/client/gui/widget/SliderWidget value D -accessible method net/minecraft/client/gui/widget/ClickableWidget drawScrollableText (Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/client/font/TextRenderer;II)V accessible field net/minecraft/client/gui/widget/ClickableWidget alpha F accessible method net/minecraft/client/gui/widget/TextFieldWidget isEditable ()Z accessible field net/minecraft/client/gui/widget/TextFieldWidget firstCharacterIndex I