├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── src └── main │ ├── resources │ ├── viewmodel.mixins.json │ └── fabric.mod.json │ └── java │ └── me │ └── ethius │ └── viewmodel │ ├── settings │ ├── BooleanSetting.java │ ├── Setting.java │ └── FloatSetting.java │ ├── util │ └── Stopwatch.java │ ├── mixin │ ├── MixinKeyboard.java │ └── MixinHeldItemRenderer.java │ ├── config │ ├── LoadConfig.java │ └── SaveConfig.java │ ├── Viewmodel.java │ └── gui │ └── ViewmodelScreen.java ├── README.md ├── gradle.properties ├── LICENSE ├── .gitignore ├── gradlew.bat └── gradlew /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu7d7/viewmodel-changer/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-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/resources/viewmodel.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "me.ethius.viewmodel.mixin", 5 | "compatibilityLevel": "JAVA_8", 6 | "mixins": [ 7 | "MixinHeldItemRenderer", 8 | "MixinKeyboard" 9 | ], 10 | "client": [ 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # viewmodel-changer 2 | just a fabric mod that gives you the ability to change your viewmodel. 3 | done for volker1 on discord. 4 | # how-to-use 5 | to open the gui, press the BACKSLASH key. 6 | inside it, you'll see switches and sliders. 7 | for sliders, you can use either your mouse wheel to change the values or click on a specific spot and hope to get it right. 8 | for switches, just click on it to negate the value of that setting. 9 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | # Fabric Properties 4 | # check these on https://modmuss50.me/fabric.html 5 | minecraft_version=1.18.2 6 | yarn_mappings=1.18.2+build.1 7 | loader_version=0.13.3 8 | # Mod Properties 9 | mod_version=1.1-SNAPSHOT 10 | maven_group=me.ethius 11 | archives_base_name=viewmodel 12 | # Dependencies 13 | # check this on https://modmuss50.me/fabric.html 14 | fabric_version=0.47.8+1.18.2 15 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/settings/BooleanSetting.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.settings; 2 | 3 | public class BooleanSetting extends Setting { 4 | 5 | public BooleanSetting(String name, boolean defaultValue) { 6 | super(name, defaultValue); 7 | } 8 | 9 | public String getName() { 10 | return name; 11 | } 12 | 13 | public void setValue(boolean value) { 14 | this.value = value; 15 | } 16 | 17 | public Boolean getValue() { 18 | return value; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/settings/Setting.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.settings; 2 | 3 | public class Setting { 4 | 5 | protected T value; 6 | protected String name; 7 | 8 | public Setting(String name, T defaultValue) { 9 | this.name = name; 10 | this.value = defaultValue; 11 | } 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public T getValue() { 18 | return value; 19 | } 20 | 21 | public void setValue(T value) { 22 | this.value = value; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/settings/FloatSetting.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.settings; 2 | 3 | public class FloatSetting extends Setting { 4 | 5 | public float min, max; 6 | 7 | public FloatSetting(String name, float defaultValue, float min, float max) { 8 | super(name, defaultValue); 9 | this.min = min; 10 | this.max = max; 11 | } 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setValue(float value) { 18 | this.value = value; 19 | } 20 | 21 | public Float getValue() { 22 | return value; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "viewmodel", 4 | "version": "${version}", 5 | "name": "Viewmodel", 6 | "description": "A mod to change the scaling/position of first person items", 7 | "authors": [ 8 | "Ethius" 9 | ], 10 | "contact": { 11 | "website": "none" 12 | }, 13 | "license": "MIT", 14 | "icon": "assets/viewmodel/icon.png", 15 | "environment": "client", 16 | "entrypoints": { 17 | "main": [ 18 | "me.ethius.viewmodel.Viewmodel" 19 | ] 20 | }, 21 | "mixins": [ 22 | "viewmodel.mixins.json" 23 | ], 24 | "depends": { 25 | "fabricloader": ">=0.13.3", 26 | "fabric": "*", 27 | "minecraft": "1.18.x" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/util/Stopwatch.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.util; 2 | 3 | public final class Stopwatch { 4 | 5 | private long time; 6 | 7 | public Stopwatch() 8 | { 9 | time = -1; 10 | } 11 | 12 | public boolean passed(double ms) 13 | { 14 | return System.currentTimeMillis() - this.time >= ms; 15 | } 16 | 17 | public void reset() 18 | { 19 | this.time = System.currentTimeMillis(); 20 | } 21 | 22 | public void resetTimeSkipTo(long p_MS) 23 | { 24 | this.time = System.currentTimeMillis() + p_MS; 25 | } 26 | 27 | @Deprecated 28 | public long getTime() { 29 | return time; 30 | } 31 | 32 | public long getTimeReal() { 33 | return System.currentTimeMillis() - this.time; 34 | } 35 | 36 | public void setTime(long time) 37 | { 38 | this.time = time; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/mixin/MixinKeyboard.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.mixin; 2 | 3 | import me.ethius.viewmodel.gui.ViewmodelScreen; 4 | import net.minecraft.client.Keyboard; 5 | import net.minecraft.client.MinecraftClient; 6 | import org.lwjgl.glfw.GLFW; 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.CallbackInfo; 11 | 12 | @Mixin(Keyboard.class) 13 | public class MixinKeyboard { 14 | 15 | @Inject(at = @At("HEAD"), method = "onKey(JIIII)V", cancellable = true) 16 | private void onOnKey(long windowHandle, int keyCode, int scanCode, int action, int modifiers, CallbackInfo ci) { 17 | if (MinecraftClient.getInstance().world != null && action == GLFW.GLFW_PRESS && keyCode == GLFW.GLFW_KEY_BACKSLASH) { 18 | MinecraftClient.getInstance().setScreen(new ViewmodelScreen()); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Ethius 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/config/LoadConfig.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.config; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonParser; 6 | import me.ethius.viewmodel.Viewmodel; 7 | import me.ethius.viewmodel.settings.BooleanSetting; 8 | import me.ethius.viewmodel.settings.FloatSetting; 9 | import me.ethius.viewmodel.settings.Setting; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.nio.file.Files; 15 | import java.nio.file.Paths; 16 | 17 | /** 18 | * @author ChiquitaV2 19 | */ 20 | @SuppressWarnings("unchecked") 21 | public class LoadConfig { 22 | 23 | public static String folderName = SaveConfig.folderName; 24 | 25 | public LoadConfig() { 26 | loadAllSettings(); 27 | } 28 | 29 | public void loadAllSettings() { 30 | try { 31 | if (!Files.exists(Paths.get(folderName + "Viewmodel.json"))) { 32 | return; 33 | } 34 | 35 | InputStream inputStream = Files.newInputStream(Paths.get(folderName + "Viewmodel.json")); 36 | JsonObject viewmodelObj = new JsonParser().parse(new InputStreamReader(inputStream)).getAsJsonObject(); 37 | 38 | for (Setting value : Viewmodel.SETTINGS) { 39 | JsonElement valueElement = viewmodelObj.get(value.getName()); 40 | if (valueElement == null) continue; 41 | if (value instanceof BooleanSetting) { 42 | value.setValue(valueElement.getAsBoolean()); 43 | } else if (value instanceof FloatSetting) { 44 | value.setValue(valueElement.getAsFloat()); 45 | } 46 | } 47 | inputStream.close(); 48 | } catch (IOException ignored) { 49 | 50 | } 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/Viewmodel.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel; 2 | 3 | import me.ethius.viewmodel.config.LoadConfig; 4 | import me.ethius.viewmodel.config.SaveConfig; 5 | import me.ethius.viewmodel.settings.BooleanSetting; 6 | import me.ethius.viewmodel.settings.FloatSetting; 7 | import me.ethius.viewmodel.settings.Setting; 8 | import net.fabricmc.api.ModInitializer; 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class Viewmodel implements ModInitializer { 16 | 17 | public final Logger LOGGER = LogManager.getLogger(); 18 | public static final BooleanSetting SCALE = new BooleanSetting("Scale", false); 19 | public static final FloatSetting SCALE_X = new FloatSetting("Scale X", 1, 0, 3); 20 | public static final FloatSetting SCALE_Y = new FloatSetting("Scale Y", 1, 0, 3); 21 | public static final FloatSetting SCALE_Z = new FloatSetting("Scale Z", 1, 0, 3); 22 | public static final BooleanSetting POS = new BooleanSetting("Position", false); 23 | public static final FloatSetting POS_X = new FloatSetting("Position X", 0, -2, 2); 24 | public static final FloatSetting POS_Y = new FloatSetting("Position Y", 0, -2, 2); 25 | public static final FloatSetting POS_Z = new FloatSetting("Position Z", 0, -2, 2); 26 | public static final BooleanSetting ROTATION = new BooleanSetting("Rotation", false); 27 | public static final FloatSetting ROTATION_X = new FloatSetting("Rotation X", 0, -180, 180); 28 | public static final FloatSetting ROTATION_Y = new FloatSetting("Rotation Y", 0, -180, 180); 29 | public static final FloatSetting ROTATION_Z = new FloatSetting("Rotation Z", 0, -180, 180); 30 | public static final BooleanSetting CHANGE_SWING = new BooleanSetting("Change Swing", false); 31 | public static final List> SETTINGS = Arrays.asList(SCALE, SCALE_X, SCALE_Y, SCALE_Z, POS, POS_X, POS_Y, POS_Z, ROTATION, ROTATION_X, ROTATION_Y, ROTATION_Z, CHANGE_SWING); 32 | 33 | protected static SaveConfig sconfig; 34 | protected static LoadConfig lconfig; 35 | 36 | @Override 37 | public void onInitialize() { 38 | LOGGER.info("Loading Viewmodel!"); 39 | lconfig = new LoadConfig(); 40 | sconfig = new SaveConfig(); 41 | Runtime.getRuntime().addShutdownHook(new Thread(() -> sconfig.saveAllSettings())); 42 | } 43 | 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/java/me/ethius/viewmodel/config/SaveConfig.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.config; 2 | 3 | import com.google.gson.*; 4 | import me.ethius.viewmodel.Viewmodel; 5 | import me.ethius.viewmodel.settings.BooleanSetting; 6 | import me.ethius.viewmodel.settings.FloatSetting; 7 | import me.ethius.viewmodel.settings.Setting; 8 | import me.ethius.viewmodel.util.Stopwatch; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.OutputStreamWriter; 14 | import java.nio.charset.StandardCharsets; 15 | import java.nio.file.Files; 16 | import java.nio.file.Paths; 17 | 18 | /** 19 | * @author ChiquitaV2 20 | */ 21 | public class SaveConfig { 22 | 23 | private Gson gson; 24 | public static Stopwatch saveTimer; 25 | 26 | public SaveConfig() { 27 | try { 28 | gson = new GsonBuilder().setPrettyPrinting().create(); 29 | saveConfig(); 30 | saveAllSettings(); 31 | saveTimer = new Stopwatch(); 32 | timedSave(); 33 | } 34 | catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | public static String folderName = "Viewmodel/"; 40 | 41 | public void saveConfig() throws IOException { 42 | if (!Files.exists(Paths.get(folderName))) { 43 | Files.createDirectories(Paths.get(folderName)); 44 | } 45 | } 46 | 47 | public void saveAllSettings() { 48 | try { 49 | makeFile(null, "Viewmodel"); 50 | 51 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 52 | OutputStreamWriter fileOutputStreamWriter = new OutputStreamWriter(new FileOutputStream(folderName + "Viewmodel.json"), StandardCharsets.UTF_8); 53 | JsonObject viewmodelObj = new JsonObject(); 54 | 55 | for (Setting value : Viewmodel.SETTINGS) { 56 | if (value instanceof BooleanSetting) { 57 | viewmodelObj.add(value.getName(), new JsonPrimitive((Boolean) value.getValue())); 58 | } else if (value instanceof FloatSetting) { 59 | viewmodelObj.add(value.getName(), new JsonPrimitive((Float) value.getValue())); 60 | } 61 | } 62 | 63 | String jsonString = gson.toJson(new JsonParser().parse(viewmodelObj.toString())); 64 | fileOutputStreamWriter.write(jsonString); 65 | fileOutputStreamWriter.close(); 66 | } 67 | catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public void makeFile(String location, String name) throws IOException { 73 | if (location != null) { 74 | if (!Files.exists(Paths.get(folderName + location + name + ".json"))) { 75 | Files.createFile(Paths.get(folderName + location + name + ".json")); 76 | } 77 | else { 78 | File file = new File(folderName + location + name + ".json"); 79 | 80 | if (file.delete()) { 81 | Files.createFile(Paths.get(folderName + location + name + ".json")); 82 | } 83 | } 84 | } else { 85 | if (Files.exists(Paths.get(folderName + name + ".json"))) { 86 | File file = new File(folderName + name + ".json"); 87 | 88 | file.delete(); 89 | } 90 | Files.createFile(Paths.get(folderName + name + ".json")); 91 | } 92 | 93 | } 94 | 95 | public void timedSave() { 96 | if (saveTimer.passed(5000)) { 97 | saveAllSettings(); 98 | saveTimer.reset(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/gui/ViewmodelScreen.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.gui; 2 | 3 | import me.ethius.viewmodel.Viewmodel; 4 | import me.ethius.viewmodel.gui.ViewmodelScreen.Slider; 5 | import me.ethius.viewmodel.gui.ViewmodelScreen.Switch; 6 | import me.ethius.viewmodel.gui.ViewmodelScreen.ViewmodelGuiObj; 7 | import me.ethius.viewmodel.settings.BooleanSetting; 8 | import me.ethius.viewmodel.settings.FloatSetting; 9 | import me.ethius.viewmodel.settings.Setting; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.client.gui.screen.Screen; 12 | import net.minecraft.client.util.math.MatrixStack; 13 | import net.minecraft.text.Text; 14 | import net.minecraft.util.math.MathHelper; 15 | 16 | import java.math.BigDecimal; 17 | import java.math.RoundingMode; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class ViewmodelScreen extends Screen { 22 | 23 | final MinecraftClient mc = MinecraftClient.getInstance(); 24 | final List objs = new ArrayList<>(); 25 | 26 | public ViewmodelScreen() { 27 | super(Text.of("Viewmodel")); 28 | } 29 | 30 | public void init() { 31 | int settingCount = 0; 32 | for (Setting setting : Viewmodel.SETTINGS) { 33 | settingCount++; 34 | if (setting instanceof BooleanSetting) { 35 | objs.add(new Switch((BooleanSetting) setting, 80, 50 + settingCount * 16, 12)); 36 | } else if (setting instanceof FloatSetting) { 37 | objs.add(new Slider((FloatSetting) setting, 80, 50 + settingCount * 16, 80, 12)); 38 | } 39 | } 40 | } 41 | 42 | class Slider implements ViewmodelGuiObj { 43 | 44 | private final FloatSetting setting; 45 | private final int x, y, width, height; 46 | private final float min, max; 47 | 48 | public Slider(FloatSetting setting, int x, int y, int width, int height) { 49 | this.setting = setting; 50 | this.x = x; 51 | this.y = y; 52 | this.width = width; 53 | this.height = height; 54 | min = setting.min; 55 | max = setting.max; 56 | } 57 | 58 | @Override 59 | public void mouseScrolled(double mx, double my, float inc) { 60 | setting.setValue(MathHelper.clamp(setting.getValue() + inc * 0.1F, min, max)); 61 | } 62 | 63 | @Override 64 | public void mouseClicked(double mx, double my) { 65 | setting.setValue(min + (float) ((max - min) / width * (mx - x))); 66 | } 67 | 68 | @Override 69 | public void render(MatrixStack matrices, int mouseX, int mouseY) { 70 | mc.textRenderer.drawWithShadow(matrices, setting.getName(), x - mc.textRenderer.getWidth(setting.getName()) - 1, y + height/2f - mc.textRenderer.fontHeight/2f, -1); 71 | fill(matrices, x, y, (int) (x + ((setting.getValue() - min) / (max - min)) * width), y + height, -1); 72 | mc.textRenderer.drawWithShadow(matrices, "" + round(setting.getValue(), 1), x + width + 1, y + height/2f - mc.textRenderer.fontHeight/2f, -1); 73 | } 74 | 75 | @Override 76 | public boolean isWithin(double mouseX, double mouseY) { 77 | return mouseX > x && mouseY > y && mouseX < x + width && mouseY < y + height; 78 | } 79 | 80 | } 81 | 82 | class Switch implements ViewmodelGuiObj { 83 | 84 | private final BooleanSetting setting; 85 | private final int x; 86 | private final int y; 87 | private final int height; 88 | 89 | public Switch(BooleanSetting setting, int x, int y, int height) { 90 | this.setting = setting; 91 | this.x = x; 92 | this.y = y; 93 | this.height = height; 94 | } 95 | 96 | @Override 97 | public void mouseScrolled(double mx, double my, float inc) { 98 | 99 | } 100 | 101 | @Override 102 | public void mouseClicked(double mx, double my) { 103 | setting.setValue(!setting.getValue()); 104 | } 105 | 106 | @Override 107 | public void render(MatrixStack matrices, int mouseX, int mouseY) { 108 | mc.textRenderer.drawWithShadow(matrices, setting.getName(), x - mc.textRenderer.getWidth(setting.getName()) - 1, y + height / 2f - mc.textRenderer.fontHeight / 2f, -1); 109 | fill(matrices, x, y, x + height * 2, y + height, -0x78EFEFF0); 110 | if (setting.getValue()) { 111 | fill(matrices, x + 1, y + 1, x + height - 1, y + height - 1, -1); 112 | } else { 113 | fill(matrices, x + height + 1, y + 1, x + height * 2 - 1, y + height - 1, -1); 114 | } 115 | mc.textRenderer.drawWithShadow(matrices, setting.getValue().toString(), x + height * 2 + 1, y + height/2f - mc.textRenderer.fontHeight/2f, -1); 116 | } 117 | 118 | @Override 119 | public boolean isWithin(double mouseX, double mouseY) { 120 | return mouseX > x && mouseY > y && mouseX < x + height * 2 && mouseY < y + height; 121 | } 122 | } 123 | 124 | interface ViewmodelGuiObj { 125 | 126 | void mouseScrolled(double mx, double my, float inc); 127 | 128 | void mouseClicked(double mx, double my); 129 | 130 | void render(MatrixStack matrices, int mouseX, int mouseY); 131 | 132 | boolean isWithin(double mouseX, double mouseY); 133 | 134 | } 135 | 136 | @Override 137 | public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) { 138 | renderBackground(matrices); 139 | for (ViewmodelGuiObj obj : objs) { 140 | obj.render(matrices, mouseX, mouseY); 141 | } 142 | } 143 | 144 | @Override 145 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 146 | for (ViewmodelGuiObj obj : objs) { 147 | if (obj.isWithin(mouseX, mouseY)) { 148 | obj.mouseClicked(mouseX, mouseY); 149 | } 150 | } 151 | return super.mouseClicked(mouseX, mouseY, button); 152 | } 153 | 154 | @Override 155 | public boolean mouseScrolled(double mouseX, double mouseY, double multiplier) { 156 | for (ViewmodelGuiObj obj : objs) { 157 | if (obj.isWithin(mouseX, mouseY)) { 158 | obj.mouseScrolled(mouseX, mouseY, (float) multiplier); 159 | } 160 | } 161 | return super.mouseScrolled(mouseX, mouseY, multiplier); 162 | } 163 | 164 | public float round(float value, int places) { 165 | BigDecimal bd = new BigDecimal(value); 166 | bd = bd.setScale(places, RoundingMode.HALF_UP); 167 | return bd.floatValue(); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/me/ethius/viewmodel/mixin/MixinHeldItemRenderer.java: -------------------------------------------------------------------------------- 1 | package me.ethius.viewmodel.mixin; 2 | 3 | import me.ethius.viewmodel.Viewmodel; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.network.AbstractClientPlayerEntity; 6 | import net.minecraft.client.render.VertexConsumerProvider; 7 | import net.minecraft.client.render.item.HeldItemRenderer; 8 | import net.minecraft.client.render.model.json.ModelTransformation; 9 | import net.minecraft.client.util.math.MatrixStack; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.item.CrossbowItem; 12 | import net.minecraft.item.ItemStack; 13 | import net.minecraft.item.Items; 14 | import net.minecraft.util.Arm; 15 | import net.minecraft.util.Hand; 16 | import net.minecraft.util.math.MathHelper; 17 | import net.minecraft.util.math.Vec3f; 18 | import org.spongepowered.asm.mixin.Final; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.Shadow; 21 | import org.spongepowered.asm.mixin.injection.At; 22 | import org.spongepowered.asm.mixin.injection.Inject; 23 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 24 | 25 | @Mixin(HeldItemRenderer.class) 26 | public abstract class MixinHeldItemRenderer { 27 | 28 | @Shadow protected abstract void renderArmHoldingItem(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, float swingProgress, Arm arm); 29 | 30 | @Shadow private ItemStack offHand; 31 | 32 | @Shadow protected abstract void renderMapInBothHands(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float pitch, float equipProgress, float swingProgress); 33 | 34 | @Shadow protected abstract void renderMapInOneHand(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, Arm arm, float swingProgress, ItemStack stack); 35 | 36 | @Shadow protected abstract void applyEquipOffset(MatrixStack matrices, Arm arm, float equipProgress); 37 | 38 | @Shadow @Final private MinecraftClient client; 39 | 40 | @Shadow protected abstract void applySwingOffset(MatrixStack matrices, Arm arm, float swingProgress); 41 | 42 | @Shadow public abstract void renderItem(LivingEntity entity, ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light); 43 | 44 | @Shadow protected abstract void applyEatOrDrinkTransformation(MatrixStack matrices, float tickDelta, Arm arm, ItemStack stack); 45 | 46 | @Inject(at = @At(value = "HEAD"), method = "renderFirstPersonItem", cancellable = true) 47 | private void renderFirstPersonItem1(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo info) { 48 | if (!player.isUsingSpyglass()) { 49 | boolean bl = hand == Hand.MAIN_HAND; 50 | Arm arm = bl ? player.getMainArm() : player.getMainArm().getOpposite(); 51 | matrices.push(); 52 | if (Viewmodel.POS.getValue()) { 53 | matrices.translate(Viewmodel.POS_X.getValue() * 0.1, Viewmodel.POS_Y.getValue() * 0.1, Viewmodel.POS_Z.getValue() * 0.1); 54 | } 55 | if (Viewmodel.ROTATION.getValue()) { 56 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion(Viewmodel.ROTATION_Y.getValue())); 57 | matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(Viewmodel.ROTATION_X.getValue())); 58 | matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion(Viewmodel.ROTATION_Z.getValue())); 59 | } 60 | if (Viewmodel.SCALE.getValue()) { 61 | matrices.scale(1 - (1 - Viewmodel.SCALE_X.getValue()) * 0.1F, 1 - (1 - Viewmodel.SCALE_Y.getValue()) * 0.1F, 1 - (1 - Viewmodel.SCALE_Z.getValue()) * 0.1F); 62 | } 63 | if (item.isEmpty()) { 64 | if (bl && !player.isInvisible()) { 65 | this.renderArmHoldingItem(matrices, vertexConsumers, light, equipProgress, swingProgress, arm); 66 | } 67 | } else if (item.isOf(Items.FILLED_MAP)) { 68 | if (bl && this.offHand.isEmpty()) { 69 | this.renderMapInBothHands(matrices, vertexConsumers, light, pitch, equipProgress, swingProgress); 70 | } else { 71 | this.renderMapInOneHand(matrices, vertexConsumers, light, equipProgress, arm, swingProgress, item); 72 | } 73 | } else { 74 | boolean bl4; 75 | float v; 76 | float w; 77 | float x; 78 | float y; 79 | if (item.isOf(Items.CROSSBOW)) { 80 | bl4 = CrossbowItem.isCharged(item); 81 | boolean bl3 = arm == Arm.RIGHT; 82 | int i = bl3 ? 1 : -1; 83 | if (player.isUsingItem() && player.getItemUseTimeLeft() > 0 && player.getActiveHand() == hand) { 84 | this.applyEquipOffset(matrices, arm, equipProgress); 85 | matrices.translate((float)i * -0.4785682F, -0.0943870022892952D, 0.05731530860066414D); 86 | matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(-11.935F)); 87 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((float)i * 65.3F)); 88 | matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion((float)i * -9.785F)); 89 | v = (float)item.getMaxUseTime() - ((float)this.client.player.getItemUseTimeLeft() - tickDelta + 1.0F); 90 | w = v / (float)CrossbowItem.getPullTime(item); 91 | if (w > 1.0F) { 92 | w = 1.0F; 93 | } 94 | 95 | if (w > 0.1F) { 96 | x = MathHelper.sin((v - 0.1F) * 1.3F); 97 | y = w - 0.1F; 98 | float k = x * y; 99 | matrices.translate(k * 0.0F, k * 0.004F, k * 0.0F); 100 | } 101 | 102 | matrices.translate(w * 0.0F, w * 0.0F, w * 0.04F); 103 | matrices.scale(1.0F, 1.0F, 1.0F + w * 0.2F); 104 | matrices.multiply(Vec3f.NEGATIVE_Y.getDegreesQuaternion((float)i * 45.0F)); 105 | } else { 106 | v = -0.4F * MathHelper.sin(MathHelper.sqrt(swingProgress) * 3.1415927F); 107 | w = 0.2F * MathHelper.sin(MathHelper.sqrt(swingProgress) * 6.2831855F); 108 | x = -0.2F * MathHelper.sin(swingProgress * 3.1415927F); 109 | matrices.translate((float)i * v, w, x); 110 | this.applyEquipOffset(matrices, arm, equipProgress); 111 | this.applySwingOffset(matrices, arm, swingProgress); 112 | if (bl4 && swingProgress < 0.001F && bl) { 113 | matrices.translate((float)i * -0.641864F, 0.0D, 0.0D); 114 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((float)i * 10.0F)); 115 | } 116 | } 117 | 118 | this.renderItem(player, item, bl3 ? ModelTransformation.Mode.FIRST_PERSON_RIGHT_HAND : ModelTransformation.Mode.FIRST_PERSON_LEFT_HAND, !bl3, matrices, vertexConsumers, light); 119 | } else { 120 | bl4 = arm == Arm.RIGHT; 121 | int o; 122 | float u; 123 | if (player.isUsingItem() && player.getItemUseTimeLeft() > 0 && player.getActiveHand() == hand) { 124 | o = bl4 ? 1 : -1; 125 | switch (item.getUseAction()) { 126 | case NONE, BLOCK -> this.applyEquipOffset(matrices, arm, equipProgress); 127 | case EAT, DRINK -> { 128 | this.applyEatOrDrinkTransformation(matrices, tickDelta, arm, item); 129 | this.applyEquipOffset(matrices, arm, equipProgress); 130 | } 131 | case BOW -> { 132 | this.applyEquipOffset(matrices, arm, equipProgress); 133 | matrices.translate((float) o * -0.2785682F, 0.18344387412071228D, 0.15731531381607056D); 134 | matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(-13.935F)); 135 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((float) o * 35.3F)); 136 | matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion((float) o * -9.785F)); 137 | u = (float) item.getMaxUseTime() - ((float) this.client.player.getItemUseTimeLeft() - tickDelta + 1.0F); 138 | v = u / 20.0F; 139 | v = (v * v + v * 2.0F) / 3.0F; 140 | if (v > 1.0F) { 141 | v = 1.0F; 142 | } 143 | if (v > 0.1F) { 144 | w = MathHelper.sin((u - 0.1F) * 1.3F); 145 | x = v - 0.1F; 146 | y = w * x; 147 | matrices.translate(y * 0.0F, y * 0.004F, y * 0.0F); 148 | } 149 | matrices.translate(v * 0.0F, v * 0.0F, v * 0.04F); 150 | matrices.scale(1.0F, 1.0F, 1.0F + v * 0.2F); 151 | matrices.multiply(Vec3f.NEGATIVE_Y.getDegreesQuaternion((float) o * 45.0F)); 152 | } 153 | case SPEAR -> { 154 | this.applyEquipOffset(matrices, arm, equipProgress); 155 | matrices.translate((float) o * -0.5F, 0.699999988079071D, 0.10000000149011612D); 156 | matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(-55.0F)); 157 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((float) o * 35.3F)); 158 | matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion((float) o * -9.785F)); 159 | u = (float) item.getMaxUseTime() - ((float) this.client.player.getItemUseTimeLeft() - tickDelta + 1.0F); 160 | v = u / 10.0F; 161 | if (v > 1.0F) { 162 | v = 1.0F; 163 | } 164 | if (v > 0.1F) { 165 | w = MathHelper.sin((u - 0.1F) * 1.3F); 166 | x = v - 0.1F; 167 | y = w * x; 168 | matrices.translate(y * 0.0F, y * 0.004F, y * 0.0F); 169 | } 170 | matrices.translate(0.0D, 0.0D, v * 0.2F); 171 | matrices.scale(1.0F, 1.0F, 1.0F + v * 0.2F); 172 | matrices.multiply(Vec3f.NEGATIVE_Y.getDegreesQuaternion((float) o * 45.0F)); 173 | } 174 | } 175 | } else if (player.isUsingRiptide()) { 176 | this.applyEquipOffset(matrices, arm, equipProgress); 177 | o = bl4 ? 1 : -1; 178 | if (!Viewmodel.CHANGE_SWING.getValue()) { 179 | matrices.translate((float) o * -0.4F, 0.800000011920929D, 0.30000001192092896D); 180 | } 181 | matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((float)o * 65.0F)); 182 | matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion((float)o * -85.0F)); 183 | } else { 184 | float aa = -0.4F * MathHelper.sin(MathHelper.sqrt(swingProgress) * 3.1415927F); 185 | u = 0.2F * MathHelper.sin(MathHelper.sqrt(swingProgress) * 6.2831855F); 186 | v = -0.2F * MathHelper.sin(swingProgress * 3.1415927F); 187 | int ad = bl4 ? 1 : -1; 188 | matrices.translate((float)ad * aa, u, v); 189 | this.applyEquipOffset(matrices, arm, equipProgress); 190 | this.applySwingOffset(matrices, arm, swingProgress); 191 | } 192 | 193 | this.renderItem(player, item, bl4 ? ModelTransformation.Mode.FIRST_PERSON_RIGHT_HAND : ModelTransformation.Mode.FIRST_PERSON_LEFT_HAND, !bl4, matrices, vertexConsumers, light); 194 | } 195 | } 196 | 197 | matrices.pop(); 198 | } 199 | info.cancel(); 200 | 201 | } 202 | 203 | } 204 | --------------------------------------------------------------------------------