From d051a370407c55cf74b8ea2f483c7f71b83ad731 Mon Sep 17 00:00:00 2001 From: KosmX Date: Wed, 24 Jun 2020 12:48:59 +0200 Subject: [PATCH 1/2] Update to 1.16 -fixed fishing rod --- build.gradle | 16 ++- gradle.properties | 14 +- gradle/wrapper/gradle-wrapper.properties | 5 +- .../tr7zw/firstperson/FirstPersonModMenu.java | 14 +- .../firstperson/FirstPersonModelMod.java | 7 + .../mixins/ArmorRendererMixin.java | 13 +- .../mixins/FishingBobberRendererMixin.java | 121 ++++++++++++++++++ .../firstperson/mixins/PlayerRenderMixin.java | 14 +- src/main/resources/firstperson.mixins.json | 3 +- 9 files changed, 173 insertions(+), 34 deletions(-) create mode 100644 src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java diff --git a/build.gradle b/build.gradle index 9cba3c98..6666c793 100644 --- a/build.gradle +++ b/build.gradle @@ -20,15 +20,15 @@ minecraft { dependencies { //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modCompile "net.fabricmc:fabric-loader:${project.loader_version}" modCompile "io.github.prospector:modmenu:${project.modmenu_version}" - modApi "me.sargunvohra.mcmods:autoconfig1u:2.1.0" - include "me.sargunvohra.mcmods:autoconfig1u:2.1.0" - modApi "me.shedaniel.cloth:config-2:2.14.0" - include "me.shedaniel.cloth:config-2:2.14.0" + modApi "me.sargunvohra.mcmods:autoconfig1u:${project.autoconfig_version}" + include "me.sargunvohra.mcmods:autoconfig1u:${project.autoconfig_version}" + modApi "me.shedaniel.cloth:config-2:${project.cloth_version}" + include "me.shedaniel.cloth:config-2:${project.cloth_version}" // Fabric API. This is technically optional, but you probably want it anyway. //modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" @@ -87,4 +87,10 @@ publishing { // uncomment to publish to the local maven // mavenLocal() } + /*dependencies { + //@Nullable essential for mc modding + compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0' + } + + */ } diff --git a/gradle.properties b/gradle.properties index 92678055..a70aba3f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,17 @@ org.gradle.jvmargs = -Xmx1G #Fabric properties -minecraft_version = 1.15.2 -yarn_mappings = 1.15.2+build.15 -loader_version = 0.7.8+build.187 +minecraft_version = 1.16 +yarn_mappings = 1.16+build.1 +loader_version = 0.8.8+build.202 #Mod properties -mod_version = 1.1.0 +mod_version = 1.1.1 maven_group = de.tr7zw archives_base_name = FirstPersonMod #Dependencies -fabric_api_version = 0.5.1+build.294-1.15 -modmenu_version = 1.10.2+build.32 \ No newline at end of file +fabric_api_version = 0.13.1+build.370-1.16 +modmenu_version = 1.12.2+build.16 +autoconfig_version = 3.2.0-unstable +cloth_version = 4.5.6 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 290541c7..df1e7941 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Jun 24 12:32:40 CEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/de/tr7zw/firstperson/FirstPersonModMenu.java b/src/main/java/de/tr7zw/firstperson/FirstPersonModMenu.java index eafad34e..b271f8ba 100644 --- a/src/main/java/de/tr7zw/firstperson/FirstPersonModMenu.java +++ b/src/main/java/de/tr7zw/firstperson/FirstPersonModMenu.java @@ -1,24 +1,28 @@ package de.tr7zw.firstperson; +import java.util.Map; import java.util.Optional; import java.util.function.Supplier; +import io.github.prospector.modmenu.api.ConfigScreenFactory; import io.github.prospector.modmenu.api.ModMenuApi; import me.sargunvohra.mcmods.autoconfig1u.AutoConfig; import net.minecraft.client.gui.screen.Screen; public class FirstPersonModMenu implements ModMenuApi{ - + + /* @Override public String getModId() { return "firstperson"; } - + + */ + @Override - public Optional> getConfigScreen(Screen screen) { - return Optional.of(AutoConfig.getConfigScreen(FirstPersonConfig.class, screen)); + public ConfigScreenFactory getModConfigScreenFactory() { + return screen -> AutoConfig.getConfigScreen(FirstPersonConfig.class, screen).get(); } - } \ No newline at end of file diff --git a/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java b/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java index f1b94749..9389151a 100644 --- a/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java +++ b/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java @@ -24,6 +24,13 @@ public class FirstPersonModelMod implements ModInitializer { public static boolean fixBodyShadow(){ return (!enabled || config.improvedCompatibility && !hideNextHeadItem); } + + + public static final float sneakBodyOffset = 0.27f; + public static final float swimUpBodyOffset = 0.60f; + public static final float swimDownBodyOffset = 0.50f; + public static final float inVehicleBodyOffset = 0.20f; + @Override public void onInitialize() { diff --git a/src/main/java/de/tr7zw/firstperson/mixins/ArmorRendererMixin.java b/src/main/java/de/tr7zw/firstperson/mixins/ArmorRendererMixin.java index 4c7f4a6a..885d80c7 100644 --- a/src/main/java/de/tr7zw/firstperson/mixins/ArmorRendererMixin.java +++ b/src/main/java/de/tr7zw/firstperson/mixins/ArmorRendererMixin.java @@ -1,24 +1,25 @@ package de.tr7zw.firstperson.mixins; +import net.minecraft.client.render.entity.feature.FeatureRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import de.tr7zw.firstperson.FirstPersonModelMod; -import net.minecraft.client.render.entity.feature.ArmorBipedFeatureRenderer; +//import net.minecraft.client.render.entity.feature.ArmorBipedFeatureRenderer; import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; -@Mixin(ArmorBipedFeatureRenderer.class) -public abstract class ArmorRendererMixin , A extends BipedEntityModel> extends ArmorFeatureRenderer { +@Mixin(ArmorFeatureRenderer.class) +public abstract class ArmorRendererMixin , A extends BipedEntityModel> extends FeatureRenderer { - protected ArmorRendererMixin(FeatureRendererContext featureRendererContext_1, A bipedEntityModel_1, - A bipedEntityModel_2) { - super(featureRendererContext_1, bipedEntityModel_1, bipedEntityModel_2); + + public ArmorRendererMixin(FeatureRendererContext context) { + super(context); } @Inject(at = @At("RETURN"), method = "setVisible") diff --git a/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java b/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java new file mode 100644 index 00000000..3ac5ec82 --- /dev/null +++ b/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java @@ -0,0 +1,121 @@ +package de.tr7zw.firstperson.mixins; + + +import de.tr7zw.firstperson.FirstPersonModelMod; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.options.GameOptions; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.FishingBobberEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.FishingBobberEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(FishingBobberEntityRenderer.class) +public class FishingBobberRendererMixin { + + private boolean doCorrect(){ + return FirstPersonModelMod.enabled && MinecraftClient.getInstance().options.perspective <= 0; + } + + private Vec3d offsetvec3d = Vec3d.ZERO; //to not create @Nullable + + private Vec3d getPositionOffset(PlayerEntity var1) { + double x,y,z = x = y = z = 0; + PlayerEntity abstractClientPlayerEntity_1; + Float realYaw = 0f; + if(var1 == (PlayerEntity) MinecraftClient.getInstance().player && doCorrect()) { + abstractClientPlayerEntity_1 = (PlayerEntity) var1; + realYaw = MathHelper.lerpAngleDegrees(MinecraftClient.getInstance().getTickDelta(), abstractClientPlayerEntity_1.prevYaw, abstractClientPlayerEntity_1.yaw); + }else { + abstractClientPlayerEntity_1 = null; + return Vec3d.ZERO; + } + if (abstractClientPlayerEntity_1 != null && (!abstractClientPlayerEntity_1.isMainPlayer() || MinecraftClient.getInstance().getCameraEntity() != null && MinecraftClient.getInstance().getCameraEntity() == abstractClientPlayerEntity_1)) { + float bodyOffset; + if(abstractClientPlayerEntity_1.isSneaking()){ + bodyOffset = FirstPersonModelMod.sneakBodyOffset + (FirstPersonModelMod.config.sneakXOffset / 100f); + }else if(MinecraftClient.getInstance().player.isInSwimmingPose()) { + abstractClientPlayerEntity_1.bodyYaw = abstractClientPlayerEntity_1.headYaw; + if(abstractClientPlayerEntity_1.prevPitch > 0) { + bodyOffset = FirstPersonModelMod.swimUpBodyOffset; + }else { + bodyOffset = FirstPersonModelMod.swimDownBodyOffset; + } + }else if(abstractClientPlayerEntity_1.hasVehicle()) { + bodyOffset = FirstPersonModelMod.inVehicleBodyOffset; + }else{ + bodyOffset = 0.25f + (FirstPersonModelMod.config.xOffset / 100f); + } + x += bodyOffset * Math.sin(Math.toRadians(realYaw)); + z -= bodyOffset * Math.cos(Math.toRadians(realYaw)); + if(MinecraftClient.getInstance().player.isInSwimmingPose()) { + if(abstractClientPlayerEntity_1.prevPitch > 0 && abstractClientPlayerEntity_1.isSubmergedInWater()) { + y += 0.6f * Math.sin(Math.toRadians(abstractClientPlayerEntity_1.prevPitch)); + }else { + y += 0.01f * -Math.sin(Math.toRadians(abstractClientPlayerEntity_1.prevPitch)); + } + } + + } + Vec3d vec = new Vec3d(x, y, z); + abstractClientPlayerEntity_1 = null; + FirstPersonModelMod.isRenderingPlayer = false; + return vec; + } + + @Redirect(method = "render", at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/options/GameOptions;perspective:I" + )) + private int redirect(GameOptions gameOptions){ + return (doCorrect()) ? 1 : gameOptions.perspective; + } + + @Inject(method = "render", at = @At("HEAD")) + private void calcOffset(FishingBobberEntity fishingBobberEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info){ + this.offsetvec3d = getPositionOffset(fishingBobberEntity.getOwner()); + } + + @Redirect(method = "render", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/PlayerEntity;getX()D" + )) + private double offsetX(PlayerEntity playerEntity){ + return playerEntity.getX() + this.offsetvec3d.getX(); + } + + @Redirect(method = "render", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/PlayerEntity;getZ()D" + )) + private double offsetZ(PlayerEntity playerEntity){ + return playerEntity.getZ() + this.offsetvec3d.getZ(); + } + + @Redirect(method = "render", at = @At( + value = "FIELD", + target = "Lnet/minecraft/entity/player/PlayerEntity;prevX:D" + )) + private double prevOffsetX(PlayerEntity playerEntity){ + return playerEntity.prevX + offsetvec3d.getX(); + } + @Redirect(method = "render", at = @At( + value = "FIELD", + target = "Lnet/minecraft/entity/player/PlayerEntity;prevZ:D" + )) + private double prevOffsetZ(PlayerEntity playerEntity){ + return playerEntity.prevZ + offsetvec3d.getZ(); + } + + +} diff --git a/src/main/java/de/tr7zw/firstperson/mixins/PlayerRenderMixin.java b/src/main/java/de/tr7zw/firstperson/mixins/PlayerRenderMixin.java index 158c7e69..148431e5 100644 --- a/src/main/java/de/tr7zw/firstperson/mixins/PlayerRenderMixin.java +++ b/src/main/java/de/tr7zw/firstperson/mixins/PlayerRenderMixin.java @@ -32,10 +32,6 @@ public PlayerRenderMixin(EntityRenderDispatcher entityRenderDispatcher_1, super(entityRenderDispatcher_1, entityModel_1, float_1); } - private final float sneakBodyOffset = 0.27f; - private final float swimUpBodyOffset = 0.60f; - private final float swimDownBodyOffset = 0.50f; - private final float inVehicleBodyOffset = 0.20f; @Inject(at = @At("RETURN"), method = "setModelPose") private void setModelPose(AbstractClientPlayerEntity abstractClientPlayerEntity_1, CallbackInfo info) { @@ -64,19 +60,19 @@ public void getPositionOffset(AbstractClientPlayerEntity var1, float var2, Callb this.abstractClientPlayerEntity_1 = null; return; } - if (abstractClientPlayerEntity_1 != null && (!abstractClientPlayerEntity_1.isMainPlayer() || this.renderManager.camera != null && this.renderManager.camera.getFocusedEntity() == abstractClientPlayerEntity_1)) { + if (abstractClientPlayerEntity_1 != null && (!abstractClientPlayerEntity_1.isMainPlayer() || this.getRenderManager().camera != null && this.getRenderManager().camera.getFocusedEntity() == abstractClientPlayerEntity_1)) { float bodyOffset; if(abstractClientPlayerEntity_1.isSneaking()){ - bodyOffset = sneakBodyOffset + (FirstPersonModelMod.config.sneakXOffset / 100f); + bodyOffset = FirstPersonModelMod.sneakBodyOffset + (FirstPersonModelMod.config.sneakXOffset / 100f); }else if(MinecraftClient.getInstance().player.isInSwimmingPose()) { abstractClientPlayerEntity_1.bodyYaw = abstractClientPlayerEntity_1.headYaw; if(abstractClientPlayerEntity_1.prevPitch > 0) { - bodyOffset = swimUpBodyOffset; + bodyOffset = FirstPersonModelMod.swimUpBodyOffset; }else { - bodyOffset = swimDownBodyOffset; + bodyOffset = FirstPersonModelMod.swimDownBodyOffset; } }else if(abstractClientPlayerEntity_1.hasVehicle()) { - bodyOffset = inVehicleBodyOffset; + bodyOffset = FirstPersonModelMod.inVehicleBodyOffset; }else{ bodyOffset = 0.25f + (FirstPersonModelMod.config.xOffset / 100f); } diff --git a/src/main/resources/firstperson.mixins.json b/src/main/resources/firstperson.mixins.json index 39941a3a..edeb780e 100644 --- a/src/main/resources/firstperson.mixins.json +++ b/src/main/resources/firstperson.mixins.json @@ -11,7 +11,8 @@ "ArmorRendererMixin", "CameraMixin", "GameRendererMixin", - "WorldRendererMixin" + "WorldRendererMixin", + "FishingBobberRendererMixin" ], "injectors": { "defaultRequire": 1 From 6d240f13b014c70f35666c23b38a0853402747eb Mon Sep 17 00:00:00 2001 From: tr7zw Date: Thu, 25 Jun 2020 16:46:38 +0200 Subject: [PATCH 2/2] Update to 1.16.1, fix view bobbing, enabledByDefault setting --- gradle.properties | 6 +++--- .../de/tr7zw/firstperson/FirstPersonConfig.java | 4 ++++ .../de/tr7zw/firstperson/FirstPersonModelMod.java | 1 + .../mixins/FishingBobberRendererMixin.java | 14 ++++++-------- .../firstperson/mixins/GameRendererMixin.java | 14 ++------------ .../resources/assets/firstperson/lang/en_us.json | 4 +++- 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/gradle.properties b/gradle.properties index a70aba3f..a10056a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ org.gradle.jvmargs = -Xmx1G #Fabric properties -minecraft_version = 1.16 -yarn_mappings = 1.16+build.1 +minecraft_version = 1.16.1 +yarn_mappings = 1.16.1+build.1 loader_version = 0.8.8+build.202 #Mod properties -mod_version = 1.1.1 +mod_version = 1.2.0 maven_group = de.tr7zw archives_base_name = FirstPersonMod diff --git a/src/main/java/de/tr7zw/firstperson/FirstPersonConfig.java b/src/main/java/de/tr7zw/firstperson/FirstPersonConfig.java index 1e474725..730decad 100644 --- a/src/main/java/de/tr7zw/firstperson/FirstPersonConfig.java +++ b/src/main/java/de/tr7zw/firstperson/FirstPersonConfig.java @@ -19,4 +19,8 @@ public class FirstPersonConfig implements ConfigData { @ConfigEntry.Gui.Tooltip public boolean improvedCompatibility = true; + + @ConfigEntry.Gui.Tooltip + public boolean enabledByDefault = true; + } \ No newline at end of file diff --git a/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java b/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java index 9389151a..14e0cba6 100644 --- a/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java +++ b/src/main/java/de/tr7zw/firstperson/FirstPersonModelMod.java @@ -37,6 +37,7 @@ public void onInitialize() { System.out.println("Loaded FirstPerson Models"); AutoConfig.register(FirstPersonConfig.class, GsonConfigSerializer::new); config = AutoConfig.getConfigHolder(FirstPersonConfig.class).getConfig(); + enabled = config.enabledByDefault; keyBinding = FabricKeyBinding.Builder.create( new Identifier("firstperson", "toggle"), net.minecraft.client.util.InputUtil.Type.KEYSYM, diff --git a/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java b/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java index 3ac5ec82..13e6bbb0 100644 --- a/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java +++ b/src/main/java/de/tr7zw/firstperson/mixins/FishingBobberRendererMixin.java @@ -1,24 +1,22 @@ package de.tr7zw.firstperson.mixins; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + import de.tr7zw.firstperson.FirstPersonModelMod; import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.GameOptions; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.FishingBobberEntityRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.FishingBobberEntity; -import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(FishingBobberEntityRenderer.class) public class FishingBobberRendererMixin { diff --git a/src/main/java/de/tr7zw/firstperson/mixins/GameRendererMixin.java b/src/main/java/de/tr7zw/firstperson/mixins/GameRendererMixin.java index 412258b1..0ac44efe 100644 --- a/src/main/java/de/tr7zw/firstperson/mixins/GameRendererMixin.java +++ b/src/main/java/de/tr7zw/firstperson/mixins/GameRendererMixin.java @@ -5,27 +5,17 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.render.Camera; +import de.tr7zw.firstperson.FirstPersonModelMod; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; @Mixin(GameRenderer.class) public class GameRendererMixin { - private int allowBob = 0; - @Inject(at = @At("HEAD"), method = "bobView", cancellable = true) private void bobView(MatrixStack matrixStack_1, float float_1, CallbackInfo info) { - if (--allowBob == 0) { - // Allow bob - } else { + if(FirstPersonModelMod.enabled) info.cancel(); - } - } - - @Inject(at = @At("HEAD"), method = "renderHand") - private void renderHand(MatrixStack matrixStack, Camera camera, float f, CallbackInfo info) { - allowBob = 3; } } diff --git a/src/main/resources/assets/firstperson/lang/en_us.json b/src/main/resources/assets/firstperson/lang/en_us.json index 6713c98c..7cf08ce8 100644 --- a/src/main/resources/assets/firstperson/lang/en_us.json +++ b/src/main/resources/assets/firstperson/lang/en_us.json @@ -6,5 +6,7 @@ "text.autoconfig.firstperson.option.sneakXOffset.@Tooltip": "Moves the body relative to the camera back and forth while sneaking", "key.firstperson.toggle": "Toggle Firstperson", "text.autoconfig.firstperson.option.improvedCompatibility": "Improved Mod Compatibility", - "text.autoconfig.firstperson.option.improvedCompatibility.@Tooltip": "Tries to fix offset issues with mods like Immersive Portals Mirrors" + "text.autoconfig.firstperson.option.improvedCompatibility.@Tooltip": "Tries to fix offset issues with mods like Immersive Portals Mirrors", + "text.autoconfig.firstperson.option.enabledByDefault": "Enabled by default", + "text.autoconfig.firstperson.option.enabledByDefault.@Tooltip": "The default state of the FirstPerson mod after starting the game" } \ No newline at end of file