Build for Minecraft 26.1
Adds 26.1 as a Stonecutter version (step 3 of #39). Its jar also loads on the 26.1.1 and 26.1.2 hotfixes. Most of 26.1's changes are renames: the GUI's render methods became extract methods and GuiGraphics became GuiGraphicsExtractor, which Stonecutter replacements cover along with the moved render state package and GuiRenderState's add methods. The rest are version comments: - The menu panorama is drawn by GuiRenderer from vanilla's cube map; the new GuiRendererMixin swaps in Saturn's while a Saturn screen is open (empty on older versions). - The camera works out the FOV and aligns with its entity in alignWithEntity, so the zoom and freelook hooks move to CameraMixin. - Gamma and the menu blur are read while extracting render state. - The glass blur's post chain takes a Projection and its buffer. - The dragon's alpha render type is gone; capes use entityCutout. - Fabric API renamed KeyBindingHelper to KeyMappingHelper. The docs describe the 26.x build and Java 25. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
Saturn Client is a free, open-source Minecraft client designed to enhance the gameplay experience while staying lightweight and customizable.
|
Saturn Client is a free, open-source Minecraft client designed to enhance the gameplay experience while staying lightweight and customizable.
|
||||||
Our goal is to build a clean, optimized client that the community can contribute to and improve together.
|
Our goal is to build a clean, optimized client that the community can contribute to and improve together.
|
||||||
|
|
||||||
Saturn runs on Fabric and supports **Minecraft 1.21.4 to 1.21.11**, with one build per version. If something doesn't work on your version, please open an issue.
|
Saturn runs on Fabric and supports **Minecraft 1.21.4 to 1.21.11 and 26.1**, with one build per version (the 26.1 build also runs on 26.1.1 and 26.1.2). If something doesn't work on your version, please open an issue.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ cd saturnclient
|
|||||||
./gradlew :1.21.11:runClient # launch a development client
|
./gradlew :1.21.11:runClient # launch a development client
|
||||||
```
|
```
|
||||||
|
|
||||||
Building needs Java 21.
|
Building needs Java 21. The 26.x versions compile with Java 25, which Gradle downloads when it isn't installed.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -4,21 +4,23 @@ How Saturn Client supports several Minecraft versions, and how to change or add
|
|||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
Every supported Minecraft version (1.21.4 to 1.21.11) builds from one copy of the version-specific code with [Stonecutter](https://stonecutter.kikugie.dev/):
|
Every supported Minecraft version (1.21.4 to 1.21.11, and 26.1) builds from one copy of the version-specific code with [Stonecutter](https://stonecutter.kikugie.dev/):
|
||||||
|
|
||||||
- `common/`: all version-independent code (mods, UI, cosmetics, the server client). It has no Minecraft dependency and reaches the game only through the interfaces in `org.saturnclient.common`.
|
- `common/`: all version-independent code (mods, UI, cosmetics, the server client). It has no Minecraft dependency and reaches the game only through the interfaces in `org.saturnclient.common`.
|
||||||
- `src/`: the version-specific code (providers, refs, mixins and the three mixin configs), one copy for every version. Where Minecraft's API differs between versions, the code goes behind version comments (see below).
|
- `src/`: the version-specific code (providers, refs, mixins and the three mixin configs), one copy for every version. Where Minecraft's API differs between versions, the code goes behind version comments (see below).
|
||||||
- `versions/<mc>/`: each version's `gradle.properties` (Minecraft, Fabric Loader and Fabric API versions), plus its `build/` and `run/` folders. Each version is the Gradle project `:<mc>`.
|
- `versions/<mc>/`: each version's `gradle.properties` (Minecraft, Fabric Loader and Fabric API versions), plus its `build/` and `run/` folders. Each version is the Gradle project `:<mc>`.
|
||||||
|
|
||||||
`settings.gradle.kts` lists the versions in `stonecutterVersions`. The root `build.gradle.kts` builds each version, and `stonecutter.gradle.kts` configures the root project (shared repositories, the `common` wiring and `buildAll`). Loom's version is `loom_version` in the root `gradle.properties`.
|
`settings.gradle.kts` lists the versions in `stonecutterVersions`. The root `build.gradle.kts` builds each version, and `stonecutter.gradle.kts` configures the root project (shared repositories, the `common` wiring and `buildAll`). Loom's version is `loomx.loom_version` in the root `gradle.properties`.
|
||||||
|
|
||||||
|
Minecraft is obfuscated up to 1.21.11 and ships with Mojang's names from 26.1. The `loom-back-compat` plugin (`loomx`) applies the matching Loom for each version: the remapping one for 1.21.x, whose jar is `remapJar`'s output, and the plain one for 26.x, whose jar is `jar`'s. 26.x also compiles with Java 25 (21 before), set per version in `build.gradle.kts`; Gradle downloads a missing JDK through the foojay resolver, and CI installs both. An optional `minecraft_compat` in a version's `gradle.properties` widens the Minecraft versions its jar loads on, as 26.1's does for its hotfixes.
|
||||||
|
|
||||||
## Mappings
|
## Mappings
|
||||||
|
|
||||||
Every version is built with Mojang's official names (`loom.officialMojangMappings()`), the names Minecraft itself ships from 26.1 on. Yarn isn't used any more: 1.21.11 has the last Yarn release.
|
Every version is built with Mojang's official names (`loom.officialMojangMappings()`), the names Minecraft itself ships from 26.1 on. Yarn isn't used any more: 1.21.11 has the last Yarn release.
|
||||||
|
|
||||||
Mojang renamed a few classes within 1.21.x. `src/` uses the newest names, and `stonecutter.gradle.kts` lists replacements that swap in the older name when Stonecutter processes an older version (for example `Identifier`, which was `ResourceLocation` before 1.21.11, and `AvatarRenderState`, which was `PlayerRenderState` before 1.21.9). Add a replacement there when a rename touches many lines. A class that only moved package needs just a version comment on its import, and a renamed method a version comment where it's called.
|
Mojang renames things between versions. `src/` uses the active version's (1.21.11's) names, and `stonecutter.gradle.kts` lists replacements that swap in each version's name when Stonecutter processes it: for example `Identifier`, which was `ResourceLocation` before 1.21.11, `AvatarRenderState`, which was `PlayerRenderState` before 1.21.9, and `GuiGraphics`, which is `GuiGraphicsExtractor` from 26.1. Add a replacement there when a rename touches many lines. A class that only moved package needs just a version comment on its import, and a renamed method a version comment where it's called.
|
||||||
|
|
||||||
Released jars run on intermediary names (`method_1234`), not Mojang's, and Loom renames everything that refers to Minecraft when it builds them. So a mixin can't implement one of `common`'s Ref interfaces by relying on a vanilla method that happens to have the same name: the vanilla method is renamed in the jar, and the interface method is left without an implementation (`AbstractMethodError`). Shadow the vanilla method and implement the Ref method explicitly, as `WindowMixin` does. For the same reason, Ref methods mustn't share a name and parameters with a method of the class they're mixed into, or the mixin replaces the vanilla method in development.
|
Released 1.21.x jars run on intermediary names (`method_1234`), not Mojang's, and Loom renames everything that refers to Minecraft when it builds them. So a mixin can't implement one of `common`'s Ref interfaces by relying on a vanilla method that happens to have the same name: the vanilla method is renamed in the jar, and the interface method is left without an implementation (`AbstractMethodError`). Shadow the vanilla method and implement the Ref method explicitly, as `WindowMixin` does. For the same reason, Ref methods mustn't share a name and parameters with a method of the class they're mixed into, or the mixin replaces the vanilla method in development.
|
||||||
|
|
||||||
## Version-specific code with Stonecutter
|
## Version-specific code with Stonecutter
|
||||||
|
|
||||||
@@ -72,5 +74,5 @@ For bigger changes, `./gradlew buildAll` builds every version's jar into `build/
|
|||||||
|
|
||||||
1. Create `versions/<new>/gradle.properties` with `minecraft_version`, `loader_version` and `fabric_api_version` (copy 1.21.11's and change the values; they're listed at <https://fabricmc.net/develop>). Loom's version is shared, in the root `gradle.properties`.
|
1. Create `versions/<new>/gradle.properties` with `minecraft_version`, `loader_version` and `fabric_api_version` (copy 1.21.11's and change the values; they're listed at <https://fabricmc.net/develop>). Loom's version is shared, in the root `gradle.properties`.
|
||||||
2. Add `<new>` to `stonecutterVersions` in `settings.gradle.kts`.
|
2. Add `<new>` to `stonecutterVersions` in `settings.gradle.kts`.
|
||||||
3. Build it with `./gradlew :<new>:compileJava` and put what Minecraft changed behind version comments. Check the mixin configs in `src/main/resources/*.mixins.json` as well: a mixin whose target changed fails at startup, not at compile time, so launch it with `./gradlew :<new>:runClient`.
|
3. Build it with `./gradlew :<new>:compileJava` and put what Minecraft changed behind version comments. Check the mixin configs in `src/main/resources/*.mixins.json` as well: a mixin whose target changed fails at startup (or when its class first loads, such as in a world), not at compile time, so launch it with `./gradlew :<new>:runClient`.
|
||||||
4. The release workflow builds everything through `buildAll`, and "Publish to Modrinth" takes the game version from each jar's name, so neither needs changing.
|
4. The release workflow builds everything through `buildAll`, and "Publish to Modrinth" takes the game version from each jar's name, so neither needs changing.
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ include("common")
|
|||||||
// versions/<v>/gradle.properties holds its Minecraft, Fabric Loader and Fabric API versions.
|
// versions/<v>/gradle.properties holds its Minecraft, Fabric Loader and Fabric API versions.
|
||||||
val stonecutterVersions = listOf(
|
val stonecutterVersions = listOf(
|
||||||
"1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11",
|
"1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11",
|
||||||
|
"26.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
stonecutter {
|
stonecutter {
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ public class ShaderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static RenderType entityAlpha(Identifier texture) {
|
private static RenderType entityAlpha(Identifier texture) {
|
||||||
//? if >=1.21.11 {
|
// 26.1 dropped the dragon's alpha pipeline; with opaque vertices it's an alpha cutout.
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*return RenderTypes.entityCutout(texture);
|
||||||
|
*///?} else if >=1.21.11 {
|
||||||
return RenderTypes.dragonExplosionAlpha(texture);
|
return RenderTypes.dragonExplosionAlpha(texture);
|
||||||
//?} else
|
//?} else
|
||||||
//return RenderType.dragonExplosionAlpha(texture);
|
//return RenderType.dragonExplosionAlpha(texture);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.saturnclient.impl.features.mixins.entity;
|
package org.saturnclient.impl.features.mixins.entity;
|
||||||
|
|
||||||
import org.saturnclient.impl.features.entity.CameraOverriddenEntity;
|
import org.saturnclient.impl.features.entity.CameraOverriddenEntity;
|
||||||
|
import org.saturnclient.impl.features.render.ZoomFov;
|
||||||
import org.saturnclient.mod.mods.FreelookMod;
|
import org.saturnclient.mod.mods.FreelookMod;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -9,6 +10,8 @@ import org.spongepowered.asm.mixin.Unique;
|
|||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
//? if >=26.1
|
||||||
|
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
@@ -26,17 +29,38 @@ public abstract class CameraMixin {
|
|||||||
@Shadow
|
@Shadow
|
||||||
protected abstract void setRotation(float yaw, float pitch);
|
protected abstract void setRotation(float yaw, float pitch);
|
||||||
|
|
||||||
|
// Freelook keeps the camera's rotation after vanilla points it along the entity's view. From 26.1
|
||||||
|
// that happens in alignWithEntity, which takes the camera's own entity.
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*@Shadow
|
||||||
|
public abstract Entity entity();
|
||||||
|
|
||||||
|
@Inject(method = "alignWithEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
|
||||||
|
public void lockRotation(float tickDelta, CallbackInfo ci) {
|
||||||
|
saturn$lockRotation(entity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The camera works out the FOV from 26.1 (GameRenderer.getFov before).
|
||||||
|
@Inject(method = "calculateFov", at = @At("RETURN"), cancellable = true)
|
||||||
|
private void onCalculateFov(float tickDelta, CallbackInfoReturnable<Float> cir) {
|
||||||
|
cir.setReturnValue(ZoomFov.apply(cir.getReturnValue()));
|
||||||
|
}
|
||||||
|
*///?} else if >=1.21.11 {
|
||||||
@Inject(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
|
@Inject(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
|
||||||
public void lockRotation(
|
public void lockRotation(Level focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing,
|
||||||
//? if >=1.21.11 {
|
float tickDelta, CallbackInfo ci) {
|
||||||
Level focusedBlock,
|
saturn$lockRotation(cameraEntity);
|
||||||
//?} else
|
}
|
||||||
//BlockGetter focusedBlock,
|
//?} else {
|
||||||
Entity cameraEntity,
|
/*@Inject(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
|
||||||
boolean isThirdPerson,
|
public void lockRotation(BlockGetter focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing,
|
||||||
boolean isFrontFacing,
|
float tickDelta, CallbackInfo ci) {
|
||||||
float tickDelta,
|
saturn$lockRotation(cameraEntity);
|
||||||
CallbackInfo ci) {
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void saturn$lockRotation(Entity cameraEntity) {
|
||||||
if (FreelookMod.isFreeLooking() && cameraEntity instanceof LocalPlayer) {
|
if (FreelookMod.isFreeLooking() && cameraEntity instanceof LocalPlayer) {
|
||||||
CameraOverriddenEntity cameraOverriddenEntity = (CameraOverriddenEntity) cameraEntity;
|
CameraOverriddenEntity cameraOverriddenEntity = (CameraOverriddenEntity) cameraEntity;
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import net.minecraft.client.renderer.GameRenderer;
|
|||||||
|
|
||||||
//? if >=1.21.6
|
//? if >=1.21.6
|
||||||
import org.saturnclient.impl.ui.SaturnScreenFabric;
|
import org.saturnclient.impl.ui.SaturnScreenFabric;
|
||||||
import org.saturnclient.mod.mods.FreelookMod;
|
import org.saturnclient.impl.features.render.ZoomFov;
|
||||||
import org.saturnclient.mod.mods.ZoomMod;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -18,11 +17,11 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
|||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the game's field-of-view when {@link ZoomMod} is active.
|
* Overrides the game's field-of-view when {@link org.saturnclient.mod.mods.ZoomMod} is active.
|
||||||
*
|
*
|
||||||
* The old code checked both {@code Zoom.isZooming} and
|
* The old code checked both {@code Zoom.isZooming} and
|
||||||
* {@code Zoom.shouldZoom()} separately. The refactored
|
* {@code Zoom.shouldZoom()} separately. The refactored
|
||||||
* {@link ZoomMod#shouldZoom()} already ORs both conditions
|
* {@link org.saturnclient.mod.mods.ZoomMod#shouldZoom()} already ORs both conditions
|
||||||
* ({@code enabled.value && isZooming}), so only one check is needed.
|
* ({@code enabled.value && isZooming}), so only one check is needed.
|
||||||
*
|
*
|
||||||
* No {@link org.saturnclient.common.module.ModProvider} is required
|
* No {@link org.saturnclient.common.module.ModProvider} is required
|
||||||
@@ -36,20 +35,21 @@ public class GameRendererMixin {
|
|||||||
* After the vanilla FOV has been computed, divide it by the zoom
|
* After the vanilla FOV has been computed, divide it by the zoom
|
||||||
* level to produce the narrowed field-of-view.
|
* level to produce the narrowed field-of-view.
|
||||||
*/
|
*/
|
||||||
|
// From 26.1 the camera works out the FOV, so CameraMixin applies the zoom there.
|
||||||
|
//? if <26.1 {
|
||||||
@Inject(method = "getFov", at = @At("RETURN"), cancellable = true)
|
@Inject(method = "getFov", at = @At("RETURN"), cancellable = true)
|
||||||
private void onGetFov(CallbackInfoReturnable<Float> cir) {
|
private void onGetFov(CallbackInfoReturnable<Float> cir) {
|
||||||
if (ZoomMod.shouldZoom()) {
|
cir.setReturnValue(ZoomFov.apply(cir.getReturnValue()));
|
||||||
float zoomedFov = cir.getReturnValue() / ZoomMod.getZoomLevel();
|
|
||||||
cir.setReturnValue(zoomedFov);
|
|
||||||
} else if (FreelookMod.shouldZoomOut()) {
|
|
||||||
float zoomedFov = cir.getReturnValue() / FreelookMod.getZoomLevel();
|
|
||||||
cir.setReturnValue(zoomedFov);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//?}
|
||||||
|
|
||||||
//? if >=1.21.6 {
|
//? if >=1.21.6 {
|
||||||
// From 1.21.6 the menu blur's strength is the vanilla setting, read here every frame. While a
|
// From 1.21.6 the menu blur's strength is the vanilla setting, read here every frame. While a
|
||||||
// Saturn screen is open, it's Saturn's background blur instead, faded in with the screen.
|
// Saturn screen is open, it's Saturn's background blur instead, faded in with the screen.
|
||||||
|
// From 26.1 the setting is read while extracting the options' render state.
|
||||||
|
//? if >=26.1
|
||||||
|
//@Redirect(method = "extractOptions", at = @At(value = "INVOKE",
|
||||||
|
//? if <26.1
|
||||||
@Redirect(method = "render", at = @At(value = "INVOKE",
|
@Redirect(method = "render", at = @At(value = "INVOKE",
|
||||||
target = "Lnet/minecraft/client/Options;getMenuBackgroundBlurriness()I"))
|
target = "Lnet/minecraft/client/Options;getMenuBackgroundBlurriness()I"))
|
||||||
private int useSaturnBlur(Options options) {
|
private int useSaturnBlur(Options options) {
|
||||||
|
|||||||
+10
@@ -3,6 +3,9 @@ package org.saturnclient.impl.features.mixins.render;
|
|||||||
// Code approach adapted from Gamma Utils: https://github.com/Sjouwer/gamma-utils
|
// Code approach adapted from Gamma Utils: https://github.com/Sjouwer/gamma-utils
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*import net.minecraft.client.renderer.LightmapRenderStateExtractor;
|
||||||
|
*///?} else
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
import org.saturnclient.mod.mods.FullbrightMod;
|
import org.saturnclient.mod.mods.FullbrightMod;
|
||||||
@@ -18,6 +21,10 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||||||
* it is now {@link FullbrightMod}. The injection target and
|
* it is now {@link FullbrightMod}. The injection target and
|
||||||
* strategy are unchanged.
|
* strategy are unchanged.
|
||||||
*/
|
*/
|
||||||
|
// From 26.1 the gamma is worked out while extracting the lightmap's render state.
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*@Mixin(LightmapRenderStateExtractor.class)
|
||||||
|
*///?} else
|
||||||
@Mixin(LightTexture.class)
|
@Mixin(LightTexture.class)
|
||||||
public class LightmapTextureManagerMixin {
|
public class LightmapTextureManagerMixin {
|
||||||
|
|
||||||
@@ -25,6 +32,9 @@ public class LightmapTextureManagerMixin {
|
|||||||
* If fullbright is active, substitute the feature's brightness
|
* If fullbright is active, substitute the feature's brightness
|
||||||
* value for whatever vanilla calculated.
|
* value for whatever vanilla calculated.
|
||||||
*/
|
*/
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*@ModifyExpressionValue(method = "extract", at = @At(value = "INVOKE", target = "Ljava/lang/Math;max(FF)F", ordinal = 0))
|
||||||
|
*///?} else
|
||||||
@ModifyExpressionValue(method = "updateLightTexture", at = @At(value = "INVOKE", target = "Ljava/lang/Math;max(FF)F", ordinal = 0))
|
@ModifyExpressionValue(method = "updateLightTexture", at = @At(value = "INVOKE", target = "Ljava/lang/Math;max(FF)F", ordinal = 0))
|
||||||
private float modifyGamma(float original) {
|
private float modifyGamma(float original) {
|
||||||
if (FullbrightMod.shouldOverrideBrightness()) {
|
if (FullbrightMod.shouldOverrideBrightness()) {
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(Gui.class)
|
@Mixin(Gui.class)
|
||||||
public class RenderMixin {
|
public class RenderMixin {
|
||||||
|
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*@Inject(method = "extractChat", at = @At("TAIL"))
|
||||||
|
*///?} else
|
||||||
@Inject(method = "renderChat", at = @At("TAIL"))
|
@Inject(method = "renderChat", at = @At("TAIL"))
|
||||||
public void renderMods(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) {
|
public void renderMods(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) {
|
||||||
Font textRenderer = SaturnClient.client.font;
|
Font textRenderer = SaturnClient.client.font;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.saturnclient.impl.features.render;
|
||||||
|
|
||||||
|
import org.saturnclient.mod.mods.FreelookMod;
|
||||||
|
import org.saturnclient.mod.mods.ZoomMod;
|
||||||
|
|
||||||
|
/** The zoom mods' change to the field of view, applied where each version computes it. */
|
||||||
|
public final class ZoomFov {
|
||||||
|
private ZoomFov() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float apply(float fov) {
|
||||||
|
if (ZoomMod.shouldZoom()) {
|
||||||
|
return fov / ZoomMod.getZoomLevel();
|
||||||
|
} else if (FreelookMod.shouldZoomOut()) {
|
||||||
|
return fov / FreelookMod.getZoomLevel();
|
||||||
|
}
|
||||||
|
return fov;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,6 +92,9 @@ public abstract class MinecraftClientMixin implements MinecraftClientRef {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Options:
|
case Options:
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*this.setScreen(new OptionsScreen(exitTarget, this.options, ((Minecraft) (Object) this).level != null));
|
||||||
|
*///?} else
|
||||||
this.setScreen(new OptionsScreen(exitTarget, this.options));
|
this.setScreen(new OptionsScreen(exitTarget, this.options));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ import net.minecraft.client.renderer.PostChain;
|
|||||||
import net.minecraft.client.renderer.RenderPipelines;
|
import net.minecraft.client.renderer.RenderPipelines;
|
||||||
import com.mojang.blaze3d.pipeline.TextureTarget;
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||||
import net.minecraft.client.renderer.LevelTargetBundle;
|
import net.minecraft.client.renderer.LevelTargetBundle;
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*import net.minecraft.client.renderer.Projection;
|
||||||
|
import net.minecraft.client.renderer.ProjectionMatrixBuffer;
|
||||||
|
*///?} else
|
||||||
import net.minecraft.client.renderer.CachedOrthoProjectionMatrixBuffer;
|
import net.minecraft.client.renderer.CachedOrthoProjectionMatrixBuffer;
|
||||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||||
import net.minecraft.client.gui.render.TextureSetup;
|
import net.minecraft.client.gui.render.TextureSetup;
|
||||||
@@ -54,6 +58,15 @@ public final class GlassRenderer {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
private static final Identifier BLUR = Identifier.withDefaultNamespace("post_effect/blur.json");
|
private static final Identifier BLUR = Identifier.withDefaultNamespace("post_effect/blur.json");
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*private static final Projection PROJECTION = new Projection();
|
||||||
|
private static final ProjectionMatrixBuffer PROJECTION_BUFFER = new ProjectionMatrixBuffer("saturn glass");
|
||||||
|
|
||||||
|
static {
|
||||||
|
// As vanilla sets up its post chains' projection; the chain sizes it when it runs.
|
||||||
|
PROJECTION.setupOrtho(0.1f, 1000f, 1f, 1f, false);
|
||||||
|
}
|
||||||
|
*///?} else
|
||||||
private static final CachedOrthoProjectionMatrixBuffer PROJECTION = new CachedOrthoProjectionMatrixBuffer("saturn glass", 0.1f, 1000f, false);
|
private static final CachedOrthoProjectionMatrixBuffer PROJECTION = new CachedOrthoProjectionMatrixBuffer("saturn glass", 0.1f, 1000f, false);
|
||||||
// For the blurs' intermediate targets, freed once unused for a few frames
|
// For the blurs' intermediate targets, freed once unused for a few frames
|
||||||
private static final CrossFrameResourcePool POOL = new CrossFrameResourcePool(3);
|
private static final CrossFrameResourcePool POOL = new CrossFrameResourcePool(3);
|
||||||
@@ -140,6 +153,9 @@ public final class GlassRenderer {
|
|||||||
|
|
||||||
PostChainConfig pipeline = PostChainConfig.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow();
|
PostChainConfig pipeline = PostChainConfig.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow();
|
||||||
return PostChain.load(pipeline, SaturnClient.client.getTextureManager(),
|
return PostChain.load(pipeline, SaturnClient.client.getTextureManager(),
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*LevelTargetBundle.MAIN_TARGETS, Identifier.fromNamespaceAndPath("saturnclient", "glass_blur_" + blur), PROJECTION, PROJECTION_BUFFER);
|
||||||
|
*///?} else
|
||||||
LevelTargetBundle.MAIN_TARGETS, Identifier.fromNamespaceAndPath("saturnclient", "glass_blur_" + blur), PROJECTION);
|
LevelTargetBundle.MAIN_TARGETS, Identifier.fromNamespaceAndPath("saturnclient", "glass_blur_" + blur), PROJECTION);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Couldn't load the glass blur", e);
|
SaturnClient.LOGGER.error("Couldn't load the glass blur", e);
|
||||||
|
|||||||
@@ -325,6 +325,9 @@ public class RenderScopeImpl implements RenderScope {
|
|||||||
entity, seed);
|
entity, seed);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*this.state.submitItem(new GuiItemRenderState(
|
||||||
|
*///?} else
|
||||||
this.state.submitItem(new GuiItemRenderState(stack.getItem().getName().toString(),
|
this.state.submitItem(new GuiItemRenderState(stack.getItem().getName().toString(),
|
||||||
new Matrix3x2f(this.matrices.stack), keyedItemRenderState, x, y,
|
new Matrix3x2f(this.matrices.stack), keyedItemRenderState, x, y,
|
||||||
this.scissorStack.peekLast()));
|
this.scissorStack.peekLast()));
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import net.minecraft.client.Minecraft;
|
|||||||
import net.minecraft.client.input.MouseButtonEvent;
|
import net.minecraft.client.input.MouseButtonEvent;
|
||||||
import net.minecraft.client.renderer.CubeMap;
|
import net.minecraft.client.renderer.CubeMap;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*import net.minecraft.client.renderer.Panorama;
|
||||||
|
*///?} else
|
||||||
import net.minecraft.client.renderer.PanoramaRenderer;
|
import net.minecraft.client.renderer.PanoramaRenderer;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
//? if >=1.21.6 {
|
//? if >=1.21.6 {
|
||||||
@@ -34,13 +37,18 @@ import net.minecraft.resources.Identifier;
|
|||||||
public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
||||||
protected static final Identifier PANORAMA = Identifier.fromNamespaceAndPath("saturnclient",
|
protected static final Identifier PANORAMA = Identifier.fromNamespaceAndPath("saturnclient",
|
||||||
"textures/gui/title/background/panorama");
|
"textures/gui/title/background/panorama");
|
||||||
protected static final CubeMap PANORAMA_RENDERER = new CubeMap(PANORAMA);
|
public static final CubeMap PANORAMA_RENDERER = new CubeMap(PANORAMA);
|
||||||
|
|
||||||
|
// From 26.1 vanilla draws the panorama from its own cube map; GuiRendererMixin swaps in Saturn's.
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*public static final Panorama ROTATING_PANORAMA_RENDERER = new Panorama();
|
||||||
|
*///?} else {
|
||||||
public static final PanoramaRenderer ROTATING_PANORAMA_RENDERER;
|
public static final PanoramaRenderer ROTATING_PANORAMA_RENDERER;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ROTATING_PANORAMA_RENDERER = new PanoramaRenderer(PANORAMA_RENDERER);
|
ROTATING_PANORAMA_RENDERER = new PanoramaRenderer(PANORAMA_RENDERER);
|
||||||
}
|
}
|
||||||
|
//?}
|
||||||
|
|
||||||
//? if <1.21.6
|
//? if <1.21.6
|
||||||
//private final CrossFrameResourcePool pool = new CrossFrameResourcePool(3);
|
//private final CrossFrameResourcePool pool = new CrossFrameResourcePool(3);
|
||||||
@@ -81,6 +89,9 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
//? if <1.21.6
|
//? if <1.21.6
|
||||||
//@SuppressWarnings("deprecation")
|
//@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*public void extractRenderState(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
|
*///?} else
|
||||||
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
if (screen.start == null) {
|
if (screen.start == null) {
|
||||||
screen.start = Instant.now();
|
screen.start = Instant.now();
|
||||||
@@ -128,10 +139,16 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
// Vanilla's background would cover Saturn's panorama, and blurs by the vanilla setting. The
|
// Vanilla's background would cover Saturn's panorama, and blurs by the vanilla setting. The
|
||||||
// strength of this blur comes from GameRendererMixin, which gives Saturn's setting instead.
|
// strength of this blur comes from GameRendererMixin, which gives Saturn's setting instead.
|
||||||
@Override
|
@Override
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*public void extractBackground(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
|
*///?} else
|
||||||
public void renderBackground(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
public void renderBackground(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
// The panorama renderer has no opacity (and takes no delta) from 1.21.6, so it's drawn fully
|
// The panorama renderer has no opacity (and takes no delta) from 1.21.6, so it's drawn fully
|
||||||
// opaque.
|
// opaque.
|
||||||
if (isShowingPanorama()) {
|
if (isShowingPanorama()) {
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*ROTATING_PANORAMA_RENDERER.extractRenderState(context, this.width, this.height, true);
|
||||||
|
*///?} else
|
||||||
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, true);
|
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +157,9 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (minecraft.level != null) {
|
if (minecraft.level != null) {
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*extractMenuBackground(context);
|
||||||
|
*///?} else
|
||||||
renderMenuBackground(context);
|
renderMenuBackground(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.saturnclient.saturnclient.event;
|
package org.saturnclient.saturnclient.event;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper;
|
||||||
|
*///?} else
|
||||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
import net.minecraft.client.KeyMapping;
|
import net.minecraft.client.KeyMapping;
|
||||||
import com.mojang.blaze3d.platform.InputConstants;
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
@@ -32,7 +35,13 @@ public class KeyInputHandler {
|
|||||||
private static KeyMapping mainMenuKeyBinding;
|
private static KeyMapping mainMenuKeyBinding;
|
||||||
|
|
||||||
public static void register() {
|
public static void register() {
|
||||||
//? if >=1.21.9 {
|
//? if >=26.1 {
|
||||||
|
/*mainMenuKeyBinding = KeyMappingHelper.registerKeyMapping(
|
||||||
|
new KeyMapping(
|
||||||
|
MAIN_MENU_KEY_ID,
|
||||||
|
DEFAULT_MENU_KEY,
|
||||||
|
KeyMapping.Category.register(KEY_CATEGORY)));
|
||||||
|
*///?} else if >=1.21.9 {
|
||||||
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(
|
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(
|
||||||
new KeyMapping(
|
new KeyMapping(
|
||||||
MAIN_MENU_KEY_ID,
|
MAIN_MENU_KEY_ID,
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.saturnclient.saturnclient.mixin;
|
||||||
|
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.render.GuiRenderer;
|
||||||
|
import net.minecraft.client.renderer.CubeMap;
|
||||||
|
import org.saturnclient.impl.ui.SaturnScreenFabric;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
*///?} else
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From 26.1 GuiRenderer draws the menu panorama from its own cube map, which is vanilla's. While a
|
||||||
|
* Saturn screen is open, this draws Saturn's panorama instead. Before 26.1 SaturnScreenFabric draws
|
||||||
|
* the panorama itself, so this mixin is empty there, and it targets Minecraft because GuiRenderer
|
||||||
|
* doesn't exist before 1.21.6. It stays registered, keeping saturnclient.mixins.json the same for
|
||||||
|
* every version.
|
||||||
|
*/
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*@Mixin(GuiRenderer.class)
|
||||||
|
public class GuiRendererMixin {
|
||||||
|
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/CubeMap;render(FF)V"))
|
||||||
|
private void saturn$drawSaturnPanorama(CubeMap cubeMap, float xRot, float yRot, Operation<Void> original) {
|
||||||
|
boolean saturnScreen = Minecraft.getInstance().screen instanceof SaturnScreenFabric;
|
||||||
|
original.call(saturnScreen ? SaturnScreenFabric.PANORAMA_RENDERER : cubeMap, xRot, yRot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*///?} else {
|
||||||
|
@Mixin(Minecraft.class)
|
||||||
|
public class GuiRendererMixin {
|
||||||
|
}
|
||||||
|
//?}
|
||||||
@@ -54,6 +54,9 @@ public abstract class SplashOverlayMixin {
|
|||||||
* @reason Replace vanilla splash rendering completely but keep exit logic
|
* @reason Replace vanilla splash rendering completely but keep exit logic
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*public void extractRenderState(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
|
*///?} else
|
||||||
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
int screenWidth = context.guiWidth();
|
int screenWidth = context.guiWidth();
|
||||||
int screenHeight = context.guiHeight();
|
int screenHeight = context.guiHeight();
|
||||||
@@ -116,6 +119,9 @@ public abstract class SplashOverlayMixin {
|
|||||||
|
|
||||||
private void renderCurrentScreen(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
private void renderCurrentScreen(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
if (minecraft.screen != null) {
|
if (minecraft.screen != null) {
|
||||||
|
//? if >=26.1 {
|
||||||
|
/*minecraft.screen.extractRenderState(context, mouseX, mouseY, delta);
|
||||||
|
*///?} else
|
||||||
minecraft.screen.render(context, mouseX, mouseY, delta);
|
minecraft.screen.render(context, mouseX, mouseY, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +135,9 @@ public abstract class SplashOverlayMixin {
|
|||||||
private void renderProgressBar(RenderScope scope, GuiGraphics context, int screenWidth, int screenHeight,
|
private void renderProgressBar(RenderScope scope, GuiGraphics context, int screenWidth, int screenHeight,
|
||||||
int alpha) {
|
int alpha) {
|
||||||
int progressY = ((screenHeight - 5) / 2) + 25;
|
int progressY = ((screenHeight - 5) / 2) + 25;
|
||||||
//? if >=1.21.11 {
|
//? if >=26.1 {
|
||||||
|
/*context.outline((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
||||||
|
*///?} else if >=1.21.11 {
|
||||||
context.renderOutline((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
context.renderOutline((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
||||||
//?} else if >=1.21.9 {
|
//?} else if >=1.21.9 {
|
||||||
/*context.submitOutline((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
/*context.submitOutline((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
||||||
|
|||||||
+10
-3
@@ -6,16 +6,23 @@ plugins {
|
|||||||
// "Reset active project" before committing.
|
// "Reset active project" before committing.
|
||||||
stonecutter active "1.21.11"
|
stonecutter active "1.21.11"
|
||||||
|
|
||||||
// src/ uses the newest Mojang names. These classes were renamed in the versions given, so Stonecutter
|
// src/ uses 1.21.11's Mojang names (the active version). These names changed in the versions given,
|
||||||
// swaps in the older names when it processes an older version.
|
// so Stonecutter swaps in each version's name when it processes it.
|
||||||
stonecutter parameters {
|
stonecutter parameters {
|
||||||
for ((since, old, new) in listOf(
|
for ((since, old, new) in listOf(
|
||||||
Triple("1.21.11", "ResourceLocation", "Identifier"),
|
Triple("1.21.11", "ResourceLocation", "Identifier"),
|
||||||
Triple("1.21.9", "PlayerRenderer", "AvatarRenderer"),
|
Triple("1.21.9", "PlayerRenderer", "AvatarRenderer"),
|
||||||
Triple("1.21.9", "PlayerRenderState", "AvatarRenderState"),
|
Triple("1.21.9", "PlayerRenderState", "AvatarRenderState"),
|
||||||
|
Triple("26.1", "GuiGraphics", "GuiGraphicsExtractor"),
|
||||||
|
Triple("26.1", "net.minecraft.client.gui.render.state", "net.minecraft.client.renderer.state.gui"),
|
||||||
|
// GuiRenderState's methods
|
||||||
|
Triple("26.1", "submitGuiElement", "addGuiElement"),
|
||||||
|
Triple("26.1", "submitText", "addText"),
|
||||||
|
Triple("26.1", "submitItem", "addItem"),
|
||||||
|
Triple("26.1", "submitPicturesInPictureState", "addPicturesInPictureState"),
|
||||||
)) {
|
)) {
|
||||||
replacements.regex(eval(current.version, ">=$since")) {
|
replacements.regex(eval(current.version, ">=$since")) {
|
||||||
replace("\\b$old\\b", new, "\\b$new\\b", old)
|
replace("\\b${Regex.escape(old)}\\b", new, "\\b${Regex.escape(new)}\\b", old)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Done to increase the memory available to gradle.
|
||||||
|
org.gradle.jvmargs=-Xmx1G
|
||||||
|
org.gradle.parallel=true
|
||||||
|
|
||||||
|
# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349
|
||||||
|
org.gradle.configuration-cache=false
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
minecraft_version=26.1
|
||||||
|
# Built against 26.1 and allowed on its hotfixes (26.1.1, 26.1.2).
|
||||||
|
minecraft_compat=~26.1
|
||||||
|
loader_version=0.19.5
|
||||||
|
|
||||||
|
fabric_api_version=0.145.1+26.1
|
||||||
|
|
||||||
|
# Mod Properties
|
||||||
|
maven_group=org.saturnclient
|
||||||
|
archives_base_name=saturn-client
|
||||||
Reference in New Issue
Block a user