├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── assets │ │ └── tiefix │ │ │ ├── icon.png │ │ │ ├── sizemap.bin │ │ │ ├── icon-large.png │ │ │ └── lang │ │ │ ├── zh_cn.json │ │ │ ├── en_us.json │ │ │ ├── tt_ru.json │ │ │ └── fr_fr.json │ ├── fabric.mod.json │ └── TieFix.mixins.json │ └── java │ └── ca │ └── jtai │ └── tiefix │ ├── fixes │ ├── mc122477 │ │ └── PollCounter.java │ └── mc89242 │ │ ├── SizemapDumper.java │ │ └── Sizemap.java │ ├── TieFixModMenu.java │ ├── mixin │ ├── mc122477 │ │ ├── RenderSystemMixin.java │ │ └── TextFieldWidgetMixin.java │ ├── mc122645 │ │ └── KeyboardMixin.java │ ├── mc203401 │ │ └── ClientPlayerEntityMixin.java │ ├── mc237493 │ │ ├── TelemetrySenderMixin.java │ │ └── UserPropertiesMixin.java │ ├── mc147766 │ │ └── TextFieldWidgetMixin.java │ ├── mc2071 │ │ └── ClientPlayerEntityMixin.java │ ├── mc62997 │ │ └── InGameHudMixin.java │ ├── mc12829 │ │ └── LivingEntityMixin.java │ ├── mc80859 │ │ └── HandledScreenMixin.java │ ├── mc79545 │ │ └── InGameHudMixin.java │ ├── mc89242 │ │ ├── KeyboardMixin.java │ │ └── AbstractSignEditScreenMixin.java │ ├── mc136249 │ │ └── LivingEntityMixin.java │ ├── mc127970 │ │ └── HeldItemRendererMixin.java │ ├── mc4490 │ │ └── FishingBobberEntityRendererMixin.java │ └── mc140646 │ │ └── TextFieldWidgetMixin.java │ ├── config │ ├── Config.java │ ├── ConfigHelper.java │ └── ConfigScreenBuilder.java │ └── TieFix.java ├── settings.gradle ├── gradle.properties ├── .github └── workflows │ └── gradle.yml ├── justfile ├── CONTRIBUTING.md ├── .gitignore ├── gradlew.bat ├── README.md ├── CHANGELOG.md ├── gradlew └── LICENSE /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-tai/TieFix/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-tai/TieFix/HEAD/src/main/resources/assets/tiefix/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/sizemap.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-tai/TieFix/HEAD/src/main/resources/assets/tiefix/sizemap.bin -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/icon-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-tai/TieFix/HEAD/src/main/resources/assets/tiefix/icon-large.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | jcenter() 4 | maven { 5 | name = 'Fabric' 6 | url = 'https://maven.fabricmc.net/' 7 | } 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/fixes/mc122477/PollCounter.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.fixes.mc122477; 2 | 3 | public class PollCounter { 4 | private static long count = 0; 5 | 6 | public static void increment() { 7 | count++; 8 | } 9 | 10 | public static long get() { 11 | return count; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | # Mod Properties 4 | mod_version=1.14.0 5 | maven_group=ca.jtai 6 | archives_base_name=TieFix 7 | 8 | # https://fabricmc.net/develop/ 9 | minecraft_version=1.20 10 | yarn_mappings=1.20+build.1 11 | loader_version=0.14.21 12 | fabric_version=0.83.0+1.20 13 | 14 | # Dependencies 15 | modmenu_version=7.0.1 16 | clothconfig_version=11.0.99 17 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/TieFixModMenu.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix; 2 | 3 | import ca.jtai.tiefix.config.ConfigScreenBuilder; 4 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 5 | import com.terraformersmc.modmenu.api.ModMenuApi; 6 | 7 | public class TieFixModMenu implements ModMenuApi { 8 | @Override 9 | public ConfigScreenFactory getModConfigScreenFactory() { 10 | return parent -> ConfigScreenBuilder.build(parent, TieFix.getConfig()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - uses: actions/setup-java@v2 13 | with: 14 | distribution: temurin 15 | java-version: 17 16 | cache: gradle 17 | 18 | - name: Build 19 | run: ./gradlew build --no-daemon 20 | 21 | - name: Upload artifacts 22 | uses: actions/upload-artifact@v2 23 | with: 24 | name: artifacts 25 | path: build/libs/*[0-9].jar 26 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc122477/RenderSystemMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc122477; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import ca.jtai.tiefix.fixes.mc122477.PollCounter; 5 | import com.mojang.blaze3d.systems.RenderSystem; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(value = RenderSystem.class, priority = TieFix.MIXIN_PRIORITY) 12 | public class RenderSystemMixin { 13 | @Inject(method = "pollEvents", at = @At("HEAD"), remap = false) 14 | private static void onPollEvents(CallbackInfo ci) { 15 | PollCounter.increment(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc122645/KeyboardMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc122645; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.Keyboard; 5 | import net.minecraft.client.util.NarratorManager; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | 10 | @Mixin(value = Keyboard.class, priority = TieFix.MIXIN_PRIORITY) 11 | public class KeyboardMixin { 12 | @Redirect(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/NarratorManager;isActive()Z")) 13 | private boolean isActiveProxy(NarratorManager instance) { 14 | if (TieFix.getConfig().mc122645_fix) { 15 | return false; 16 | } else { 17 | return instance.isActive(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc203401/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc203401; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.network.ClientPlayerEntity; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(value = ClientPlayerEntity.class, priority = TieFix.MIXIN_PRIORITY) 12 | public class ClientPlayerEntityMixin { 13 | @Shadow 14 | protected int ticksLeftToDoubleTapSprint; 15 | 16 | @Inject(method = "tickMovement", at = @At("HEAD")) 17 | private void onTickMovement(CallbackInfo ci) { 18 | if (TieFix.getConfig().mc203401_fix) { 19 | ticksLeftToDoubleTapSprint = 0; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc237493/TelemetrySenderMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc237493; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.util.telemetry.TelemetryManager; 5 | import net.minecraft.client.util.telemetry.TelemetrySender; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | @Mixin(value = TelemetryManager.class, priority = TieFix.MIXIN_PRIORITY) 12 | public class TelemetrySenderMixin { 13 | @Inject(method = "getSender", at = @At("HEAD"), cancellable = true) 14 | private void onGetSender(CallbackInfoReturnable cir) { 15 | if (TieFix.getConfig().mc237493_fix) { 16 | cir.setReturnValue(TelemetrySender.NOOP); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc237493/UserPropertiesMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc237493; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import com.mojang.authlib.minecraft.UserApiService; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | 10 | @Mixin(value = UserApiService.UserProperties.class, priority = TieFix.MIXIN_PRIORITY) 11 | public class UserPropertiesMixin { 12 | @Inject(method = "flag", at = @At("HEAD"), cancellable = true, remap = false) 13 | private void onFlag(UserApiService.UserFlag flag, CallbackInfoReturnable cir) { 14 | if (TieFix.getConfig().mc237493_fix && flag == UserApiService.UserFlag.TELEMETRY_ENABLED) { 15 | cir.setReturnValue(false); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "tiefix", 4 | "version": "${version}", 5 | "name": "TieFix", 6 | "description": "Fixes some annoying bugs", 7 | "authors": [ 8 | "j-tai" 9 | ], 10 | "contact": { 11 | "homepage": "https://github.com/j-tai/TieFix", 12 | "issues": "https://github.com/j-tai/TieFix/issues", 13 | "sources": "https://github.com/j-tai/TieFix" 14 | }, 15 | "license": "LGPL-3.0-only", 16 | "icon": "assets/tiefix/icon.png", 17 | "environment": "client", 18 | "entrypoints": { 19 | "client": [ 20 | "ca.jtai.tiefix.TieFix" 21 | ], 22 | "modmenu": [ 23 | "ca.jtai.tiefix.TieFixModMenu" 24 | ] 25 | }, 26 | "mixins": [ 27 | "TieFix.mixins.json" 28 | ], 29 | "depends": { 30 | "fabric-resource-loader-v0": "*", 31 | "minecraft": "~1.20" 32 | }, 33 | "recommends": { 34 | "modmenu": ">=6" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/resources/TieFix.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "ca.jtai.tiefix.mixin", 5 | "compatibilityLevel": "JAVA_8", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | "mc122477.RenderSystemMixin", 10 | "mc122477.TextFieldWidgetMixin", 11 | "mc122645.KeyboardMixin", 12 | "mc127970.HeldItemRendererMixin", 13 | "mc12829.LivingEntityMixin", 14 | "mc136249.LivingEntityMixin", 15 | "mc140646.TextFieldWidgetMixin", 16 | "mc147766.TextFieldWidgetMixin", 17 | "mc203401.ClientPlayerEntityMixin", 18 | "mc2071.ClientPlayerEntityMixin", 19 | "mc237493.TelemetrySenderMixin", 20 | "mc237493.UserPropertiesMixin", 21 | "mc4490.FishingBobberEntityRendererMixin", 22 | "mc62997.InGameHudMixin", 23 | "mc79545.InGameHudMixin", 24 | "mc80859.HandledScreenMixin", 25 | "mc89242.AbstractSignEditScreenMixin", 26 | "mc89242.KeyboardMixin" 27 | ], 28 | "injectors": { 29 | "defaultRequire": 0 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc147766/TextFieldWidgetMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc147766; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.gui.screen.Screen; 5 | import net.minecraft.client.gui.widget.TextFieldWidget; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(value = TextFieldWidget.class, priority = TieFix.MIXIN_PRIORITY) 13 | public class TextFieldWidgetMixin { 14 | @Shadow 15 | private boolean selecting; 16 | 17 | @Inject(method = "onClick", at = @At( 18 | value = "INVOKE", 19 | target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;setCursor(I)V" 20 | )) 21 | private void onKeyPressed(double mouseX, double mouseY, CallbackInfo ci) { 22 | if (TieFix.getConfig().mc147766_fix) { 23 | this.selecting = Screen.hasShiftDown(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc2071/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc2071; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gui.screen.Screen; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | 11 | @Mixin(value = ClientPlayerEntity.class, priority = TieFix.MIXIN_PRIORITY) 12 | public class ClientPlayerEntityMixin { 13 | @Redirect(method = "updateNausea", at = @At( 14 | value = "FIELD", 15 | target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", 16 | ordinal = 0 17 | )) 18 | private Screen onUpdateNausea(MinecraftClient instance) { 19 | if (TieFix.getConfig().mc2071_fix) { 20 | return null; // Pretend that there's no screen open 21 | } else { 22 | return instance.currentScreen; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc62997/InGameHudMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc62997; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gui.DrawContext; 6 | import net.minecraft.client.gui.hud.InGameHud; 7 | import net.minecraft.client.util.math.MatrixStack; 8 | import net.minecraft.scoreboard.ScoreboardObjective; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(value = InGameHud.class, priority = TieFix.MIXIN_PRIORITY) 15 | public class InGameHudMixin { 16 | @Inject(method = "renderScoreboardSidebar", at = @At("HEAD"), cancellable = true) 17 | private void onRenderScoreboardSidebar(DrawContext context, ScoreboardObjective objective, CallbackInfo ci) { 18 | if (TieFix.getConfig().mc62997_fix && MinecraftClient.getInstance().options.debugEnabled) { 19 | ci.cancel(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | gradle := "./gradlew" 2 | open := "xdg-open" 3 | today := `date +%Y-%m-%d` 4 | 5 | # Display this help message 6 | help: 7 | @just --list 8 | 9 | # Build the project 10 | build: 11 | {{gradle}} build 12 | 13 | # Run the mod 14 | run: build 15 | {{gradle}} runClient --console=plain 16 | 17 | # Decompile Minecraft 18 | decompile: 19 | {{gradle}} genSources 20 | 21 | # Publish to Modrinth and CurseForge 22 | publish: build 23 | {{gradle}} modrinth 24 | -{{open}} 'https://modrinth.com/mod/tiefix/versions' 25 | {{gradle}} curseforge 26 | -{{open}} 'https://legacy.curseforge.com/minecraft/mc-mods/tiefix/files' 27 | 28 | # Bump the version number and commit 29 | bump-version version: 30 | sed -i~ 's/^## master$/## v{{version}} ({{today}})/' CHANGELOG.md 31 | grep '^## v{{version}} ({{today}})$' CHANGELOG.md 32 | sed -i~ 's/^mod_version=.*$/mod_version={{version}}/' gradle.properties 33 | grep '^mod_version={{version}}$' gradle.properties 34 | @just build 35 | git add . 36 | git commit -m 'Bump version to {{version}}' 37 | git tag -s -m 'v{{version}}' 'v{{version}}' 38 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc12829/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc12829; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.entity.LivingEntity; 6 | import net.minecraft.entity.player.PlayerEntity; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | 12 | @Mixin(value = LivingEntity.class, priority = TieFix.MIXIN_PRIORITY) 13 | public class LivingEntityMixin { 14 | @Inject(method = "isClimbing", at = @At("HEAD"), cancellable = true) 15 | private void onIsClimbing(CallbackInfoReturnable cir) { 16 | if (TieFix.getConfig().mc12829_fix 17 | && (TieFix.getConfig().gameplayAllowMultiplayer || MinecraftClient.getInstance().isInSingleplayer())) { 18 | //noinspection ConstantConditions 19 | if ((Object) this instanceof PlayerEntity player && player.getAbilities().flying) { 20 | cir.setReturnValue(false); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to TieFix 2 | 3 | ## Adding a fix 4 | 5 | 1. Add a boolean field to `ca.jtai.tiefix.Config` that toggles the fix on or off. 6 | 2. Create the mixin(s) that fix the bug in `ca.jtai.tiefix.mixin`. Remember to set the mixin `priority` to `TieFix.MIXIN_PRIORITY`. Add the mixin(s) to `TieFix.mixins.json`. 7 | 3. Add the config option(s) to the options screen in `ca.jtai.tiefix.config.ConfigScreenBuilder`. 8 | 4. Add the name of the fix and the bug tracker ID to the language file, `assets/tiefix/lang/en_us.json`. 9 | 5. Add the fix to the README and changelog. 10 | 11 | ## Updating to a new Minecraft version 12 | 13 | 1. Edit `gradle.properties` and update the fields. There is a link provided in that file to get the updated values. 14 | 2. Update the Minecraft version in `fabric.mod.json`. 15 | 16 | ## Releasing a new version 17 | 18 | 1. Update the mod version in `gradle.properties` and change the `master` section to the version number in `CHANGELOG.md`. 19 | 2. `./gradlew modrinth` 20 | 3. `./gradlew curseforge` 21 | 4. Check that the publishing went well, and fix anything if needed 22 | 5. Copy the README into the mod description in Modrinth and CurseForge 23 | 6. Publish to GitHub releases 24 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc80859/HandledScreenMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc80859; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 5 | import net.minecraft.screen.slot.Slot; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | 12 | import java.util.Set; 13 | 14 | @Mixin(value = HandledScreen.class, priority = TieFix.MIXIN_PRIORITY) 15 | public class HandledScreenMixin { 16 | @Shadow 17 | protected boolean cursorDragging; 18 | @Shadow 19 | @Final 20 | protected Set cursorDragSlots; 21 | 22 | @Redirect(method = "drawSlot", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;cursorDragging:Z")) 23 | private boolean cursorDraggingProxy(HandledScreen instance) { 24 | assert instance == (Object) this; 25 | if (!TieFix.getConfig().mc80859_fix) { 26 | return cursorDragging; 27 | } 28 | return cursorDragging && cursorDragSlots.size() != 1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc79545/InGameHudMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc79545; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.gui.hud.InGameHud; 5 | import net.minecraft.client.network.ClientPlayerEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | 10 | @Mixin(value = InGameHud.class, priority = TieFix.MIXIN_PRIORITY) 11 | public class InGameHudMixin { 12 | @Redirect( 13 | method = "renderExperienceBar", 14 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getNextLevelExperience()I") 15 | ) 16 | private int getNextLevelExperienceProxy(ClientPlayerEntity instance) { 17 | if (!TieFix.getConfig().mc79545_fix) { 18 | return instance.getNextLevelExperience(); 19 | } 20 | // The game renders the XP bar if this value is positive. The value is not used for anything else, so we can 21 | // really return whatever we want here. I'm still keeping the call to getNextLevelExperience in case another 22 | // mod relies on that. 23 | return Math.max(1, instance.getNextLevelExperience()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc89242/KeyboardMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc89242; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import ca.jtai.tiefix.fixes.mc89242.SizemapDumper; 5 | import net.minecraft.client.Keyboard; 6 | import net.minecraft.client.MinecraftClient; 7 | import org.lwjgl.glfw.GLFW; 8 | import org.spongepowered.asm.mixin.Final; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.Shadow; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(value = Keyboard.class, priority = TieFix.MIXIN_PRIORITY) 16 | public class KeyboardMixin { 17 | @Shadow 18 | @Final 19 | private MinecraftClient client; 20 | 21 | /** 22 | * Dumps the font sizemap when F3 + X is pressed and the {@code debug} option in the config is {@code true}. 23 | */ 24 | @Inject(method = "processF3", at = @At("TAIL"), cancellable = true) 25 | private void onProcessF3(int key, CallbackInfoReturnable cir) { 26 | if (TieFix.getConfig().debug && key == GLFW.GLFW_KEY_X) { 27 | SizemapDumper.dump(client); 28 | cir.setReturnValue(true); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc89242/AbstractSignEditScreenMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc89242; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.block.entity.SignBlockEntity; 5 | import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.ModifyArg; 11 | 12 | import java.util.function.Predicate; 13 | 14 | @Mixin(value = AbstractSignEditScreen.class, priority = TieFix.MIXIN_PRIORITY) 15 | public class AbstractSignEditScreenMixin { 16 | @Shadow 17 | @Final 18 | private SignBlockEntity blockEntity; 19 | 20 | @ModifyArg(method = "init", at = @At( 21 | value = "INVOKE", 22 | target = "Lnet/minecraft/client/util/SelectionManager;(Ljava/util/function/Supplier;Ljava/util/function/Consumer;Ljava/util/function/Supplier;Ljava/util/function/Consumer;Ljava/util/function/Predicate;)V" 23 | ), index = 4) 24 | private Predicate stringFilterProxy(Predicate stringFilter) { 25 | if (!TieFix.getConfig().mc89242_fix) { 26 | return stringFilter; 27 | } 28 | 29 | return text -> TieFix.getSizemap().getWidth(text) <= blockEntity.getMaxTextWidth(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc136249/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc136249; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.enchantment.EnchantmentHelper; 6 | import net.minecraft.entity.LivingEntity; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | 12 | @Mixin(value = LivingEntity.class, priority = TieFix.MIXIN_PRIORITY) 13 | public class LivingEntityMixin { 14 | @Shadow 15 | protected int riptideTicks; 16 | 17 | @Redirect(method = "travel", at = @At( 18 | value = "INVOKE", 19 | target = "Lnet/minecraft/enchantment/EnchantmentHelper;getDepthStrider(Lnet/minecraft/entity/LivingEntity;)I" 20 | )) 21 | private int getDepthStriderProxy(LivingEntity entity) { 22 | if (riptideTicks == 0) { 23 | return EnchantmentHelper.getDepthStrider(entity); 24 | } 25 | 26 | var config = TieFix.getConfig(); 27 | var fixIsEnabled = config.mc136249_fix 28 | && (config.gameplayAllowMultiplayer || MinecraftClient.getInstance().isInSingleplayer()); 29 | if (fixIsEnabled) { 30 | return 0; 31 | } else { 32 | return EnchantmentHelper.getDepthStrider(entity); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc127970/HeldItemRendererMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc127970; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.network.AbstractClientPlayerEntity; 5 | import net.minecraft.client.render.item.HeldItemRenderer; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.item.Items; 8 | import net.minecraft.util.Hand; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | @Mixin(value = HeldItemRenderer.class, priority = TieFix.MIXIN_PRIORITY) 14 | public class HeldItemRendererMixin { 15 | @Redirect( 16 | method = "renderFirstPersonItem", 17 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;isUsingRiptide()Z") 18 | ) 19 | private boolean isUsingRiptideProxy( 20 | AbstractClientPlayerEntity obj, 21 | AbstractClientPlayerEntity player, 22 | float tickDelta, 23 | float pitch, 24 | Hand hand, 25 | float swingProgress, 26 | ItemStack item 27 | ) { 28 | if (!TieFix.getConfig().mc127970_fix || item.isOf(Items.TRIDENT)) { 29 | return obj.isUsingRiptide(); 30 | } 31 | // Assume the player is not using riptide for the purpose of rendering the first person held item 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/config/Config.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.config; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import net.minecraft.util.Util; 5 | 6 | public class Config { 7 | private int version = 0; 8 | 9 | /** 10 | * Whether to enable debug and development features. Off by default. 11 | *

12 | * This option is not shown in the settings screen. It can only be changed by editing the JSON config file. 13 | */ 14 | public boolean debug = false; 15 | 16 | /** 17 | * Enable gameplay fixes in multiplayer 18 | */ 19 | @SerializedName("mc136249_allowMultiplayer") // Compatibility with old config files 20 | public boolean gameplayAllowMultiplayer = false; 21 | 22 | public boolean mc2071_fix = true; 23 | public boolean mc4490_fix = true; 24 | public boolean mc12829_fix = true; 25 | public boolean mc62997_fix = true; 26 | public boolean mc79545_fix = true; 27 | public boolean mc80859_fix = true; 28 | public boolean mc89242_fix = true; 29 | public boolean mc122477_fix = Util.getOperatingSystem() == Util.OperatingSystem.LINUX; 30 | public String mc122477_keys = ""; 31 | public boolean mc122645_fix = true; 32 | public boolean mc127970_fix = true; 33 | public boolean mc136249_fix = true; 34 | public boolean mc140646_fix = true; 35 | public boolean mc147766_fix = true; 36 | public boolean mc203401_fix = false; 37 | public boolean mc237493_fix = true; 38 | 39 | /** 40 | * The default configuration. Do not mutate this object. 41 | */ 42 | public static final Config DEFAULT = new Config(); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc122477/TextFieldWidgetMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc122477; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import ca.jtai.tiefix.fixes.mc122477.PollCounter; 5 | import net.minecraft.client.font.TextRenderer; 6 | import net.minecraft.client.gui.widget.TextFieldWidget; 7 | import net.minecraft.text.Text; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(value = TextFieldWidget.class, priority = TieFix.MIXIN_PRIORITY) 15 | public class TextFieldWidgetMixin { 16 | private long tiefix_initialPoll = -1; 17 | 18 | @Inject(method = "(Lnet/minecraft/client/font/TextRenderer;IIIILnet/minecraft/client/gui/widget/TextFieldWidget;Lnet/minecraft/text/Text;)V", at = @At("RETURN")) 19 | private void onInit(TextRenderer textRenderer, int x, int y, int width, int height, TextFieldWidget copyFrom, Text text, CallbackInfo ci) { 20 | tiefix_initialPoll = PollCounter.get(); 21 | } 22 | 23 | @Inject(method = "charTyped", at = @At("HEAD"), cancellable = true) 24 | private void onCharTyped(char chr, int keyCode, CallbackInfoReturnable cir) { 25 | var config = TieFix.getConfig(); 26 | if (!config.mc122477_fix) { 27 | return; 28 | } 29 | 30 | // Deny typing blacklisted characters on the very first poll after initialization 31 | if (tiefix_initialPoll + 1 == PollCounter.get()) { 32 | var keys = config.mc122477_keys; 33 | if (keys.isEmpty() || keys.toLowerCase().indexOf(Character.toLowerCase(chr)) != -1) { 34 | // Return from the function early; ignore the key press 35 | cir.setReturnValue(true); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/fixes/mc89242/SizemapDumper.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.fixes.mc89242; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.text.Text; 5 | 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | 9 | public class SizemapDumper { 10 | /** 11 | * Create a sizemap for the currently loaded font, and write it to {@code sizemap.json}. 12 | *

13 | * This method prints debug messages to the client's chat window. The player must be in-game. 14 | */ 15 | public static void dump(MinecraftClient client) { 16 | var player = client.player; 17 | if (player == null) { 18 | return; 19 | } 20 | player.sendMessage(Text.of("TieFix: ENSURE RESOURCE PACKS ARE DISABLED!")); 21 | player.sendMessage(Text.of("TieFix: Dumping the sizemap...")); 22 | 23 | var sizemap = new Sizemap(); 24 | 25 | var renderer = client.textRenderer; 26 | for (var codepoint = 0; codepoint <= 0x10FFFF; ++codepoint) { 27 | var text = new String(Character.toChars(codepoint)); 28 | var width = renderer.getTextHandler().getWidth(text); 29 | // Sanity checks 30 | if (width < 0.5) { 31 | player.sendMessage(Text.of( 32 | "W: U+%04X '%s' has small or negative width %f".formatted(codepoint, text, width) 33 | )); 34 | } 35 | var roundedWidth = Math.ceil(width); 36 | var offset = Math.abs(roundedWidth - width); 37 | if (offset > 0.01) { 38 | player.sendMessage(Text.of( 39 | "W: U+%04X '%s' has non-integer width %f".formatted(codepoint, text, width) 40 | )); 41 | } 42 | sizemap.set(codepoint, (int) roundedWidth); 43 | } 44 | 45 | try { 46 | Files.write(Path.of("sizemap.bin"), sizemap.getBytes()); 47 | player.sendMessage(Text.of("Saved sizemap to sizemap.bin")); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc4490/FishingBobberEntityRendererMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc4490; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.render.entity.FishingBobberEntityRenderer; 5 | import net.minecraft.entity.projectile.FishingBobberEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.Constant; 8 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 9 | 10 | @Mixin(value = FishingBobberEntityRenderer.class, priority = TieFix.MIXIN_PRIORITY) 11 | public abstract class FishingBobberEntityRendererMixin { 12 | /** 13 | * When sneaking, the fishing rod is pulled inward slightly. Make the fishing line should respect that. 14 | */ 15 | @ModifyConstant( 16 | method = "render(Lnet/minecraft/entity/projectile/FishingBobberEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 17 | constant = @Constant(doubleValue = 0.8) 18 | ) 19 | private double applySneakContraction(double constant, FishingBobberEntity fishingBobberEntity) { 20 | if (!TieFix.getConfig().mc4490_fix) { 21 | return constant; 22 | } 23 | var player = fishingBobberEntity.getPlayerOwner(); 24 | var isSneaking = player != null && player.isInSneakingPose(); 25 | if (!isSneaking) { 26 | return constant; 27 | } 28 | return constant - 0.05; 29 | } 30 | 31 | /** 32 | * Move the fishing line down a bit more when sneaking. 33 | */ 34 | @ModifyConstant( 35 | method = "render(Lnet/minecraft/entity/projectile/FishingBobberEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 36 | constant = @Constant(floatValue = -0.1875f) 37 | ) 38 | private float applySneakYOffset(float constant) { 39 | if (!TieFix.getConfig().mc4490_fix) { 40 | return constant; 41 | } 42 | // No need to check for sneaking here, since this constant is only used when sneaking. 43 | return constant - 0.1f; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "options.tiefix.title": "TieFix 设置", 3 | "options.tiefix.category.ui": "UI & HUD", 4 | "options.tiefix.category.controls": "控制", 5 | "options.tiefix.category.audioVisual": "音频与视觉", 6 | "options.tiefix.category.gameplay": "游戏性和运动", 7 | "options.tiefix.category.misc": "杂项", 8 | "options.tiefix.mc2071": "允许在下界传送门中打开 GUI", 9 | "options.tiefix.mc2071.bug": "MC-2071", 10 | "options.tiefix.mc4490": "修复第三人称下的钓鱼线", 11 | "options.tiefix.mc4490.bug": "MC-4490", 12 | "options.tiefix.mc12829": "修复在梯子/藤蔓等处飞行缓慢的问题", 13 | "options.tiefix.mc12829.bug": "MC-12829", 14 | "options.tiefix.mc62997": "启用 F3 时隐藏记分版", 15 | "options.tiefix.mc62997.bug": "MC-62997", 16 | "options.tiefix.mc79545": "修复高等级经验的经验栏", 17 | "options.tiefix.mc79545.bug": "MC-79545", 18 | "options.tiefix.mc80859": "修复拖动时不可见的物品", 19 | "options.tiefix.mc80859.bug": "MC-80859", 20 | "options.tiefix.mc89242": "修复书写告示牌时的行数限制", 21 | "options.tiefix.mc89242.bug": "MC-89242", 22 | "options.tiefix.mc122477": "修复打开聊天时的 “t”(仅 Linux)", 23 | "options.tiefix.mc122477.bug": "MC-122477", 24 | "options.tiefix.mc122477_keys": "忽略的按键", 25 | "options.tiefix.mc122477.explanation": "当打开聊天后立即收到一个按键,只有在「忽略的按键」中找到它,它才会被忽略。如果此栏是空的,那么所有字符都会被忽略。如果您发现聊天提示有时会忽略您的第一次按键,那么请将其设置为您的背包、聊天和命令键(例如,\"et/\"),以及任何可能立即聚焦文本框的修改键。如果不确定,就留空。", 26 | "options.tiefix.mc122645": "禁用叙述者热键", 27 | "options.tiefix.mc122645.bug": "MC-122645", 28 | "options.tiefix.mc127970": "修复使用激流时物品脱手", 29 | "options.tiefix.mc127970.bug": "MC-127970", 30 | "options.tiefix.mc136249": "修复与深海探索者共用时的激流的速度", 31 | "options.tiefix.mc136249.bug": "MC-136249", 32 | "options.tiefix.mc140646": "选择文本时滚动文本字段", 33 | "options.tiefix.mc140646.bug": "MC-140646", 34 | "options.tiefix.mc147766": "修复文本框中卡住的 Shift 键", 35 | "options.tiefix.mc147766.bug": "MC-147766", 36 | "options.tiefix.mc203401": "禁用双击向前疾跑的功能", 37 | "options.tiefix.mc203401.bug": "MC-203401", 38 | "options.tiefix.mc237493": "禁用遥测(需要重启游戏)", 39 | "options.tiefix.mc237493.bug": "MC-237493", 40 | "options.tiefix.enableInMultiplayer": "在多人游戏中启用", 41 | "options.tiefix.mayTriggerAnticheat": "警告。在多人游戏中,这些修复可能会触发反作弊。请慎重使用。", 42 | "options.tiefix.reloadToApply": "重新加载资源(F3+T)以应用更改" 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/mixin/mc140646/TextFieldWidgetMixin.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.mixin.mc140646; 2 | 3 | import ca.jtai.tiefix.TieFix; 4 | import net.minecraft.client.gui.widget.TextFieldWidget; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.ModifyArg; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(value = TextFieldWidget.class, priority = TieFix.MIXIN_PRIORITY) 13 | public abstract class TextFieldWidgetMixin { 14 | @Shadow 15 | private boolean selecting; 16 | @Shadow 17 | private int selectionEnd; 18 | 19 | @Shadow 20 | public abstract void setSelectionEnd(int index); 21 | 22 | @Inject(method = "setCursor", at = @At( 23 | value = "INVOKE", 24 | target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;setSelectionStart(I)V", 25 | shift = At.Shift.AFTER 26 | )) 27 | private void onSetCursor(int cursor, CallbackInfo ci) { 28 | if (TieFix.getConfig().mc140646_fix && selecting) { 29 | // The logic for scrolling is contained in setSelectionEnd, so 30 | // we call it without modifying the actual selectionEnd field 31 | var end = selectionEnd; 32 | setSelectionEnd(cursor); 33 | selectionEnd = end; 34 | } 35 | } 36 | 37 | /** 38 | * Fixes the crash that occurs when the {@code selectionEnd} is outside the visible part of the text box. 39 | *

40 | * Such a situation is normally impossible in the vanilla game, but is possible with this fix enabled. 41 | *

42 | * See issue #7. 43 | */ 44 | @ModifyArg(method = "renderButton", at = @At( 45 | value = "INVOKE", 46 | target = "Ljava/lang/String;substring(II)Ljava/lang/String;", 47 | ordinal = 1 48 | ), index = 1) 49 | private int boundSelectionEnd(int relativeSelectionEnd) { 50 | if (TieFix.getConfig().mc140646_fix) { 51 | return Math.max(0, relativeSelectionEnd); 52 | } else { 53 | return relativeSelectionEnd; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/TieFix.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix; 2 | 3 | import ca.jtai.tiefix.config.Config; 4 | import ca.jtai.tiefix.config.ConfigHelper; 5 | import ca.jtai.tiefix.fixes.mc89242.Sizemap; 6 | import net.fabricmc.api.ClientModInitializer; 7 | import net.fabricmc.api.EnvType; 8 | import net.fabricmc.api.Environment; 9 | import net.fabricmc.fabric.api.resource.ResourceManagerHelper; 10 | import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; 11 | import net.minecraft.resource.ResourceManager; 12 | import net.minecraft.resource.ResourceType; 13 | import net.minecraft.util.Identifier; 14 | import org.apache.commons.io.IOUtils; 15 | 16 | @Environment(EnvType.CLIENT) 17 | public class TieFix implements ClientModInitializer { 18 | @Override 19 | public void onInitializeClient() { 20 | // Sizemap loader 21 | ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener( 22 | new SimpleSynchronousResourceReloadListener() { 23 | @Override 24 | public Identifier getFabricId() { 25 | return new Identifier("tiefix", "sizemap"); 26 | } 27 | 28 | @Override 29 | public void reload(ResourceManager manager) { 30 | var id = new Identifier("tiefix", "sizemap.bin"); 31 | try (var stream = manager.getResource(id).get().getInputStream()) { 32 | sizemap = new Sizemap(IOUtils.toByteArray(stream)); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | } 38 | ); 39 | } 40 | 41 | public static final int MIXIN_PRIORITY = 500; 42 | 43 | private static Config config = null; 44 | private static Sizemap sizemap = null; 45 | 46 | public static Config getConfig() { 47 | // We can't initialize this in onInitializeClient, because the config is 48 | // needed before the client is initialized. 49 | if (config == null) { 50 | config = ConfigHelper.readConfig(); 51 | } 52 | return config; 53 | } 54 | 55 | public static Sizemap getSizemap() { 56 | return sizemap; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | secrets.properties 2 | 3 | # User-specific stuff 4 | .idea/ 5 | 6 | *.iml 7 | *.ipr 8 | *.iws 9 | 10 | # IntelliJ 11 | out/ 12 | # mpeltonen/sbt-idea plugin 13 | .idea_modules/ 14 | 15 | # JIRA plugin 16 | atlassian-ide-plugin.xml 17 | 18 | # Compiled class file 19 | *.class 20 | 21 | # Log file 22 | *.log 23 | 24 | # BlueJ files 25 | *.ctxt 26 | 27 | # Package Files # 28 | *.jar 29 | *.war 30 | *.nar 31 | *.ear 32 | *.zip 33 | *.tar.gz 34 | *.rar 35 | 36 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 37 | hs_err_pid* 38 | 39 | *~ 40 | 41 | # temporary files which can be created if a process still has a handle open of a deleted file 42 | .fuse_hidden* 43 | 44 | # KDE directory preferences 45 | .directory 46 | 47 | # Linux trash folder which might appear on any partition or disk 48 | .Trash-* 49 | 50 | # .nfs files are created when an open file is removed but is still being accessed 51 | .nfs* 52 | 53 | # General 54 | .DS_Store 55 | .AppleDouble 56 | .LSOverride 57 | 58 | # Icon must end with two \r 59 | Icon 60 | 61 | # Thumbnails 62 | ._* 63 | 64 | # Files that might appear in the root of a volume 65 | .DocumentRevisions-V100 66 | .fseventsd 67 | .Spotlight-V100 68 | .TemporaryItems 69 | .Trashes 70 | .VolumeIcon.icns 71 | .com.apple.timemachine.donotpresent 72 | 73 | # Directories potentially created on remote AFP share 74 | .AppleDB 75 | .AppleDesktop 76 | Network Trash Folder 77 | Temporary Items 78 | .apdisk 79 | 80 | # Windows thumbnail cache files 81 | Thumbs.db 82 | Thumbs.db:encryptable 83 | ehthumbs.db 84 | ehthumbs_vista.db 85 | 86 | # Dump file 87 | *.stackdump 88 | 89 | # Folder config file 90 | [Dd]esktop.ini 91 | 92 | # Recycle Bin used on file shares 93 | $RECYCLE.BIN/ 94 | 95 | # Windows Installer files 96 | *.cab 97 | *.msi 98 | *.msix 99 | *.msm 100 | *.msp 101 | 102 | # Windows shortcuts 103 | *.lnk 104 | 105 | .gradle 106 | build/ 107 | 108 | # Ignore Gradle GUI config 109 | gradle-app.setting 110 | 111 | # Cache of project 112 | .gradletasknamecache 113 | 114 | **/build/ 115 | 116 | # Common working directory 117 | run/ 118 | 119 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 120 | !gradle-wrapper.jar 121 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/config/ConfigHelper.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.config; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import net.fabricmc.loader.api.FabricLoader; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.NoSuchFileException; 12 | import java.nio.file.Path; 13 | 14 | public class ConfigHelper { 15 | private static Path configPath = FabricLoader.getInstance().getConfigDir().resolve("tiefix.json"); 16 | private static Gson gson = new GsonBuilder().setPrettyPrinting().create(); 17 | 18 | /** 19 | * Read the configuration from disk. 20 | */ 21 | public static Config readConfig() { 22 | try { 23 | var contents = Files.readString(configPath); 24 | // Get the version of the config 25 | var version = gson.fromJson(contents, VersionChecker.class); 26 | if (version != null) { 27 | // Figure out which class to deserialize as 28 | if (version.version != 0) { 29 | throw new IllegalArgumentException("Unknown config version " + version.version); 30 | } 31 | // Deserialize using that class 32 | return gson.fromJson(contents, Config.class); 33 | } 34 | } catch (FileNotFoundException | NoSuchFileException ignored) { 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | 39 | // Something didn't go right -- create a new config and save it 40 | var config = new Config(); 41 | writeConfig(config); 42 | return config; 43 | } 44 | 45 | private static class VersionChecker { 46 | public int version = 0; 47 | } 48 | 49 | /** 50 | * Write the configuration to disk. 51 | */ 52 | public static void writeConfig(Config config) { 53 | // Create the config directory if it doesn't exist 54 | try { 55 | Files.createDirectories(configPath.getParent()); 56 | } catch (IOException ignored) { 57 | } 58 | // Save the config 59 | try (var writer = new FileWriter(configPath.toFile())) { 60 | gson.toJson(config, writer); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/fixes/mc89242/Sizemap.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.fixes.mc89242; 2 | 3 | import net.minecraft.text.Style; 4 | import net.minecraft.text.TextVisitFactory; 5 | 6 | /** 7 | * A mapping of characters to their widths when rendered. 8 | *

9 | * A sizemap helps calculate the width of text when rendered. This 10 | * functionality is already provided by Minecraft's {@code TextRenderer}; 11 | * however, that implementation depends on the currently loaded font, which can 12 | * be changed by resource packs. This class is independent from 13 | * {@code TextRenderer}, so it can be used to calculate the width of text 14 | * if it were rendered in the default font. 15 | */ 16 | public class Sizemap { 17 | /** 18 | * The size of each codepoint -- 4 bits each. 19 | *

20 | * Each byte contains the size of two codepoints. The bottom four bits 21 | * contain the size of the first codepoint, and the top four bits contain 22 | * the size of the second codepoint. 23 | */ 24 | private final byte[] sizes; 25 | 26 | public Sizemap() { 27 | // Yeah, this is 500KB of memory... but we all have 500KB to spare, right? 28 | sizes = new byte[ARRAY_SIZE]; 29 | } 30 | 31 | /** 32 | * Construct a new Sizemap from the array returned from {@link #getBytes}. 33 | */ 34 | public Sizemap(byte[] sizes) { 35 | if (sizes.length != ARRAY_SIZE) { 36 | throw new IllegalArgumentException( 37 | "Incorrect size: expected " + ARRAY_SIZE + ", got " + sizes.length 38 | ); 39 | } 40 | this.sizes = sizes; 41 | } 42 | 43 | public int getWidth(int codepoint) { 44 | var shift = (codepoint & 1) * 4; 45 | return (sizes[codepoint >> 1] >> shift) & 0xF; 46 | } 47 | 48 | public int getWidth(String text) { 49 | int[] total = {0}; 50 | TextVisitFactory.visitForwards(text, Style.EMPTY, (index, style, codepoint) -> { 51 | total[0] += getWidth(codepoint); 52 | return true; 53 | }); 54 | return total[0]; 55 | } 56 | 57 | public void set(int codepoint, int size) { 58 | if (size < 0 || size > 0xF) { 59 | throw new IllegalArgumentException("Size out of range: " + size); 60 | } 61 | var shift = (codepoint & 1) * 4; 62 | sizes[codepoint >> 1] &= ~(byte) (0xF << shift); 63 | sizes[codepoint >> 1] |= (byte) (size << shift); 64 | } 65 | 66 | /** 67 | * Get the raw bytes stored by this sizemap. The format of the bytes is 68 | * subject to change. Do not modify this array. 69 | */ 70 | public byte[] getBytes() { 71 | return sizes; 72 | } 73 | 74 | private static final int ARRAY_SIZE = 0x110000 / 2; 75 | } 76 | -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "options.tiefix.title": "TieFix Settings", 3 | "options.tiefix.category.ui": "UI & HUD", 4 | "options.tiefix.category.controls": "Controls", 5 | "options.tiefix.category.audioVisual": "Audio & Visual", 6 | "options.tiefix.category.gameplay": "Gameplay & Movement", 7 | "options.tiefix.category.misc": "Miscellaneous", 8 | "options.tiefix.mc2071": "Allow opening GUIs in a nether portal", 9 | "options.tiefix.mc2071.bug": "MC-2071", 10 | "options.tiefix.mc4490": "Fix fishing line in third person", 11 | "options.tiefix.mc4490.bug": "MC-4490", 12 | "options.tiefix.mc12829": "Fix slow flying in ladders/vines/etc.", 13 | "options.tiefix.mc12829.bug": "MC-12829", 14 | "options.tiefix.mc62997": "Hide scoreboard when F3 is enabled", 15 | "options.tiefix.mc62997.bug": "MC-62997", 16 | "options.tiefix.mc79545": "Fix XP bar with high XP levels", 17 | "options.tiefix.mc79545.bug": "MC-79545", 18 | "options.tiefix.mc80859": "Fix invisible items when dragging", 19 | "options.tiefix.mc80859.bug": "MC-80859", 20 | "options.tiefix.mc89242": "Fix line limit when writing sign", 21 | "options.tiefix.mc89242.bug": "MC-89242", 22 | "options.tiefix.mc122477": "Fix 't' when opening chat (Linux only)", 23 | "options.tiefix.mc122477.bug": "MC-122477", 24 | "options.tiefix.mc122477_keys": "Keys to ignore", 25 | "options.tiefix.mc122477.explanation": "When a key press is received immediately after opening the chat, it will be ignored only if it is found in \"Keys to ignore\". If the box is empty, then all characters will be ignored. If you find that the chat prompt is sometimes ignoring your first key press, then set it to your inventory, chat, and command keybinds (for example, \"et/\"), and any modded keybinds that may immediately focus a text box. If unsure, leave it blank.", 26 | "options.tiefix.mc122645": "Disable narrator hotkey", 27 | "options.tiefix.mc122645.bug": "MC-122645", 28 | "options.tiefix.mc127970": "Fix offhand item while using riptide", 29 | "options.tiefix.mc127970.bug": "MC-127970", 30 | "options.tiefix.mc136249": "Fix riptide speed with depth strider", 31 | "options.tiefix.mc136249.bug": "MC-136249", 32 | "options.tiefix.mc140646": "Scroll text fields while selecting text", 33 | "options.tiefix.mc140646.bug": "MC-140646", 34 | "options.tiefix.mc147766": "Fix stuck Shift key in text boxes", 35 | "options.tiefix.mc147766.bug": "MC-147766", 36 | "options.tiefix.mc203401": "Disable double-tap forward to sprint", 37 | "options.tiefix.mc203401.bug": "MC-203401", 38 | "options.tiefix.mc237493": "Disable telemetry (requires restart)", 39 | "options.tiefix.mc237493.bug": "MC-237493", 40 | "options.tiefix.enableInMultiplayer": "Enable in multiplayer", 41 | "options.tiefix.mayTriggerAnticheat": "Warning: In multiplayer, these fixes could trigger the anticheat. Use with caution.", 42 | "options.tiefix.reloadToApply": "Reload resources (F3+T) to apply changes" 43 | } 44 | -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/lang/tt_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "modmenu.descriptionTranslation.tiefix": "Кайбер теңкә корткыч хаталарны төзәтә", 3 | "options.tiefix.title": "TieFix көйләүләре", 4 | "options.tiefix.category.ui": "UI & HUD", 5 | "options.tiefix.category.controls": "Идарә", 6 | "options.tiefix.category.audioVisual": "Аудио һәм визуаль", 7 | "options.tiefix.category.gameplay": "Уен процессы һәм хәрәкәт", 8 | "options.tiefix.category.misc": "Төрле", 9 | "options.tiefix.mc2071": "Незер порталында һәртөрле интерфейсны ачарга рөхсәт алу", 10 | "options.tiefix.mc2071.bug": "MC-2071", 11 | "options.tiefix.mc4490": "Өченче заттан кармак җебен төзәтү", 12 | "options.tiefix.mc4490.bug": "MC-4490", 13 | "options.tiefix.mc12829": "Баскычлар/лианалар/һ. б. аша күчкәндә, салмак очуны төзәтү", 14 | "options.tiefix.mc12829.bug": "MC-12829", 15 | "options.tiefix.mc62997": "Төзәтү экраны кушылганда, исәпләр тактасын яшерү", 16 | "options.tiefix.mc62997.bug": "MC-62997", 17 | "options.tiefix.mc79545": "Югары тәҗрибә дәрәҗәләре белән тәҗрибә юлын төзәтү", 18 | "options.tiefix.mc79545.bug": "MC-79545", 19 | "options.tiefix.mc80859": "Күчеренгәндә, күренмәс предметларны төзәтү", 20 | "options.tiefix.mc80859.bug": "MC-80859", 21 | "options.tiefix.mc89242": "Билге язылганда, юл чиген төзәтү", 22 | "options.tiefix.mc89242.bug": "MC-89242", 23 | "options.tiefix.mc122477": "Чат ачылганда, «t» төймәсен төзәтү (Linux-та гына)", 24 | "options.tiefix.mc122477.bug": "MC-122477", 25 | "options.tiefix.mc122477_keys": "Әһәмият бирмәү өчен төймәләр", 26 | "options.tiefix.mc122477.explanation": "Әгәр ул «Әһәмият бирмәү өчен төймәләр» исемлегендә табылса гына, чатны ачкач төймәгә басу шундук алганда ул әһәмият бирмәячәк. Әгәр исемлек юк икән, барлык символлар әһәмият бирмәячәк. Әгәр дә Сез чат юлы кайвакыт беренче төймә басуыгызны әһәмият бирмәвен белсәгез, Сезнең инвентарь, чат һәм боерык төймәләренә (мәсәлән, \"et/\"), һәм текст кырын шундук ача ала торган һәртөрле үзгәртелгән төймәләренә үзгәртегез. Әгәр ышанмасагыз, аны буш калдырыгыз.", 27 | "options.tiefix.mc122645": "Сөйләүче төймәсен сүндерү", 28 | "options.tiefix.mc122645.bug": "MC-122645", 29 | "options.tiefix.mc127970": "Эләктерү кулланганда, икенче кулдагы предметны төзәтү", 30 | "options.tiefix.mc127970.bug": "MC-127970", 31 | "options.tiefix.mc136249": "Су асты йөреше кулланганда, эләктерү тизлеген төзәтү", 32 | "options.tiefix.mc136249.bug": "MC-136249", 33 | "options.tiefix.mc140646": "Текст аерып күрсәткәндә, кертү кырын әйләнү", 34 | "options.tiefix.mc140646.bug": "MC-140646", 35 | "options.tiefix.mc147766": "Кертү кырларында Shift төймәсенең уйланма тотып торуны төзәтү", 36 | "options.tiefix.mc147766.bug": "MC-147766", 37 | "options.tiefix.mc203401": "Йөгерү өчен «алга» төймәсен икеләтә тапкыр басуны сүндерү", 38 | "options.tiefix.mc203401.bug": "MC-203401", 39 | "options.tiefix.mc237493": "Телеметрия сүндерү (яңадан кушырга кирәк)", 40 | "options.tiefix.mc237493.bug": "MC-237493", 41 | "options.tiefix.enableInMultiplayer": "Челтәр уенда кушу", 42 | "options.tiefix.mayTriggerAnticheat": "Игътибар: Челтәр уенда шушы төзәтмәләр античит системасын активлаштыра ала. Сак булыгыз!", 43 | "options.tiefix.reloadToApply": "Үзгәрешләр кертү өчен ресурсларны яңадан йөкләгез (F3+T)" 44 | } 45 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/resources/assets/tiefix/lang/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "options.tiefix.title": "Paramètres de TieFix", 3 | "options.tiefix.category.ui": "Interface utilisateur et HUD", 4 | "options.tiefix.category.controls": "Contrôles", 5 | "options.tiefix.category.audioVisual": "Audio et visuel", 6 | "options.tiefix.category.gameplay": "Jouabilité et mouvement", 7 | "options.tiefix.category.misc": "Divers", 8 | "options.tiefix.mc2071": "Autoriser l'ouverture de GUI dans un portail du Nether", 9 | "options.tiefix.mc2071.bug": "MC-2071", 10 | "options.tiefix.mc4490": "Corriger la ligne de pêche en vue à la troisième personne", 11 | "options.tiefix.mc4490.bug": "MC-4490", 12 | "options.tiefix.mc12829": "Corriger le vol lent dans les échelles, les vignes, etc.", 13 | "options.tiefix.mc12829.bug": "MC-12829", 14 | "options.tiefix.mc62997": "Masquer le tableau des scores lorsque F3 est activé", 15 | "options.tiefix.mc62997.bug": "MC-62997", 16 | "options.tiefix.mc79545": "Corriger la barre d'expérience avec des niveaux d'expérience élevés", 17 | "options.tiefix.mc79545.bug": "MC-79545", 18 | "options.tiefix.mc80859": "Corriger les objets invisibles lors du glissement", 19 | "options.tiefix.mc80859.bug": "MC-80859", 20 | "options.tiefix.mc89242": "Corriger la limite de ligne lors de l'écriture sur un panneau", 21 | "options.tiefix.mc89242.bug": "MC-89242", 22 | "options.tiefix.mc122477": "Corriger la touche 't' lors de l'ouverture du chat (Linux uniquement)", 23 | "options.tiefix.mc122477.bug": "MC-122477", 24 | "options.tiefix.mc122477_keys": "Touches à ignorer", 25 | "options.tiefix.mc122477.explanation": "Lorsqu'une pression de touche est détectée immédiatement après l'ouverture du chat, elle sera ignorée uniquement si elle est présente dans \"Touches à ignorer\". Si la case est vide, toutes les caractères seront ignorés. Si vous constatez que le chat ignore parfois votre première pression de touche, définissez - la sur vos raccourcis d 'inventaire, de chat et de commande (par exemple, \"et/\"), ainsi que sur tous les raccourcis modifiés qui peuvent immédiatement se concentrer sur une zone de texte. Si vous n'êtes pas sûr, laissez - la vide.", 26 | "options.tiefix.mc122645": "Désactiver la touche de narration", 27 | "options.tiefix.mc122645.bug": "MC-122645", 28 | "options.tiefix.mc127970": "Corriger l'objet de la main secondaire lors de l'utilisation de Riptide", 29 | "options.tiefix.mc127970.bug": "MC-127970", 30 | "options.tiefix.mc136249": "Corriger la vitesse de Riptide avec Depth Strider", 31 | "options.tiefix.mc136249.bug": "MC-136249", 32 | "options.tiefix.mc140646": "Défiler les champs de texte tout en sélectionnant du texte", 33 | "options.tiefix.mc140646.bug": "MC-140646", 34 | "options.tiefix.mc147766": "Corriger la touche Maj bloquée dans les zones de texte", 35 | "options.tiefix.mc147766.bug": "MC-147766", 36 | "options.tiefix.mc203401": "Désactiver la double pression de la touche avant pour courir", 37 | "options.tiefix.mc203401.bug": "MC-203401", 38 | "options.tiefix.mc237493": "Désactiver la télémétrie (nécessite un redémarrage)", 39 | "options.tiefix.mc237493.bug": "MC-237493", 40 | "options.tiefix.enableInMultiplayer": "Activer en multijoueur", 41 | "options.tiefix.mayTriggerAnticheat": "Avertissement : En multijoueur, ces corrections pourraient déclencher les anticheats. Utilisez-les avec prudence.", 42 | "options.tiefix.reloadToApply": "Recharger les ressources (F3+T) pour appliquer les modifications" 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TieFix 2 | 3 | A Fabric mod that fixes some annoying bugs in the Minecraft client. 4 | 5 | Requires Fabric API. 6 | 7 | **Download on [Modrinth](https://modrinth.com/mod/tiefix), [CurseForge](https://www.curseforge.com/minecraft/mc-mods/tiefix), or [GitHub Releases](https://github.com/j-tai/TieFix/releases)** 8 | 9 | ## Bugs fixed 10 | 11 | ### UI & HUD 12 | * [**MC-2071**](https://bugs.mojang.com/browse/MC-2071) Pausing the Game or opening any GUI in a nether portal does not 13 | work 14 | * Fix: Allow opening GUIs in a nether portal 15 | * [**MC-62997**](https://bugs.mojang.com/browse/MC-62997) Scoreboard overlaps debug screen 16 | * Fix: Hide the scoreboard when the F3 screen is shown 17 | * [**MC-79545**](https://bugs.mojang.com/browse/MC-79545) The experience bar disappears when too many levels are given 18 | to the player 19 | * Fix: Show the experience bar 20 | * [**MC-80859**](https://bugs.mojang.com/browse/MC-80859) Starting to drag item stacks over other compatible stacks 21 | makes the latter invisible until appearance change (stack size increases) 22 | * Fix: Display the item stack properly 23 | * [**MC-89242**](https://bugs.mojang.com/browse/MC-89242) Length of writing text on sign limited by Resource Pack 24 | * Fix: Limit the text based on the default font 25 | * [**MC-122477**](https://bugs.mojang.com/browse/MC-122477) Linux/GNU: Opening chat sometimes writes 't' 26 | * Workaround: Ignore a character entered on the first input poll after opening chat 27 | * [**MC-140646**](https://bugs.mojang.com/browse/MC-140646) Text fields don't scroll while selecting text with Shift 28 | * Fix: Scroll the text properly 29 | * [**MC-147766**](https://bugs.mojang.com/browse/MC-147766) Shift key stays pressed until press any other key 30 | * Fix: Handle mouse clicks properly 31 | 32 | ### Controls 33 | * [**MC-122645**](https://bugs.mojang.com/browse/MC-122645) Narrator hotkey cannot be customized or disabled 34 | * Fix: Disable the narrator hotkey by default (can be re-enabled in the configuration) 35 | * [**MC-203401**](https://bugs.mojang.com/browse/MC-203401) Double-tapping forward button to sprint cannot be disabled/reconfigured 36 | * Fix: Add option to disable double-tap-to-sprint 37 | 38 | ### Audio & Visual 39 | * [**MC-4490**](https://bugs.mojang.com/browse/MC-4490) Fishing line not attached to fishing rod in third person while 40 | crouching 41 | * Fix: Render the fishing line in the correct place 42 | * [**MC-127970**](https://bugs.mojang.com/browse/MC-127970) Using riptide on a trident with an item in your off-hand 43 | causes visual glitch with the item in your offhand 44 | * Fix: Render non-trident items in regular place while using riptide 45 | 46 | ### Gameplay & Movement 47 | * [**MC-12829**](https://bugs.mojang.com/browse/MC-12829) Flying through ladders/vines/scaffolding in creative mode slows you down 48 | * Fix: Ignore climbable blocks when flying 49 | * [**MC-136249**](https://bugs.mojang.com/browse/MC-136249) Depth strider decreases Riptide's launching effect when underwater 50 | * Fix: Ignore depth strider's increased drag while using riptide 51 | 52 | ### Miscellaneous 53 | * [**MC-237493**](https://bugs.mojang.com/browse/MC-237493) Telemetry cannot be disabled 54 | * Fix: Disable telemetry by default (can be re-enabled in the configuration) 55 | 56 | ## Configuration 57 | 58 | All fixes can be toggled on or off in the options menu. 59 | 60 | The options menu can be opened if you have [Mod Menu](https://modrinth.com/mod/modmenu) installed. To access it, go to Mods > TieFix and click the settings button at the top-right. 61 | 62 | ## License 63 | 64 | [LGPLv3.](https://github.com/j-tai/TieFix/blob/master/LICENSE) 65 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.14.0 (2023-06-08) 4 | 5 | * Update to Minecraft 1.20 6 | 7 | ## v1.13.1 (2023-06-08) 8 | 9 | * Add French language support (@Calvineries) 10 | 11 | ## v1.13.0 (2023-03-17) 12 | 13 | * Update to Minecraft 1.19.4 14 | 15 | ## v1.12.1 (2023-03-14) 16 | 17 | * Disable MC-12829 fix in multiplayer by default (@mvilk) 18 | * Add Simplified Chinese language support (@Cccc-owo) 19 | 20 | ## v1.12.0 (2022-12-08) 21 | 22 | * Update to Minecraft 1.19.3 23 | * Remove fix for MC-145929 as it has been fixed in the vanilla game 24 | * Remove fix for MC-151412 as it has been fixed in the vanilla game 25 | * Remove fix for MC-233042 as it has been fixed in the vanilla game 26 | 27 | ## v1.11.0 (2022-06-07) 28 | 29 | * Update to Minecraft 1.19 30 | * Add fix for MC-53312 (Illager/(zombie) villager/witch robes don't render the last two rows of pixels) 31 | * Add fix for MC-4490 (Fishing line not attached to fishing rod in third person while crouching) 32 | * Add fix for MC-80859 (Starting to drag item stacks over other compatible stacks makes the latter invisible until 33 | appearance change (stack size increases)) 34 | * Add fix for MC-79545 (The experience bar disappears when too many levels are given to the player) 35 | 36 | ## v1.10.0 (2022-04-09) 37 | 38 | * Update to Minecraft 1.18.2 39 | * Reorganize options screen 40 | * Add fix for MC-12829 (Flying through ladders/vines/scaffolding in creative mode slows you down) 41 | * Fix crash caused by fix for MC-140646 (Text fields don't scroll while selecting text with Shift) 42 | 43 | ## v1.9.0 (2022-01-26) 44 | 45 | * Add fix for MC-136249 (Depth strider decreases Riptide's launching effect when underwater) 46 | * Add fix for MC-62997 (Scoreboard overlaps debug screen) 47 | * Add fix for MC-122645 (Narrator hotkey cannot be customized or disabled) 48 | * Add fix for MC-203401 (Double-tapping forward button to sprint cannot be disabled/reconfigured) 49 | 50 | ## v1.8.0 (2021-12-21) 51 | 52 | * Add an options screen, accessible via Mod Menu 53 | * Add fix for MC-89242 (Length of writing text on sign limited by Resource Pack) 54 | * Add fix for MC-233042 (Server Address field isn't focused when Direct Connection menu is opened) 55 | * Make MC-127970 still show the animation for the trident (Using riptide on a trident with an item in your off-hand causes visual glitch with the item in your offhand) 56 | 57 | ## v1.7.1 (2021-12-11) 58 | 59 | * Actually fix Bedrockify compatibility 60 | 61 | ## v1.7.0 (2021-12-10) 62 | 63 | * Add fix for MC-2071 64 | * Add mod icon 65 | * Allow mixins to fail without crashing (fixes compatibility with Bedrockify) 66 | 67 | ## v1.6.0 (2021-12-01) 68 | 69 | * Add fix for MC-237493 70 | 71 | ## v1.5.1 (2021-12-01) 72 | 73 | * Update to 1.18 74 | * Remove dependency on Fabric API 75 | * Remove fix for MC-177664 as it has been fixed in the vanilla game 76 | 77 | ## v1.5.0 (2021-07-06) 78 | 79 | * Add fix for MC-140646 80 | * Add fix for MC-147766 81 | 82 | ## v1.4.1 (2021-07-06) 83 | 84 | * Update to 1.17.1 85 | 86 | ## v1.4.0 (2021-07-04) 87 | 88 | * Add fix for MC-151412 89 | 90 | ## v1.3.1 (2021-06-19) 91 | 92 | * Fill in missing fields in fabric.mod.json 93 | 94 | ## v1.3.0 (2021-06-10) 95 | 96 | * Update to Minecraft 1.17 97 | * Remove fix for MC-197616 as it has been fixed in the vanilla game 98 | 99 | ## v1.2.0 (2021-05-22) 100 | 101 | * Add fix for MC-145929 102 | 103 | ## v1.1.1 (2021-05-07) 104 | 105 | * Fix game startup failure 106 | 107 | ## v1.1.0 (2021-05-06) 108 | 109 | * Add fix for MC-177664 110 | 111 | ## v1.0.2 (2021-01-31) 112 | 113 | * Update to 1.16.5 114 | 115 | ## v1.0.1 (2020-12-27) 116 | 117 | * Update to Minecraft 1.16.4 118 | * Fix MC-122477 still occurring at 20 fps or less 119 | * Add JSON configuration 120 | 121 | ## v1.0.0 (2020-10-25) 122 | 123 | * Initial release 124 | -------------------------------------------------------------------------------- /src/main/java/ca/jtai/tiefix/config/ConfigScreenBuilder.java: -------------------------------------------------------------------------------- 1 | package ca.jtai.tiefix.config; 2 | 3 | import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; 4 | import me.shedaniel.clothconfig2.api.ConfigBuilder; 5 | import me.shedaniel.clothconfig2.api.ConfigCategory; 6 | import net.minecraft.client.gui.screen.Screen; 7 | import net.minecraft.text.MutableText; 8 | import net.minecraft.text.Text; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.function.Consumer; 13 | import java.util.function.Function; 14 | 15 | public class ConfigScreenBuilder { 16 | /** 17 | * Builds a new options screen. 18 | * 19 | * @param parent the previous screen that was showing 20 | * @param config the configuration 21 | * @return a new options screen 22 | */ 23 | public static Screen build(Screen parent, Config config) { 24 | return new ConfigScreenBuilder(parent, config).build(); 25 | } 26 | 27 | private final Config config; 28 | private final ConfigBuilder builder; 29 | private final ConfigCategory category; 30 | private ArrayList> entries; 31 | 32 | private ConfigScreenBuilder(Screen parent, Config config) { 33 | this.config = config; 34 | builder = ConfigBuilder.create() 35 | .setParentScreen(parent) 36 | .setTitle(translate("title")) 37 | .setSavingRunnable(() -> ConfigHelper.writeConfig(config)); 38 | category = builder.getOrCreateCategory(translate("main")); 39 | } 40 | 41 | /** 42 | * Build the options screen. Do not call this method more than once -- assume that it consumes {@code this}. 43 | */ 44 | private Screen build() { 45 | beginCategory(); 46 | addFixToggle("mc2071", c -> c.mc2071_fix, b -> config.mc2071_fix = b); 47 | addFixToggle("mc62997", c -> c.mc62997_fix, b -> config.mc62997_fix = b); 48 | addFixToggle("mc79545", c -> c.mc79545_fix, b -> config.mc79545_fix = b); 49 | addFixToggle("mc80859", c -> c.mc80859_fix, b -> config.mc80859_fix = b); 50 | addFixToggle("mc89242", c -> c.mc89242_fix, b -> config.mc89242_fix = b); 51 | addFixToggle("mc122477", c -> c.mc122477_fix, b -> config.mc122477_fix = b); 52 | entries.add( 53 | builder.entryBuilder() 54 | .startStrField( 55 | indented(translate("mc122477_keys")), 56 | config.mc122477_keys 57 | ) 58 | .setDefaultValue("") 59 | .setSaveConsumer(value -> config.mc122477_keys = value) 60 | .build() 61 | ); 62 | addDescription("mc122477.explanation"); 63 | addFixToggle("mc140646", c -> c.mc140646_fix, b -> config.mc140646_fix = b); 64 | addFixToggle("mc147766", c -> c.mc147766_fix, b -> config.mc147766_fix = b); 65 | endCategory("ui"); 66 | 67 | beginCategory(); 68 | addFixToggle("mc122645", c -> c.mc122645_fix, b -> config.mc122645_fix = b); 69 | addFixToggle("mc203401", c -> c.mc203401_fix, b -> config.mc203401_fix = b); 70 | endCategory("controls"); 71 | 72 | beginCategory(); 73 | addFixToggle("mc4490", c -> c.mc4490_fix, b -> config.mc4490_fix = b); 74 | addFixToggle("mc127970", c -> c.mc127970_fix, b -> config.mc127970_fix = b); 75 | endCategory("audioVisual"); 76 | 77 | beginCategory(); 78 | addMultiplayerToggle(c -> c.gameplayAllowMultiplayer, b -> config.gameplayAllowMultiplayer = b); 79 | addFixToggle("mc12829", c -> c.mc12829_fix, b -> config.mc12829_fix = b); 80 | addFixToggle("mc136249", c -> c.mc136249_fix, b -> config.mc136249_fix = b); 81 | endCategory("gameplay"); 82 | 83 | beginCategory(); 84 | addFixToggle("mc237493", c -> c.mc237493_fix, b -> config.mc237493_fix = b); 85 | endCategory("misc"); 86 | 87 | return builder.build(); 88 | } 89 | 90 | private void beginCategory() { 91 | entries = new ArrayList<>(); 92 | } 93 | 94 | private void endCategory(String id) { 95 | category.addEntry( 96 | builder.entryBuilder() 97 | .startSubCategory(translate("category." + id), Collections.unmodifiableList(entries)) 98 | .setExpanded(true) 99 | .build() 100 | ); 101 | } 102 | 103 | /** 104 | * Add a boolean option for a fix toggle. 105 | * 106 | * @param id the ID of the option, used for translation keys 107 | * @param getter a function that takes a {@link Config} object and returns the current value of the option 108 | * @param setter a function that sets the option in {@code this.config} 109 | */ 110 | private void addFixToggle( 111 | String id, 112 | Function getter, 113 | Consumer setter, 114 | String... extraTooltips 115 | ) { 116 | var title = translate(id); 117 | var tooltip = translate(id + ".bug"); 118 | for (var extra : extraTooltips) { 119 | tooltip.append("\n"); 120 | tooltip.append(translate(extra)); 121 | } 122 | 123 | entries.add( 124 | builder.entryBuilder() 125 | .startBooleanToggle(title, getter.apply(config)) 126 | .setTooltip(tooltip) 127 | .setDefaultValue(getter.apply(Config.DEFAULT)) 128 | .setSaveConsumer(setter) 129 | .build() 130 | ); 131 | } 132 | 133 | private void addMultiplayerToggle( 134 | Function getter, 135 | Consumer setter 136 | ) { 137 | addDescription("mayTriggerAnticheat"); 138 | entries.add( 139 | builder.entryBuilder() 140 | .startBooleanToggle(translate("enableInMultiplayer"), getter.apply(config)) 141 | .setDefaultValue(getter.apply(Config.DEFAULT)) 142 | .setSaveConsumer(setter) 143 | .build() 144 | ); 145 | } 146 | 147 | private void addDescription(String id) { 148 | entries.add( 149 | builder.entryBuilder() 150 | .startTextDescription(translate(id)) 151 | .build() 152 | ); 153 | } 154 | 155 | private static MutableText translate(String id) { 156 | return Text.translatable("options.tiefix." + id); 157 | } 158 | 159 | private static MutableText indented(Text text) { 160 | return Text.literal(" ".repeat(8)).append(text); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. --------------------------------------------------------------------------------