├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── one │ └── pouekdev │ └── coordinatelist │ ├── CList.java │ ├── CListClient.java │ ├── CListCommand.java │ ├── CListConfig.java │ ├── CListData.java │ ├── CListDelayedEvent.java │ ├── CListRenderLayers.java │ ├── CListVariables.java │ ├── CListWaypoint.java │ ├── CListWaypointColor.java │ ├── CListWaypointConfig.java │ ├── CListWaypointScreen.java │ └── mixin │ └── CListChatGrabber.java └── resources ├── assets └── coordinatelist │ ├── icon.png │ ├── lang │ ├── de_de.json │ ├── en_us.json │ ├── ja_jp.json │ ├── pl_pl.json │ ├── pt_br.json │ ├── ru_ru.json │ └── zh_cn.json │ ├── skull.png │ ├── textures │ └── gui │ │ └── sprites │ │ └── icon │ │ ├── change.png │ │ ├── not_visible.png │ │ └── visible.png │ └── waypoint_icon.png ├── coordinatelist.mixins.json └── fabric.mod.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Automatically build the project and run any configured tests for every push 2 | # and submitted pull request. This can help catch issues that only occur on 3 | # certain platforms or Java versions, and provides a first line of defence 4 | # against bad commits. 5 | 6 | name: build 7 | on: [pull_request, push, workflow_dispatch] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - name: checkout repository 14 | uses: actions/checkout@v4 15 | - name: validate gradle wrapper 16 | uses: gradle/actions/wrapper-validation@v4 17 | - name: setup jdk 18 | uses: actions/setup-java@v4 19 | with: 20 | java-version: '21' 21 | distribution: 'microsoft' 22 | - name: make gradle wrapper executable 23 | run: chmod +x ./gradlew 24 | - name: build 25 | run: ./gradlew build 26 | - name: capture build artifacts 27 | uses: actions/upload-artifact@v4 28 | with: 29 | name: Artifacts 30 | path: build/libs/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | 35 | # java 36 | 37 | hs_err_*.log 38 | replay_*.log 39 | *.hprof 40 | *.jfr 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Jakub Starostecki 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CList icon 2 | 3 | # CList 4 | Coordinate List (CList for short) is a simple minimalistic fabric mod for saving your coordinates. No minimaps. Just a list with in-game waypoints. 5 | 6 | fabric modrinth curseforge 7 | 8 | --- 9 | 10 | (If you want to help and know any other language than English you can help by translating the mod [here](https://github.com/PouekDEV/CList) by making a pull request) 11 | 12 | ## Features 13 | - Hotkey for placing a waypoint in the current position 14 | - Automatic waypoints in the place where you died 15 | - Copying the waypoint coordinates to the clipboard 16 | - Toggling waypoint visibility 17 | - Changing the size of the waypoint to your liking 18 | - Changing the color of the waypoint to your liking 19 | - Setting the maximum rendering distance for waypoints 20 | - Detecting coordinates from chat 21 | - Available in multiple languages 22 | - **No minimap** 23 | 24 | ### The idea behind it 25 | I initially created this mod just for me and my friends. I'm not too fond of these waypoint mods which always have built-in minimap which lagged my game even when it was off. So I made my own mod to fulfill the need for a lightweight, minimalistic waypoint mod. 26 | 27 | ### Support 28 | CList will always receive latest features for the latest version of the game. Porting the newest features to older Minecraft versions is not planned so before creating an issue check if the feature you want isn't already implemented in the latest version of the mod. 29 | 30 | Forge/NeoForge is not planned, but it seems that [Sinytra Connector](https://modrinth.com/mod/connector) does a pretty good job if you want to use CList on Forge/NeoForge. 31 | 32 | You can freely include CList in any mod packs. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '1.10-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | version = project.mod_version 7 | group = project.maven_group 8 | 9 | base { 10 | archivesName = project.archives_base_name 11 | } 12 | 13 | repositories { 14 | maven { url = "https://api.modrinth.com/maven" } 15 | // Add repositories to retrieve artifacts from in here. 16 | // You should only use this when depending on other mods because 17 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 18 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 19 | // for more information about repositories. 20 | } 21 | 22 | dependencies { 23 | // To change the versions see the gradle.properties file 24 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 25 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 26 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 27 | 28 | // Fabric API. This is technically optional, but you probably want it anyway. 29 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 30 | modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}" 31 | include "maven.modrinth:midnightlib:${project.midnightlib_version}" 32 | } 33 | 34 | processResources { 35 | inputs.property "version", project.version 36 | 37 | filesMatching("fabric.mod.json") { 38 | expand "version": inputs.properties.version 39 | } 40 | } 41 | 42 | tasks.withType(JavaCompile).configureEach { 43 | // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. 44 | // The new Minecraft 1.20.5 upwards uses Java 21 45 | it.options.release = 21 46 | } 47 | 48 | java { 49 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 50 | // if it is present. 51 | // If you remove this line, sources will not be generated. 52 | withSourcesJar() 53 | 54 | sourceCompatibility = JavaVersion.VERSION_21 55 | targetCompatibility = JavaVersion.VERSION_21 56 | } 57 | 58 | jar { 59 | inputs.property "archivesName", project.base.archivesName 60 | 61 | from("LICENSE") { 62 | rename { "${it}_${inputs.properties.archivesName}"} 63 | } 64 | } 65 | 66 | // configure the maven publication 67 | publishing { 68 | publications { 69 | create("mavenJava", MavenPublication) { 70 | artifactId = project.archives_base_name 71 | from components.java 72 | } 73 | } 74 | 75 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 76 | repositories { 77 | // Add repositories to publish to here. 78 | // Notice: This block does NOT have the same function as the block in the top level. 79 | // The repositories here will be used for publishing your artifact, not for 80 | // retrieving dependencies. 81 | } 82 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | minecraft_version=1.21.5 8 | yarn_mappings=1.21.5+build.1 9 | loader_version=0.16.10 10 | 11 | # Mod Properties 12 | mod_version = 1.7.2-1.21.5 13 | maven_group = one.pouekdev 14 | archives_base_name = coordinatelist 15 | 16 | # Dependencies 17 | fabric_version=0.119.5+1.21.5 18 | midnightlib_version=1.7.1+1.21.4-fabric 19 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/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-8.12.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original 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 POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 134 | 135 | Please set the JAVA_HOME variable in your environment to match the 136 | location of your Java installation." 137 | fi 138 | 139 | # Increase the maximum file descriptors if we can. 140 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 141 | case $MAX_FD in #( 142 | max*) 143 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 144 | # shellcheck disable=SC3045 145 | MAX_FD=$( ulimit -H -n ) || 146 | warn "Could not query maximum file descriptor limit" 147 | esac 148 | case $MAX_FD in #( 149 | '' | soft) :;; #( 150 | *) 151 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 152 | # shellcheck disable=SC3045 153 | ulimit -n "$MAX_FD" || 154 | warn "Could not set maximum file descriptor limit to $MAX_FD" 155 | esac 156 | fi 157 | 158 | # Collect all arguments for the java command, stacking in reverse order: 159 | # * args from the command line 160 | # * the main class name 161 | # * -classpath 162 | # * -D...appname settings 163 | # * --module-path (only if needed) 164 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 165 | 166 | # For Cygwin or MSYS, switch paths to Windows format before running java 167 | if "$cygwin" || "$msys" ; then 168 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 169 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 170 | 171 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 172 | 173 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 174 | for arg do 175 | if 176 | case $arg in #( 177 | -*) false ;; # don't mess with options #( 178 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 179 | [ -e "$t" ] ;; #( 180 | *) false ;; 181 | esac 182 | then 183 | arg=$( cygpath --path --ignore --mixed "$arg" ) 184 | fi 185 | # Roll the args list around exactly as many times as the number of 186 | # args, so each arg winds up back in the position where it started, but 187 | # possibly modified. 188 | # 189 | # NB: a `for` loop captures its iteration list before it begins, so 190 | # changing the positional parameters here affects neither the number of 191 | # iterations, nor the values presented in `arg`. 192 | shift # remove old arg 193 | set -- "$@" "$arg" # push replacement arg 194 | done 195 | fi 196 | 197 | 198 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 199 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 200 | 201 | # Collect all arguments for the java command; 202 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 203 | # shell script including quotes and variable substitutions, so put them in 204 | # double quotes to make sure that they get re-expanded; and 205 | # * put everything else in single quotes, so that it's not re-expanded. 206 | 207 | set -- \ 208 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 209 | -classpath "$CLASSPATH" \ 210 | org.gradle.wrapper.GradleWrapperMain \ 211 | "$@" 212 | 213 | # Stop when "xargs" is not available. 214 | if ! command -v xargs >/dev/null 2>&1 215 | then 216 | die "xargs is not available" 217 | fi 218 | 219 | # Use "xargs" to parse quoted args. 220 | # 221 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 222 | # 223 | # In Bash we could simply go: 224 | # 225 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 226 | # set -- "${ARGS[@]}" "$@" 227 | # 228 | # but POSIX shell has neither arrays nor command substitution, so instead we 229 | # post-process each arg (as a line of input to sed) to backslash-escape any 230 | # character that might be a shell metacharacter, then use eval to reverse 231 | # that process (while maintaining the separation between arguments), and wrap 232 | # the whole thing up as a single "set" statement. 233 | # 234 | # This will of course break if any of these variables contains a newline or 235 | # an unmatched quote. 236 | # 237 | 238 | eval "set -- $( 239 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 240 | xargs -n1 | 241 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 242 | tr '\n' ' ' 243 | )" '"$@"' 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /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 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CList.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import eu.midnightdust.lib.config.MidnightConfig; 4 | import net.fabricmc.api.ModInitializer; 5 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class CList implements ModInitializer { 10 | public static final String MOD_ID = "coordinatelist"; 11 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 12 | @Override 13 | public void onInitialize() { 14 | MidnightConfig.init(MOD_ID, CListConfig.class); 15 | ClientCommandRegistrationCallback.EVENT.register(new CListCommand()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListClient.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.mojang.blaze3d.vertex.VertexFormat; 4 | import net.fabricmc.api.ClientModInitializer; 5 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 6 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 7 | import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; 8 | import net.minecraft.client.font.TextRenderer; 9 | import net.minecraft.client.option.KeyBinding; 10 | import net.minecraft.client.render.*; 11 | import net.minecraft.client.util.InputUtil; 12 | import net.minecraft.client.util.math.MatrixStack; 13 | import net.minecraft.client.world.ClientWorld; 14 | import net.minecraft.entity.player.PlayerEntity; 15 | import net.minecraft.text.Text; 16 | import net.minecraft.util.Identifier; 17 | import net.minecraft.util.math.MathHelper; 18 | import net.minecraft.util.math.RotationAxis; 19 | import net.minecraft.util.math.Vec3d; 20 | import org.apache.commons.lang3.StringUtils; 21 | import org.joml.Matrix4f; 22 | import org.lwjgl.glfw.GLFW; 23 | import eu.midnightdust.lib.config.MidnightConfig; 24 | 25 | import java.util.List; 26 | import java.util.Objects; 27 | import java.util.Random; 28 | 29 | public class CListClient implements ClientModInitializer { 30 | public static CListVariables variables = new CListVariables(); 31 | static Random rand = new Random(); 32 | KeyBinding open_waypoints_keybind; 33 | KeyBinding add_a_waypoint; 34 | KeyBinding toggle_visibility; 35 | public float calculateWaypointSize(){ 36 | return 0.5f * (CListConfig.multiplier/10.0f); 37 | } 38 | public float calculateTextSize(){ 39 | return 15f * (CListConfig.multiplier/10.0f); 40 | } 41 | public float distanceTo(CListWaypoint waypoint) { 42 | float f = (float)(CListVariables.minecraft_client.player.getX() - waypoint.x); 43 | float g = (float)(CListVariables.minecraft_client.player.getY() - waypoint.y); 44 | float h = (float)(CListVariables.minecraft_client.player.getZ() - waypoint.z); 45 | return Math.round(MathHelper.sqrt(f * f + g * g + h * h)); 46 | } 47 | public Vec3d calculateRenderCoords(CListWaypoint waypoint, Camera camera, float distance) { 48 | float px = (float)camera.getPos().x; 49 | float py = (float)camera.getPos().y; 50 | float pz = (float)camera.getPos().z; 51 | float wx = waypoint.x; 52 | float wy = waypoint.y; 53 | float wz = waypoint.z; 54 | float vx = wx - px; 55 | float vy = wy - py; 56 | float vz = wz - pz; 57 | float vector_len = (float)Math.sqrt((vx*vx) + (vy*vy) + (vz*vz)); 58 | float radius = 32; 59 | float scx = radius / vector_len * vx; 60 | float scy = radius / vector_len * vy; 61 | float scz = radius / vector_len * vz; 62 | float prx, pry, prz; 63 | if (distance > 32) { 64 | prx = scx + px; 65 | pry = scy + py; 66 | prz = scz + pz; 67 | } 68 | else { 69 | prx = wx; 70 | pry = wy; 71 | prz = wz; 72 | } 73 | return new Vec3d(prx,pry,prz); 74 | } 75 | @Override 76 | public void onInitializeClient() { 77 | open_waypoints_keybind = KeyBindingHelper.registerKeyBinding(new KeyBinding( 78 | "keybinds.waypoints.menu", 79 | InputUtil.Type.KEYSYM, 80 | GLFW.GLFW_KEY_M, 81 | "keybinds.category.name" 82 | )); 83 | add_a_waypoint = KeyBindingHelper.registerKeyBinding(new KeyBinding( 84 | "keybinds.waypoint.add", 85 | InputUtil.Type.KEYSYM, 86 | GLFW.GLFW_KEY_B, 87 | "keybinds.category.name" 88 | )); 89 | toggle_visibility = KeyBindingHelper.registerKeyBinding(new KeyBinding( 90 | "keybinds.waypoints.toggle", 91 | InputUtil.Type.KEYSYM, 92 | GLFW.GLFW_KEY_J, 93 | "keybinds.category.name" 94 | )); 95 | WorldRenderEvents.END.register(context ->{ 96 | if (!variables.waypoints.isEmpty() && CListConfig.waypoints_toggled && !CListVariables.minecraft_client.options.hudHidden) { 97 | for(int i = 0; i < variables.waypoints.size(); i++){ 98 | CListWaypoint waypoint = variables.waypoints.get(i); 99 | int distance_without_decimal_places = (int) distanceTo(waypoint); 100 | if(Objects.equals(waypoint.getDimensionString(), getDimension(String.valueOf(variables.last_world.getDimension().effects()))) && waypoint.render && (CListConfig.render_distance == 0 || CListConfig.render_distance >= distance_without_decimal_places)) { 101 | Camera camera = context.camera(); 102 | float size = calculateWaypointSize(); 103 | Vec3d renderCoords = calculateRenderCoords(waypoint, camera, distance_without_decimal_places); 104 | Vec3d targetPosition = new Vec3d(renderCoords.x, renderCoords.y+1, renderCoords.z); 105 | Vec3d transformedPosition = targetPosition.subtract(camera.getPos()); 106 | MatrixStack matrixStack = new MatrixStack(); 107 | matrixStack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); 108 | matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); 109 | matrixStack.translate(transformedPosition.x, transformedPosition.y, transformedPosition.z); 110 | matrixStack.multiply(camera.getRotation()); 111 | matrixStack.scale(-size, size, size); 112 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 113 | Tessellator tessellator = Tessellator.getInstance(); 114 | BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); 115 | buffer.vertex(positionMatrix, 0, 1, 0).color(variables.colors.get(i).r, variables.colors.get(i).g, variables.colors.get(i).b, 1f).texture(0f, 0f); 116 | buffer.vertex(positionMatrix, 0, 0, 0).color(variables.colors.get(i).r, variables.colors.get(i).g, variables.colors.get(i).b, 1f).texture(0f, 1f); 117 | buffer.vertex(positionMatrix, 1, 0, 0).color(variables.colors.get(i).r, variables.colors.get(i).g, variables.colors.get(i).b, 1f).texture(1f, 1f); 118 | buffer.vertex(positionMatrix, 1, 1, 0).color(variables.colors.get(i).r, variables.colors.get(i).g, variables.colors.get(i).b, 1f).texture(1f, 0f); 119 | Identifier icon; 120 | if(waypoint.deathpoint){ 121 | icon = Identifier.of("coordinatelist", "skull.png"); 122 | } 123 | else { 124 | icon = Identifier.of("coordinatelist", "waypoint_icon.png"); 125 | } 126 | CListRenderLayers.POSITION_TEX_COLOR.apply(icon).draw(buffer.end()); 127 | TextRenderer textRenderer = CListVariables.minecraft_client.textRenderer; 128 | String labelText = waypoint.name + " (" + distance_without_decimal_places + " m)"; 129 | int textWidth = textRenderer.getWidth(labelText); 130 | matrixStack.scale(-0.025f, -0.025f, 0.025f); 131 | size = calculateTextSize(); 132 | matrixStack.scale((float) Math.log(size * 4), (float) Math.log(size * 4), (float) Math.log(size * 4)); 133 | matrixStack.translate(0,-20,0); 134 | positionMatrix = matrixStack.peek().getPositionMatrix(); 135 | float h = (float) (-textWidth/2); 136 | VertexConsumerProvider.Immediate v = CListVariables.minecraft_client.getBufferBuilders().getEntityVertexConsumers(); 137 | if(CListConfig.waypoint_text_background) { 138 | textRenderer.draw(labelText, h, 0, 0xFFFFFF, false, positionMatrix, v, TextRenderer.TextLayerType.SEE_THROUGH, 0x90000000, LightmapTextureManager.MAX_LIGHT_COORDINATE); 139 | } 140 | else{ 141 | textRenderer.draw(labelText, h, 0, 0xFFFFFF, false, positionMatrix, v, TextRenderer.TextLayerType.SEE_THROUGH, 0x00000000, LightmapTextureManager.MAX_LIGHT_COORDINATE); 142 | } 143 | v.draw(); 144 | } 145 | } 146 | } 147 | }); 148 | ClientTickEvents.END_CLIENT_TICK.register(client -> { 149 | if(!CListVariables.delayed_events.isEmpty()){ 150 | for(CListDelayedEvent event: CListVariables.delayed_events){ 151 | boolean destroy = event.update(); 152 | if(destroy){ 153 | CListVariables.delayed_events.remove(event); 154 | break; 155 | } 156 | } 157 | } 158 | while (open_waypoints_keybind.wasPressed()) { 159 | client.setScreen(new CListWaypointScreen(Text.literal("Waypoints"))); 160 | } 161 | while(add_a_waypoint.wasPressed()){ 162 | if(!Objects.equals(client.currentScreen, new CListWaypointScreen(Text.literal("Waypoints")))){ 163 | PlayerEntity player = CListVariables.minecraft_client.player; 164 | addNewWaypoint((int) Math.round(player.getX()), (int) Math.round(player.getY()), (int) Math.round(player.getZ()),false); 165 | } 166 | } 167 | while(toggle_visibility.wasPressed()){ 168 | CListConfig.waypoints_toggled = !CListConfig.waypoints_toggled; 169 | MidnightConfig.write(CList.MOD_ID); 170 | } 171 | if (client.world == null) { 172 | variables.loaded_last_world = false; 173 | variables.waypoints.clear(); 174 | variables.colors.clear(); 175 | variables.worldName = null; 176 | variables.last_world = null; 177 | variables.is_world_error = false; 178 | } 179 | else{ 180 | if(!variables.is_world_error){ 181 | try{ 182 | variables.last_world = client.world; 183 | checkForWorldChanges(variables.last_world); 184 | checkIfSaveIsNeeded(false); 185 | if (client.isInSingleplayer()) { 186 | variables.worldName = client.getServer().getSaveProperties().getLevelName(); 187 | } else { 188 | if(client.getCurrentServerEntry().isRealm()) { 189 | variables.worldName = client.getCurrentServerEntry().name; 190 | } 191 | else { 192 | variables.worldName = client.getCurrentServerEntry().address; 193 | variables.worldName = variables.worldName.replace(":","P"); 194 | } 195 | } 196 | if(!client.player.isAlive() && !variables.had_death_waypoint_placed && CListConfig.can_place_deathpoints){ 197 | PlayerEntity player = client.player; 198 | addNewWaypoint((int) Math.round(player.getX()), (int) Math.round(player.getY()), (int) Math.round(player.getZ()),true); 199 | variables.had_death_waypoint_placed = true; 200 | } else if (client.player.isAlive() && variables.had_death_waypoint_placed) { 201 | variables.had_death_waypoint_placed = false; 202 | } 203 | } 204 | catch(NullPointerException e){ 205 | CList.LOGGER.info("Can't get the current world. Player probably uses ReplayMod and is now watching the replay"); 206 | variables.is_world_error = true; 207 | } 208 | } 209 | } 210 | }); 211 | variables.saved_since_last_update = true; 212 | variables.loaded_last_world = false; 213 | } 214 | public static void addNewWaypoint(int x, int y, int z, boolean death){ 215 | CList.LOGGER.info("New waypoint for dimension " + variables.last_world.getDimension().effects()); 216 | String waypoint_name; 217 | if(death){ 218 | waypoint_name = (Text.translatable("waypoint.last.death")).getString(); 219 | } 220 | else{ 221 | waypoint_name = (Text.translatable("waypoint.new.waypoint")).getString(); 222 | } 223 | variables.waypoints.add(new CListWaypoint(x,y,z,waypoint_name,String.valueOf(variables.last_world.getDimension().effects()),true,death)); 224 | variables.colors.add(new CListWaypointColor(rand.nextFloat(),rand.nextFloat(),rand.nextFloat())); 225 | variables.saved_since_last_update = false; 226 | if(!death){ 227 | CListVariables.minecraft_client.setScreen(new CListWaypointConfig(Text.literal("Config"),variables.waypoints.size()-1)); 228 | } 229 | } 230 | public static void deleteWaypoint(int position){ 231 | try { 232 | variables.waypoints.remove(position); 233 | variables.colors.remove(position); 234 | variables.saved_since_last_update = false; 235 | } 236 | catch (IndexOutOfBoundsException ignored){} 237 | } 238 | public static String getDimension(String text){ 239 | String s = text; 240 | s = s.replace("minecraft:",""); 241 | s = s.replace("_"," "); 242 | s = StringUtils.capitalize(s); 243 | return s; 244 | } 245 | public static void checkForWorldChanges(ClientWorld current_world){ 246 | if(!variables.loaded_last_world && variables.worldName != null){ 247 | CList.LOGGER.info("New world " + variables.worldName); 248 | variables.last_world = current_world; 249 | // Check for old 1.0 saves and convert them 250 | List names = CListData.loadListFromFileLegacy("clist_names_"+variables.worldName); 251 | List dimensions = CListData.loadListFromFileLegacy("clist_dimensions_"+variables.worldName); 252 | if(names != null && !names.isEmpty()){ 253 | List temp = CListData.loadListFromFileLegacy("clist_"+variables.worldName); 254 | for(int i = 0; i < names.size(); i++){ 255 | variables.waypoints.add(new CListWaypoint(temp.get(i),names.get(i),dimensions.get(i),true,false)); 256 | } 257 | for(int i = 0; i < variables.waypoints.size(); i++){ 258 | variables.colors.add(new CListWaypointColor(rand.nextFloat(),rand.nextFloat(),rand.nextFloat())); 259 | } 260 | CListData.deleteLegacyFile("clist_names_"+variables.worldName); 261 | CListData.deleteLegacyFile("clist_dimensions_"+variables.worldName); 262 | CList.LOGGER.info("Loaded old 1.0 data for world " + variables.worldName); 263 | // Force save converting it to a new format 264 | checkIfSaveIsNeeded(true); 265 | } 266 | else{ 267 | // Check for post 1.0 saves 268 | if(!CListVariables.minecraft_client.isInSingleplayer()){ 269 | List ways = CListData.loadListFromFile("clist_"+CListVariables.minecraft_client.getCurrentServerEntry().name); 270 | if(ways != null && !ways.isEmpty()){ 271 | variables.waypoints = ways; 272 | CListData.deleteLegacyFile("clist_"+CListVariables.minecraft_client.getCurrentServerEntry().name); 273 | CList.LOGGER.info("Loaded old multiplier server data"); 274 | checkIfSaveIsNeeded(true); 275 | } 276 | else{ 277 | ways = CListData.loadListFromFile("clist_"+variables.worldName); 278 | if(ways != null && !ways.isEmpty()){ 279 | variables.waypoints = ways; 280 | CList.LOGGER.info("Loaded data for server " + variables.worldName); 281 | } 282 | else { 283 | CList.LOGGER.info("The file for " + variables.worldName + " doesn't exist"); 284 | } 285 | } 286 | } 287 | else{ 288 | List ways = CListData.loadListFromFile("clist_"+variables.worldName); 289 | if(ways != null && !ways.isEmpty()){ 290 | variables.waypoints = ways; 291 | CList.LOGGER.info("Loaded data for world " + variables.worldName); 292 | } 293 | else { 294 | CList.LOGGER.info("The file for " + variables.worldName + " doesn't exist"); 295 | } 296 | } 297 | } 298 | variables.loaded_last_world = true; 299 | } 300 | } 301 | public static void addRandomWaypointColor(){ 302 | variables.colors.add(new CListWaypointColor(rand.nextFloat(),rand.nextFloat(),rand.nextFloat())); 303 | } 304 | public static void checkIfSaveIsNeeded(boolean force){ 305 | if(!variables.saved_since_last_update || force){ 306 | CList.LOGGER.info("Saving data for world " + variables.worldName); 307 | CListData.saveListToFile("clist_"+variables.worldName, variables.waypoints); 308 | variables.saved_since_last_update = true; 309 | } 310 | } 311 | } -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListCommand.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.arguments.IntegerArgumentType; 5 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; 6 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; 7 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; 8 | import net.minecraft.command.CommandRegistryAccess; 9 | 10 | public class CListCommand implements ClientCommandRegistrationCallback { 11 | @Override 12 | public void register(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { 13 | dispatcher.register(ClientCommandManager.literal("clist") 14 | .then(ClientCommandManager.argument("x", IntegerArgumentType.integer(Integer.MIN_VALUE,Integer.MAX_VALUE)) 15 | .then(ClientCommandManager.argument("y", IntegerArgumentType.integer(Integer.MIN_VALUE,Integer.MAX_VALUE)) 16 | .then(ClientCommandManager.argument("z", IntegerArgumentType.integer(Integer.MIN_VALUE,Integer.MAX_VALUE)) 17 | .executes(ctx -> { 18 | int x = IntegerArgumentType.getInteger(ctx,"x"); 19 | int y = IntegerArgumentType.getInteger(ctx,"y"); 20 | int z = IntegerArgumentType.getInteger(ctx,"z"); 21 | CListClient.addNewWaypoint(x,y,z,false); 22 | return 0; 23 | }))))); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListConfig.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import eu.midnightdust.lib.config.MidnightConfig; 4 | 5 | public class CListConfig extends MidnightConfig { 6 | @Entry(min=1,max=200) public static int multiplier = 10; 7 | @Entry(min=0) public static int render_distance = 0; 8 | @Entry public static boolean waypoints_toggled = true; 9 | @Entry public static boolean can_place_deathpoints = true; 10 | @Entry public static boolean waypoint_text_background = true; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListData.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.google.common.collect.Lists; 4 | import net.fabricmc.loader.api.FabricLoader; 5 | 6 | import java.io.*; 7 | import java.nio.charset.StandardCharsets; 8 | import java.nio.file.Files; 9 | import java.util.List; 10 | 11 | public class CListData { 12 | public static void saveListToFile(String fileName, List waypointList) { 13 | if (!Files.exists(FabricLoader.getInstance().getConfigDir().resolve("coordinatelist"))) { 14 | try { 15 | Files.createDirectories(FabricLoader.getInstance().getConfigDir().resolve("coordinatelist")); 16 | } catch (IOException ignored) { 17 | } 18 | } 19 | File dataDir = FabricLoader.getInstance().getConfigDir().resolve("coordinatelist").toFile(); 20 | File file = new File(dataDir, fileName); 21 | 22 | try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)))) { 23 | for (int i = 0; i < waypointList.size(); i++) { 24 | writer.println(CListClient.variables.waypoints.get(i).getCoordinates() + "~" + CListClient.variables.waypoints.get(i).name.replaceAll("~","") + "~" + CListClient.variables.waypoints.get(i).dimension + "~" + CListClient.variables.colors.get(i).getHexNoAlpha() + "~" + CListClient.variables.waypoints.get(i).render + "~" + CListClient.variables.waypoints.get(i).deathpoint); 25 | } 26 | } catch (IOException ignored) { 27 | } 28 | } 29 | 30 | public static List loadListFromFile(String fileName) { 31 | File dataDir = FabricLoader.getInstance().getConfigDir().resolve("coordinatelist").toFile(); 32 | File file = new File(dataDir, fileName); 33 | 34 | if (!file.exists()) { 35 | return null; 36 | } 37 | 38 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { 39 | List waypointList = Lists.newArrayList(); 40 | String line; 41 | 42 | while ((line = reader.readLine()) != null) { 43 | String[] segments = line.split("~"); 44 | if (segments.length >= 3) { 45 | String coords = segments[0]; 46 | String name = segments[1]; 47 | String dimension = segments[2]; 48 | String color = null,bool = null,deathpoint = null; 49 | try{ 50 | color = segments[3]; 51 | bool = segments[4]; 52 | deathpoint = segments[5]; 53 | } 54 | catch (IndexOutOfBoundsException ignored){} 55 | CListWaypoint waypoint = new CListWaypoint(coords, name, dimension, Boolean.parseBoolean(bool), Boolean.parseBoolean(deathpoint)); 56 | if(color == null){ 57 | CListClient.addRandomWaypointColor(); 58 | } 59 | else{ 60 | CListWaypointColor color_class = new CListWaypointColor(0,0,0); 61 | color_class.set(color); 62 | CListClient.variables.colors.add(color_class); 63 | } 64 | waypointList.add(waypoint); 65 | } 66 | } 67 | 68 | return waypointList; 69 | } catch (IOException ignored) { 70 | } 71 | 72 | return null; 73 | } 74 | 75 | public static void deleteLegacyFile(String fileName){ 76 | File dataDir = FabricLoader.getInstance().getConfigDir().resolve("coordinatelist").toFile(); 77 | File file = new File(dataDir, fileName); 78 | if(file.exists()){ 79 | boolean ignored = file.delete(); 80 | } 81 | } 82 | 83 | public static List loadListFromFileLegacy(String fileName) { 84 | File dataDir = FabricLoader.getInstance().getConfigDir().resolve("coordinatelist").toFile(); 85 | File file = new File(dataDir, fileName); 86 | 87 | if (!file.exists()) { 88 | return null; 89 | } 90 | 91 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { 92 | List stringList = Lists.newArrayList(); 93 | String line; 94 | 95 | while ((line = reader.readLine()) != null) { 96 | stringList.add(line); 97 | } 98 | 99 | return stringList; 100 | } catch (IOException ignored) { 101 | } 102 | 103 | return null; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListDelayedEvent.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | public class CListDelayedEvent { 4 | private float ticks; 5 | private final Runnable function; 6 | public CListDelayedEvent(float seconds, Runnable function){ 7 | this.ticks = seconds*20; 8 | this.function = function; 9 | } 10 | public boolean update(){ 11 | this.ticks -= 1; 12 | if(ticks<=0){ 13 | this.function.run(); 14 | return true; 15 | } 16 | return false; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListRenderLayers.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.mojang.blaze3d.pipeline.RenderPipeline; 4 | import com.mojang.blaze3d.platform.DepthTestFunction; 5 | import net.minecraft.client.gl.RenderPipelines; 6 | import net.minecraft.client.render.RenderLayer; 7 | import net.minecraft.client.render.RenderPhase; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.TriState; 10 | import net.minecraft.util.Util; 11 | 12 | import java.util.function.Function; 13 | 14 | public class CListRenderLayers { 15 | private static final RenderPipeline POSITION_TEX_COLOR_PIPELINE = RenderPipelines.register( 16 | RenderPipeline.builder(RenderPipelines.POSITION_TEX_COLOR_SNIPPET) 17 | .withLocation("pipeline/position_tex_color") 18 | .withCull(false) 19 | .withoutBlend() 20 | .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) 21 | .withDepthWrite(true) 22 | .build() 23 | ); 24 | public static final Function POSITION_TEX_COLOR = Util.memoize( 25 | texture -> RenderLayer.of( 26 | "pos_tex_color", 27 | 1536, 28 | false, 29 | true, 30 | POSITION_TEX_COLOR_PIPELINE, 31 | RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, TriState.FALSE, false)).build(false) 32 | ) 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListVariables.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.world.ClientWorld; 5 | import org.apache.commons.compress.utils.Lists; 6 | import java.util.List; 7 | 8 | public class CListVariables { 9 | public List waypoints = Lists.newArrayList(); 10 | public List colors = Lists.newArrayList(); 11 | public static List delayed_events = Lists.newArrayList(); 12 | public String worldName; 13 | public ClientWorld last_world; 14 | public static MinecraftClient minecraft_client = MinecraftClient.getInstance(); 15 | public boolean saved_since_last_update; 16 | public boolean loaded_last_world; 17 | public boolean had_death_waypoint_placed; 18 | public boolean is_world_error; 19 | } -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListWaypoint.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import net.minecraft.text.Text; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | public class CListWaypoint { 7 | public int x, y, z; 8 | public String name; 9 | public String dimension; 10 | private int bug_fix; 11 | public boolean render; 12 | public boolean deathpoint; 13 | CListWaypoint(String coords, String waypoint_name, String waypoint_dimension, boolean is_rendered, boolean is_deathpoint){ 14 | String s = coords; 15 | s = s.replace("X", ""); 16 | s = s.replace("Y", ""); 17 | s = s.replace("Z", ""); 18 | s = s.replace(" ", ""); 19 | String[] segments = s.split(":"); 20 | this.x = Integer.parseInt(segments[1]); 21 | this.y = Integer.parseInt(segments[2]); 22 | this.z = Integer.parseInt(segments[3]); 23 | this.name = waypoint_name; 24 | this.dimension = waypoint_dimension; 25 | this.render = is_rendered; 26 | this.deathpoint = is_deathpoint; 27 | this.bug_fix = 0; 28 | } 29 | CListWaypoint(int x, int y, int z, String waypoint_name, String waypoint_dimension, boolean is_rendered, boolean is_deathpoint){ 30 | this.x = x; 31 | this.y = y; 32 | this.z = z; 33 | this.name = waypoint_name; 34 | this.dimension = waypoint_dimension; 35 | this.render = is_rendered; 36 | this.deathpoint = is_deathpoint; 37 | this.bug_fix = 0; 38 | } 39 | public String getCoordinates(){ 40 | return "X: " + x + " Y: " + y + " Z: " + z; 41 | } 42 | public void toggleVisibility(){ 43 | this.bug_fix += 1; 44 | if(bug_fix == 2){ 45 | this.bug_fix = 0; 46 | this.render = !this.render; 47 | CListClient.variables.saved_since_last_update = false; 48 | } 49 | } 50 | public Text getDimensionText(){ 51 | return Text.literal(this.getDimensionString()); 52 | } 53 | public String getDimensionString(){ 54 | String s = this.dimension; 55 | s = s.replace("minecraft:",""); 56 | s = s.replace("_"," "); 57 | s = StringUtils.capitalize(s); 58 | return s; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListWaypointColor.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | public class CListWaypointColor { 4 | public float r; 5 | public float g; 6 | public float b; 7 | CListWaypointColor(float red, float green, float blue){ 8 | r = red; 9 | g = green; 10 | b = blue; 11 | } 12 | public void set(float[] hsv) { 13 | float h = hsv[0]; 14 | float s = hsv[1]; 15 | float v = hsv[2]; 16 | s /= 100; 17 | v /= 100; 18 | float c = v * s; 19 | float x = c * (1 - Math.abs((h / 60) % 2 - 1)); 20 | float m = v - c; 21 | float rPrime, gPrime, bPrime; 22 | if (h < 60) { 23 | rPrime = c; 24 | gPrime = x; 25 | bPrime = 0; 26 | } else if (h < 120) { 27 | rPrime = x; 28 | gPrime = c; 29 | bPrime = 0; 30 | } else if (h < 180) { 31 | rPrime = 0; 32 | gPrime = c; 33 | bPrime = x; 34 | } else if (h < 240) { 35 | rPrime = 0; 36 | gPrime = x; 37 | bPrime = c; 38 | } else if (h < 300) { 39 | rPrime = x; 40 | gPrime = 0; 41 | bPrime = c; 42 | } else { 43 | rPrime = c; 44 | gPrime = 0; 45 | bPrime = x; 46 | } 47 | this.r = (rPrime + m); 48 | this.g = (gPrime + m); 49 | this.b = (bPrime + m); 50 | } 51 | public float[] getHSV() { 52 | float min = Math.min(Math.min(r, g), b); 53 | float max = Math.max(Math.max(r, g), b); 54 | float delta = max - min; 55 | float h, s; 56 | float v = max * 100; 57 | if (max != 0) 58 | s = (delta / max) * 100; 59 | else { 60 | s = 0; 61 | h = 0; 62 | return new float[]{h, s, v}; 63 | } 64 | if (r == max) 65 | h = (g - b) / delta; 66 | else if (g == max) 67 | h = 2 + (b - r) / delta; 68 | else 69 | h = 4 + (r - g) / delta; 70 | h *= 60; 71 | if (h < 0) 72 | h += 360; 73 | if (Float.isNaN(h)) 74 | h = 0; 75 | if (Float.isNaN(s)) 76 | s = 0; 77 | if (Float.isNaN(v)) 78 | v = 0; 79 | h = Float.parseFloat(String.format("%.1f", h).replace(",", ".")); 80 | s = Float.parseFloat(String.format("%.1f", s).replace(",", ".")); 81 | v = Float.parseFloat(String.format("%.1f", v).replace(",", ".")); 82 | return new float[]{h, s, v}; 83 | } 84 | public int getHex(){ 85 | int red = (int) (r * 255); 86 | int green = (int) (g * 255); 87 | int blue = (int) (b * 255); 88 | return (255 << 24) | (red << 16) | (green << 8) | blue; 89 | } 90 | public String getHexNoAlpha(){ 91 | int red = (int) (r * 255); 92 | int green = (int) (g * 255); 93 | int blue = (int) (b * 255); 94 | return String.format("%02X%02X%02X", red, green, blue); 95 | } 96 | public void set(String hex) { 97 | if(hex.length() == 6 && hex.matches("[a-zA-Z0-9]+")){ 98 | hex = hex.replace("#", ""); 99 | String redHex = hex.substring(0, 2); 100 | String greenHex = hex.substring(2, 4); 101 | String blueHex = hex.substring(4, 6); 102 | int red = -1; 103 | int green = -1; 104 | int blue = -1; 105 | try{ 106 | red = Integer.parseInt(redHex, 16); 107 | green = Integer.parseInt(greenHex, 16); 108 | blue = Integer.parseInt(blueHex, 16); 109 | } 110 | catch (NumberFormatException ignored){} 111 | if(red != -1 && green != -1 && blue != -1){ 112 | this.r = red / 255.0f; 113 | this.g = green / 255.0f; 114 | this.b = blue / 255.0f; 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListWaypointConfig.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.mojang.blaze3d.opengl.GlStateManager; 4 | import com.mojang.blaze3d.systems.RenderSystem; 5 | import net.minecraft.client.gui.DrawContext; 6 | import net.minecraft.client.gui.screen.Screen; 7 | import net.minecraft.client.gui.widget.*; 8 | import net.minecraft.client.render.*; 9 | import net.minecraft.text.Text; 10 | import net.minecraft.util.Identifier; 11 | import net.minecraft.util.math.MathHelper; 12 | import org.joml.Matrix4f; 13 | import org.lwjgl.glfw.GLFW; 14 | 15 | import java.awt.*; 16 | 17 | public class CListWaypointConfig extends Screen { 18 | private static int id; 19 | private boolean render_color_picker = false; 20 | private final CListWaypoint waypoint; 21 | private TextFieldWidget waypoint_name; 22 | private static TextFieldWidget waypoint_color; 23 | private TextFieldWidget x, y, z; 24 | private SpriteButton change_color; 25 | private HSVSlider h, s, v; 26 | private static float[] hsv; 27 | public CListWaypointConfig(Text title, int waypoint_id){ 28 | super(title); 29 | id = waypoint_id; 30 | this.waypoint = CListClient.variables.waypoints.get(id); 31 | } 32 | @Override 33 | protected void init(){ 34 | GridWidget gridWidget = new GridWidget(); 35 | hsv = CListClient.variables.colors.get(id).getHSV(); 36 | gridWidget.getMainPositioner().margin(4, 4, 4, 0); 37 | GridWidget.Adder adder = gridWidget.createAdder(2); 38 | adder.add(ButtonWidget.builder(Text.translatable("selectWorld.delete"), button -> { 39 | CListClient.deleteWaypoint(id); 40 | CListVariables.minecraft_client.setScreen(new CListWaypointScreen(Text.literal("Waypoints"))); 41 | }).width(150).build(),1, gridWidget.copyPositioner().marginBottom(10)); 42 | adder.add(ButtonWidget.builder(Text.translatable("gui.done"), button -> {CListVariables.minecraft_client.setScreen(new CListWaypointScreen(Text.literal("Waypoints")));CListClient.variables.saved_since_last_update = false;}).width(150).build(),1, gridWidget.copyPositioner().marginBottom(10)); 43 | this.waypoint_name = new TextFieldWidget(textRenderer, (this.width-150)/2, (this.height-20)/2-80, 150, 20, Text.literal("")); 44 | this.waypoint_name.setFocusUnlocked(true); 45 | this.waypoint_name.setMaxLength(25); 46 | this.waypoint_name.setText(waypoint.name); 47 | waypoint_color = new TextFieldWidget(textRenderer, (this.width-70)/2, (this.height-20)/2+50, 70, 20, Text.literal("")); 48 | waypoint_color.setFocusUnlocked(true); 49 | waypoint_color.setMaxLength(6); 50 | waypoint_color.setText(CListClient.variables.colors.get(id).getHexNoAlpha()); 51 | this.x = new TextFieldWidget(textRenderer, (this.width-50)/2-60, (this.height-20)/2-50, 50, 20, Text.literal("")); 52 | this.x.setFocusUnlocked(true); 53 | this.x.setText(String.valueOf(waypoint.x)); 54 | this.y = new TextFieldWidget(textRenderer, (this.width-50)/2, (this.height-20)/2-50, 50, 20, Text.literal("")); 55 | this.y.setFocusUnlocked(true); 56 | this.y.setText(String.valueOf(waypoint.y)); 57 | this.z = new TextFieldWidget(textRenderer, (this.width-50)/2+60, (this.height-20)/2-50, 50, 20, Text.literal("")); 58 | this.z.setFocusUnlocked(true); 59 | this.z.setText(String.valueOf(waypoint.z)); 60 | gridWidget.refreshPositions(); 61 | SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, 1f); 62 | gridWidget.forEachChild(this::addDrawableChild); 63 | addDrawableChild(this.waypoint_name); 64 | addDrawableChild(waypoint_color); 65 | addDrawableChild(this.x); 66 | addDrawableChild(this.y); 67 | addDrawableChild(this.z); 68 | change_color = new SpriteButton((this.width-50)/2+38,(this.height-20)/2-15,12,12, button -> render_color_picker = !render_color_picker); 69 | this.h = new HSVSlider((this.width-50)/2,(this.height-20)/2-15,110,15,Text.literal("H: " + hsv[0]),hsv[0] / 360,0); 70 | this.s = new HSVSlider((this.width-50)/2,(this.height-20)/2+3,110,15,Text.literal("S: " + hsv[1]),hsv[1] / 100, 1); 71 | this.v = new HSVSlider((this.width-50)/2,(this.height-20)/2+20,110,15,Text.literal("V: " + hsv[2]),hsv[2] / 100, 2); 72 | this.h.visible = false; 73 | this.s.visible = false; 74 | this.v.visible = false; 75 | addDrawableChild(change_color); 76 | addDrawableChild(this.h); 77 | addDrawableChild(this.s); 78 | addDrawableChild(this.v); 79 | } 80 | public static class HSVSlider extends SliderWidget { 81 | private float true_value; 82 | private final int max; 83 | private final int type; 84 | private final String prefix; 85 | private boolean force = false; 86 | private static final Identifier HANDLE_TEXTURE = Identifier.ofVanilla("widget/slider_handle"); 87 | private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = Identifier.ofVanilla("widget/slider_handle_highlighted"); 88 | private boolean sliderFocused; 89 | public HSVSlider(int x, int y, int width, int height, Text text, float value, int type) { 90 | super(x, y, width, height, text, value); 91 | this.type = type; 92 | this.max = type == 0 ? 360 : 100; 93 | this.prefix = type == 0 ? "H: " : type == 1 ? "S: " : "V: "; 94 | } 95 | public void setValue(float value){ 96 | double d = this.value; 97 | this.value = MathHelper.clamp(value, 0.0, 1.0); 98 | if (d != this.value) { 99 | this.force = true; 100 | this.applyValue(); 101 | } 102 | this.updateMessage(); 103 | } 104 | @Override 105 | protected void updateMessage() { 106 | this.setMessage(Text.literal(prefix + true_value)); 107 | } 108 | @Override 109 | protected void applyValue() { 110 | this.true_value = (float)Math.round((this.value * (this.max)) * (double)((float)100)) / (float)100; 111 | hsv[type] = this.true_value; 112 | if(!this.force){ 113 | CListClient.variables.colors.get(id).set(hsv); 114 | waypoint_color.setText(CListClient.variables.colors.get(id).getHexNoAlpha()); 115 | CListClient.variables.saved_since_last_update = false; 116 | } 117 | else{ 118 | this.force = false; 119 | } 120 | } 121 | private Identifier getHandleTexture() { 122 | return !this.hovered && !this.sliderFocused ? HANDLE_TEXTURE : HANDLE_HIGHLIGHTED_TEXTURE; 123 | } 124 | @Override 125 | public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta){ 126 | Matrix4f matrix4f = context.getMatrices().peek().getPositionMatrix(); 127 | VertexConsumer vertexConsumer = CListVariables.minecraft_client.getBufferBuilders().getEntityVertexConsumers().getBuffer(RenderLayer.getGui()); 128 | RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); 129 | GlStateManager._enableBlend(); 130 | GlStateManager._enableDepthTest(); 131 | int color = CListClient.variables.colors.get(id).getHex(); 132 | float[] color_float = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, null); 133 | if(type == 0){ 134 | for (int i = 0; i < this.width; i++) { 135 | float hue = i / (float) this.width; 136 | int color_h = Color.HSBtoRGB(hue, color_float[1], color_float[2]); 137 | vertexConsumer.vertex(matrix4f, this.getX() + i, this.getY(), 0).color((color_h >> 16) & 0xFF, (color_h >> 8) & 0xFF, color_h & 0xFF, 0xFF); 138 | vertexConsumer.vertex(matrix4f, this.getX() + i, this.getY() + this.getHeight(), 0).color((color_h >> 16) & 0xFF, (color_h >> 8) & 0xFF, color_h & 0xFF, 0xFF); 139 | vertexConsumer.vertex(matrix4f, this.getX() + i + 1, this.getY() + this.getHeight(), 0).color((color_h >> 16) & 0xFF, (color_h >> 8) & 0xFF, color_h & 0xFF, 0xFF); 140 | vertexConsumer.vertex(matrix4f, this.getX() + i + 1, this.getY(), 0).color((color_h >> 16) & 0xFF, (color_h >> 8) & 0xFF, color_h & 0xFF, 0xFF); 141 | } 142 | } 143 | else{ 144 | int color_s = Color.HSBtoRGB(color_float[0], 1.0f, color_float[2]); 145 | int color_v = Color.HSBtoRGB(color_float[0], color_float[1], 1.0f); 146 | int color_s_start = Color.HSBtoRGB(1.0f, 0.0f, color_float[2]); 147 | vertexConsumer.vertex(matrix4f, this.getX(), this.getY(), 0).color(type == 1 ? color_s_start : 0xFF000000); 148 | vertexConsumer.vertex(matrix4f, this.getX(), this.getY() + this.getHeight(), 0).color(type == 1 ? color_s_start : 0xFF000000); 149 | vertexConsumer.vertex(matrix4f, this.getX() + this.width, this.getY() + this.getHeight(), 0).color(type == 1 ? color_s : color_v); 150 | vertexConsumer.vertex(matrix4f, this.getX() + this.width, this.getY(), 0).color(type == 1 ? color_s : color_v); 151 | } 152 | context.drawGuiTexture(RenderLayer::getGuiTextured, this.getHandleTexture(), this.getX() + (int)(this.value * (double)(this.width - 8)), this.getY(), 8, this.getHeight()); 153 | RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); 154 | int i = this.active ? 16777215 : 10526880; 155 | this.drawScrollableText(context, CListVariables.minecraft_client.textRenderer, 2, i | MathHelper.ceil(this.alpha * 255.0F) << 24); 156 | } 157 | } 158 | private static class SpriteButton extends ButtonWidget { 159 | public SpriteButton(int x, int y, int width, int height, PressAction onPress) { 160 | super(x, y, width, height, Text.literal(""), onPress, DEFAULT_NARRATION_SUPPLIER); 161 | } 162 | @Override 163 | public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { 164 | Identifier icon = Identifier.of("coordinatelist", "icon/change"); 165 | GlStateManager._enableBlend(); 166 | context.drawGuiTexture(RenderLayer::getGuiTextured, icon, getX(), getY(), width, height); 167 | GlStateManager._disableBlend(); 168 | } 169 | } 170 | @Override 171 | public void render(DrawContext context, int mouseX, int mouseY, float delta) { 172 | int SQUARE_SIZE = 50; 173 | int centerX = this.width / 2; 174 | int centerY = this.height / 2; 175 | if(render_color_picker){ 176 | centerX = width / 2 - 60; 177 | change_color.setX((this.width-50)/2-22); 178 | } 179 | else{ 180 | change_color.setX((this.width-50)/2+38); 181 | } 182 | int left = centerX - SQUARE_SIZE / 2; 183 | int top = centerY - SQUARE_SIZE / 2; 184 | int right = centerX + SQUARE_SIZE / 2; 185 | int bottom = centerY + SQUARE_SIZE / 2; 186 | super.render(context, mouseX, mouseY, delta); 187 | context.fill(left, top, right, bottom, CListClient.variables.colors.get(id).getHex()); 188 | change_color.renderWidget(context,mouseX,mouseY,delta); 189 | if(render_color_picker){ 190 | this.h.visible = true; 191 | this.s.visible = true; 192 | this.v.visible = true; 193 | } 194 | else{ 195 | this.h.visible = false; 196 | this.s.visible = false; 197 | this.v.visible = false; 198 | } 199 | } 200 | private static boolean isParsableToInt(String str) { 201 | try { 202 | Integer.parseInt(str); 203 | return true; 204 | } catch (NumberFormatException e) { 205 | return false; 206 | } 207 | } 208 | @Override 209 | public boolean charTyped(char chr, int keyCode) { 210 | boolean result = super.charTyped(chr, keyCode); 211 | if(this.waypoint_name.isFocused()){ 212 | waypoint.name = waypoint_name.getText(); 213 | } 214 | if(waypoint_color.isFocused()){ 215 | CListClient.variables.colors.get(id).set(waypoint_color.getText()); 216 | hsv = CListClient.variables.colors.get(id).getHSV(); 217 | h.setValue(hsv[0] / 360); 218 | s.setValue(hsv[1] / 100); 219 | v.setValue(hsv[2] / 100); 220 | } 221 | if(this.x.isFocused() && isParsableToInt(x.getText())){ 222 | waypoint.x = Integer.parseInt(x.getText()); 223 | } 224 | if(this.y.isFocused() && isParsableToInt(y.getText())){ 225 | waypoint.y = Integer.parseInt(y.getText()); 226 | } 227 | if(this.z.isFocused() && isParsableToInt(z.getText())){ 228 | waypoint.z = Integer.parseInt(z.getText()); 229 | } 230 | CListClient.variables.saved_since_last_update = false; 231 | return true; 232 | } 233 | @Override 234 | public boolean keyPressed(int keyCode, int scanCode, int modifiers) { 235 | super.keyPressed(keyCode, scanCode, modifiers); 236 | if(keyCode == GLFW.GLFW_KEY_V && modifiers == GLFW.GLFW_MOD_CONTROL){ 237 | if(this.waypoint_name.isFocused()){ 238 | waypoint.name = waypoint_name.getText(); 239 | } 240 | if(waypoint_color.isFocused()){ 241 | CListClient.variables.colors.get(id).set(waypoint_color.getText()); 242 | hsv = CListClient.variables.colors.get(id).getHSV(); 243 | h.setValue(hsv[0] / 360); 244 | s.setValue(hsv[1] / 100); 245 | v.setValue(hsv[2] / 100); 246 | } 247 | if(this.x.isFocused() && isParsableToInt(x.getText())){ 248 | waypoint.x = Integer.parseInt(x.getText()); 249 | } 250 | if(this.y.isFocused() && isParsableToInt(y.getText())){ 251 | waypoint.y = Integer.parseInt(y.getText()); 252 | } 253 | if(this.z.isFocused() && isParsableToInt(z.getText())){ 254 | waypoint.z = Integer.parseInt(z.getText()); 255 | } 256 | CListClient.variables.saved_since_last_update = false; 257 | } 258 | if (keyCode == GLFW.GLFW_KEY_BACKSPACE) { 259 | if(this.waypoint_name.isFocused()){ 260 | waypoint.name = waypoint_name.getText(); 261 | } 262 | if(waypoint_color.isFocused()){ 263 | CListClient.variables.colors.get(id).set(waypoint_color.getText()); 264 | hsv = CListClient.variables.colors.get(id).getHSV(); 265 | h.setValue(hsv[0] / 360); 266 | s.setValue(hsv[1] / 100); 267 | v.setValue(hsv[2] / 100); 268 | } 269 | if(this.x.isFocused() && isParsableToInt(x.getText())){ 270 | waypoint.x = Integer.parseInt(x.getText()); 271 | } 272 | if(this.y.isFocused() && isParsableToInt(y.getText())){ 273 | waypoint.y = Integer.parseInt(y.getText()); 274 | } 275 | if(this.z.isFocused() && isParsableToInt(z.getText())){ 276 | waypoint.z = Integer.parseInt(z.getText()); 277 | } 278 | CListClient.variables.saved_since_last_update = false; 279 | } 280 | return true; 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/CListWaypointScreen.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist; 2 | 3 | import com.mojang.blaze3d.opengl.GlStateManager; 4 | import net.minecraft.client.gui.DrawContext; 5 | import net.minecraft.client.gui.Element; 6 | import net.minecraft.client.gui.screen.Screen; 7 | import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; 8 | import net.minecraft.client.gui.tooltip.Tooltip; 9 | import net.minecraft.client.gui.widget.*; 10 | import net.minecraft.client.render.RenderLayer; 11 | import net.minecraft.entity.player.PlayerEntity; 12 | import net.minecraft.text.Text; 13 | import net.minecraft.util.Identifier; 14 | import org.apache.commons.compress.utils.Lists; 15 | import org.lwjgl.glfw.GLFW; 16 | 17 | import java.util.List; 18 | 19 | public class CListWaypointScreen extends Screen { 20 | public CListWaypointScreen(Text title) { 21 | super(title); 22 | } 23 | private ScrollList list; 24 | private int selected_waypoint_id = -1; 25 | private ButtonWidget copy_coordinates_button; 26 | private ButtonWidget edit_waypoint_button; 27 | private ButtonWidget delete_waypoint_button; 28 | @Override 29 | protected void init() { 30 | GridWidget gridWidget = new GridWidget(); 31 | GridWidget gridWidgetBottom = new GridWidget(); 32 | gridWidget.getMainPositioner().margin(4, 4, 4, 0); 33 | gridWidgetBottom.getMainPositioner().margin(4, 4, 4, 0); 34 | GridWidget.Adder adder = gridWidget.createAdder(2); 35 | GridWidget.Adder adderBottom = gridWidgetBottom.createAdder(3); 36 | adder.add(ButtonWidget.builder(Text.translatable("buttons.add.new.waypoint"), button -> { 37 | PlayerEntity player = CListVariables.minecraft_client.player; 38 | CListClient.addNewWaypoint((int) Math.round(player.getX()), (int) Math.round(player.getY()), (int) Math.round(player.getZ()),false); 39 | list.RefreshElements(); 40 | }).width(300).build(),2, gridWidget.copyPositioner().marginTop(10)); 41 | copy_coordinates_button = ButtonWidget.builder(Text.literal("---"), button -> { 42 | long window = CListVariables.minecraft_client.getWindow().getHandle(); 43 | CListWaypoint waypoint = CListClient.variables.waypoints.get(selected_waypoint_id); 44 | GLFW.glfwSetClipboardString(window, waypoint.x + " " + waypoint.y + " " + waypoint.z); 45 | }).width(150).build(); 46 | copy_coordinates_button.setTooltip(Tooltip.of(Text.translatable("tooltip.copy.waypoint.coordinates"))); 47 | edit_waypoint_button = ButtonWidget.builder(Text.translatable("selectWorld.edit"), button -> CListVariables.minecraft_client.setScreen(new CListWaypointConfig(Text.literal("Config"),selected_waypoint_id))).width(100).build(); 48 | delete_waypoint_button = ButtonWidget.builder(Text.translatable("selectWorld.delete"), button -> { 49 | CListClient.deleteWaypoint(selected_waypoint_id); 50 | if(selected_waypoint_id >= CListClient.variables.waypoints.size()){ 51 | selected_waypoint_id -= 1; 52 | } 53 | list.RefreshElements(); 54 | }).width(100).build(); 55 | adderBottom.add(delete_waypoint_button,1, gridWidgetBottom.copyPositioner().marginBottom(10)); 56 | adderBottom.add(copy_coordinates_button,1, gridWidgetBottom.copyPositioner().marginBottom(10)); 57 | adderBottom.add(edit_waypoint_button,1, gridWidgetBottom.copyPositioner().marginBottom(10)); 58 | list = new ScrollList(); 59 | list.SetupElements(); 60 | addDrawableChild(list); 61 | gridWidget.refreshPositions(); 62 | gridWidgetBottom.refreshPositions(); 63 | SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, 0f); 64 | SimplePositioningWidget.setPos(gridWidgetBottom, 0, 0, this.width, this.height, 0.5f, 1f); 65 | gridWidget.forEachChild(this::addDrawableChild); 66 | gridWidgetBottom.forEachChild(this::addDrawableChild); 67 | } 68 | @Override 69 | public void render(DrawContext context, int mouseX, int mouseY, float delta) { 70 | super.render(context, mouseX, mouseY, delta); 71 | if(selected_waypoint_id != -1){ 72 | list.setSelected(list.children().get(selected_waypoint_id)); 73 | } 74 | if(selected_waypoint_id >= 0){ 75 | copy_coordinates_button.active = true; 76 | edit_waypoint_button.active = true; 77 | delete_waypoint_button.active = true; 78 | } 79 | else{ 80 | copy_coordinates_button.active = false; 81 | edit_waypoint_button.active = false; 82 | delete_waypoint_button.active = false; 83 | } 84 | } 85 | @Override 86 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 87 | list.mouseClicked(mouseX, mouseY, button); 88 | return super.mouseClicked(mouseX, mouseY, button); 89 | } 90 | @Override 91 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 92 | list.mouseReleased(mouseX, mouseY, button); 93 | return super.mouseReleased(mouseX, mouseY, button); 94 | } 95 | @Override 96 | public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { 97 | list.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); 98 | return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); 99 | } 100 | private class ScrollList extends EntryListWidget { 101 | public ScrollList(){ 102 | super(CListWaypointScreen.this.client, CListWaypointScreen.this.width, CListWaypointScreen.this.height-64, 32, 25);//32 103 | } 104 | public void SetupElements(){ 105 | for(int i = 0; i < CListClient.variables.waypoints.size(); i++){ 106 | ScrollList.ScrollListEntry Coordinate = new ScrollList.ScrollListEntry(i); 107 | list.addEntry(Coordinate); 108 | } 109 | } 110 | public void RefreshElements(){ 111 | clearEntries(); 112 | SetupElements(); 113 | } 114 | @Override 115 | public int getRowWidth() { 116 | return 245; 117 | } 118 | public void appendClickableNarrations(NarrationMessageBuilder builder){} 119 | private static class InvisibleButton extends ButtonWidget{ 120 | public InvisibleButton(int x, int y, int width, int height, PressAction onPress){ 121 | super(x, y, width, height, Text.literal(""), onPress,DEFAULT_NARRATION_SUPPLIER); 122 | } 123 | @Override 124 | public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {} 125 | } 126 | private static class SpriteButton extends ButtonWidget { 127 | private final int id; 128 | public SpriteButton(int x, int y, int width, int height, PressAction onPress, int coordinate_id) { 129 | super(x, y, width, height, Text.literal(""), onPress,DEFAULT_NARRATION_SUPPLIER); 130 | this.id = coordinate_id; 131 | } 132 | @Override 133 | public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { 134 | Identifier eye_icon; 135 | if(CListClient.variables.waypoints.get(id).render){ 136 | eye_icon = Identifier.of("coordinatelist", "icon/visible"); 137 | } 138 | else{ 139 | eye_icon = Identifier.of("coordinatelist", "icon/not_visible"); 140 | } 141 | GlStateManager._enableBlend(); 142 | context.drawGuiTexture(RenderLayer::getGuiTextured, eye_icon, getX(), getY(), width, height); 143 | GlStateManager._disableBlend(); 144 | } 145 | } 146 | private class ScrollListEntry extends EntryListWidget.Entry{ 147 | private final Text waypoint_name; 148 | private final Text dimension; 149 | private final SpriteButton sh; 150 | private final InvisibleButton select; 151 | private final List children; 152 | private final int id; 153 | public ScrollListEntry(int id){ 154 | this.id = id; 155 | this.waypoint_name = Text.of(CListClient.variables.waypoints.get(id).name); 156 | this.dimension = CListClient.variables.waypoints.get(id).getDimensionText(); 157 | this.sh = new SpriteButton(0, 0, 16, 12, button -> { 158 | CListClient.variables.waypoints.get(id).toggleVisibility(); 159 | selected_waypoint_id = id; 160 | CListWaypoint waypoint = CListClient.variables.waypoints.get(selected_waypoint_id); 161 | copy_coordinates_button.setMessage(Text.literal(waypoint.x + " " + waypoint.y + " " + waypoint.z)); 162 | }, id); 163 | this.select = new InvisibleButton(0, 0, 240, 25, button -> { 164 | selected_waypoint_id = id; 165 | CListWaypoint waypoint = CListClient.variables.waypoints.get(selected_waypoint_id); 166 | copy_coordinates_button.setMessage(Text.literal(waypoint.x + " " + waypoint.y + " " + waypoint.z)); 167 | }); 168 | this.children = Lists.newArrayList(); 169 | this.children.add(sh); 170 | this.children.add(select); 171 | } 172 | @Override 173 | public void render(DrawContext context, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovered, float delta) { 174 | sh.setX(x+2); 175 | sh.setY(y+4); 176 | select.setX(x); 177 | select.setY(y); 178 | sh.render(context, mouseX, mouseY, delta); 179 | select.render(context, mouseX, mouseY, delta); 180 | context.drawTextWithShadow(CListVariables.minecraft_client.textRenderer, dimension.getString(), x+180, y+6, 0xFFFFFF); 181 | context.drawTextWithShadow(CListVariables.minecraft_client.textRenderer, waypoint_name.getString(), x+22, y+6, CListClient.variables.colors.get(id).getHex()); 182 | } 183 | @Override 184 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 185 | boolean handled = false; 186 | for (Element E : children) { 187 | if (E.mouseClicked(mouseX, mouseY, button)) { 188 | handled = true; 189 | break; 190 | } 191 | } 192 | return handled || super.mouseClicked(mouseX, mouseY, button); 193 | } 194 | @Override 195 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 196 | boolean handled = false; 197 | for (Element E : children) { 198 | if (E.mouseReleased(mouseX, mouseY, button)) { 199 | handled = true; 200 | break; 201 | } 202 | } 203 | return handled || super.mouseReleased(mouseX, mouseY, button); 204 | } 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /src/main/java/one/pouekdev/coordinatelist/mixin/CListChatGrabber.java: -------------------------------------------------------------------------------- 1 | package one.pouekdev.coordinatelist.mixin; 2 | 3 | import net.minecraft.client.gui.hud.ChatHud; 4 | import net.minecraft.client.gui.hud.ChatHudLine; 5 | import net.minecraft.text.ClickEvent; 6 | import net.minecraft.text.Text; 7 | import net.minecraft.util.Formatting; 8 | import one.pouekdev.coordinatelist.CListDelayedEvent; 9 | import one.pouekdev.coordinatelist.CListVariables; 10 | import org.apache.commons.compress.utils.Lists; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | import java.util.List; 18 | import java.util.regex.Matcher; 19 | import java.util.regex.Pattern; 20 | 21 | @Mixin(ChatHud.class) 22 | public abstract class CListChatGrabber { 23 | @Inject(method = "logChatMessage", at = @At("RETURN")) 24 | private void getCoordsFromChat(ChatHudLine message, CallbackInfo ci) { 25 | List numbersList = Lists.newArrayList(); 26 | String player; 27 | try{ 28 | String content = message.content().getString().replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n"); 29 | player = StringUtils.substringBetween(content, "<", ">"); 30 | content = content.replace("<","").replace(">","").replace(player,""); 31 | Pattern pattern = Pattern.compile("-?\\b(?![A-Za-z])\\d+(\\.\\d+)?\\b"); 32 | Matcher matcher = pattern.matcher(content); 33 | while (matcher.find()) { 34 | numbersList.add(matcher.group()); 35 | } 36 | } 37 | catch (NullPointerException ignored){} 38 | if(numbersList.size() >= 3){ 39 | int x = Math.round(Float.parseFloat(numbersList.get(0))); 40 | int y = Math.round(Float.parseFloat(numbersList.get(1))); 41 | int z = Math.round(Float.parseFloat(numbersList.get(2))); 42 | Text clickableMessage = Text.translatable("chat.create.waypoint.message").formatted(Formatting.GREEN).styled(style -> style.withClickEvent(new ClickEvent.RunCommand("/clist " + x + " " + y + " " + z))); 43 | CListVariables.delayed_events.add(new CListDelayedEvent(0.1f,() -> CListVariables.minecraft_client.inGameHud.getChatHud().addMessage(clickableMessage))); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/de_de.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "CList Tastenkombinationen", 3 | "keybinds.waypoint.add": "Wegpunkt hier erstellen", 4 | "keybinds.waypoints.menu": "Wegpunkte Menü öffnen", 5 | "keybinds.waypoints.toggle": "Sichtbarkeit der Wegpunkte umschalten", 6 | "coordinatelist.midnightconfig.title": "CList Konfiguration", 7 | "coordinatelist.midnightconfig.multiplier": "Größe der Wegpunkte", 8 | "coordinatelist.midnightconfig.render_distance": "Sichtweite der Wegpunkte (0 für unendliche Sichtweite)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "Wegpunkte anzeigen", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "Automatisch Wegpunkte bei Tod erstellen", 11 | "waypoint.last.death": "Letzter Todespunkt", 12 | "waypoint.new.waypoint": "Neuer Wegpunkt", 13 | "buttons.add.new.waypoint": "Wegpunkt hier erstellen", 14 | "tooltip.copy.waypoint.coordinates": "Koordinaten des gewählen Punktes kopieren", 15 | "chat.create.waypoint.message": "[Wegpunkt erstellen]" 16 | } -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "CList Keybinds", 3 | "keybinds.waypoint.add": "Add a waypoint in current position", 4 | "keybinds.waypoints.menu": "Open waypoints menu", 5 | "keybinds.waypoints.toggle": "Toggle waypoints visibility", 6 | "coordinatelist.midnightconfig.title": "CList configuration", 7 | "coordinatelist.midnightconfig.multiplier": "Waypoints' size", 8 | "coordinatelist.midnightconfig.render_distance": "The distance to which the waypoint is visible (0 means no limit)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "Show waypoints", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "Create waypoints on death", 11 | "coordinatelist.midnightconfig.waypoint_text_background": "Show background behind the waypoint name", 12 | "modmenu.summaryTranslation.coordinatelist": "A simple minimalistic fabric mod for saving your coordinates.", 13 | "modmenu.descriptionTranslation.coordinatelist": "Coordinate List (CList for short) is a simple minimalistic fabric mod for saving your coordinates. No minimaps. Just a list with in-game waypoints.", 14 | "waypoint.last.death": "Last death", 15 | "waypoint.new.waypoint": "New Waypoint", 16 | "buttons.add.new.waypoint": "Add a new waypoint in current position", 17 | "tooltip.copy.waypoint.coordinates": "Click to copy selected waypoints coordinates", 18 | "chat.create.waypoint.message": "[Create a waypoint]" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/ja_jp.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "CList", 3 | "keybinds.waypoint.add": "現在位置をウェイポイントに追加", 4 | "keybinds.waypoints.menu": "ウェイポイントのメニューを開く", 5 | "keybinds.waypoints.toggle": "ウェイポイントの表示 ・非表示", 6 | "coordinatelist.midnightconfig.title": "CList 設定", 7 | "coordinatelist.midnightconfig.multiplier": "ウェイポイントの表示サイズ", 8 | "coordinatelist.midnightconfig.render_distance": "ウェイポイントが見える距離(0は制限なし)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "ウェイポイントを表示する", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "死亡時にウェイポイントを作成する", 11 | "coordinatelist.midnightconfig.waypoint_text_background": "ウェイポイント名の後ろに背景を表示する", 12 | "modmenu.summaryTranslation.coordinatelist": "シンプルでミニマルなファブリックMODで座標を保存。", 13 | "modmenu.descriptionTranslation.coordinatelist": "Coordinate List (略してCList)は、座標を保存するためのシンプルでミニマルなファブリックMODです。ミニマップはありません。ただゲーム内のウェイポイントをリスト表示するだけです。", 14 | "waypoint.last.death": "死亡地点", 15 | "waypoint.new.waypoint": "新しいウェイポイント", 16 | "buttons.add.new.waypoint": "現在位置を新しいウェイポイントに追加する", 17 | "tooltip.copy.waypoint.coordinates": "クリックすると、選択したウェイポイントの座標がコピーされます。", 18 | "chat.create.waypoint.message": "[ウェイポイントの作成]" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/pl_pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "Skróty klawiszowe CList", 3 | "keybinds.waypoint.add": "Dodaj punkt orientacyjny w obecnym miejscu", 4 | "keybinds.waypoints.menu": "Otwórz menu punktów orientacyjnych", 5 | "keybinds.waypoints.toggle": "Zmień widoczność punktów orientacyjnych", 6 | "coordinatelist.midnightconfig.title": "Konfiguracja CList", 7 | "coordinatelist.midnightconfig.multiplier": "Rozmiar punktów orientacyjnych", 8 | "coordinatelist.midnightconfig.render_distance": "Odległość na jaką jest widoczny punkt orientacyjny (0 oznacza bez limitu)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "Pokaż punkty orientacyjne", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "Twórz punkty orientacyjne przy śmierci", 11 | "coordinatelist.midnightconfig.waypoint_text_background": "Wyświetlaj tło za nazwą punktu orientacyjnego", 12 | "modmenu.summaryTranslation.coordinatelist": "Prosty i minimalistyczny mod na fabric'a do zapisywania swojej pozycji", 13 | "modmenu.descriptionTranslation.coordinatelist": "Coordinate List (w skrócie CList) to prosty i minimalistyczny mod na fabric'a do zapisywania swojej pozycji. Zero minimap. Tylko prosta lista z wyświetlanymi punktami orientacyjnymi w grze.", 14 | "waypoint.last.death": "Ostatnia śmierć", 15 | "waypoint.new.waypoint": "Nowy Punkt Orientacyjny", 16 | "buttons.add.new.waypoint": "Dodaj nowy punkt orientacyjny w obecnym miejscu", 17 | "tooltip.copy.waypoint.coordinates": "Kliknij aby skopiować współrzędne wybranego punktu orientacyjnego", 18 | "chat.create.waypoint.message": "[Stwórz punkt orientacyjny]" 19 | } -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/pt_br.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "Teclas de Atalho do CList", 3 | "keybinds.waypoint.add": "Adicionar um ponto de referência na posição atual", 4 | "keybinds.waypoints.menu": "Abrir menu de pontos de referência", 5 | "keybinds.waypoints.toggle": "Alternar visibilidade dos pontos de referência", 6 | "coordinatelist.midnightconfig.title": "Configuração do CList", 7 | "coordinatelist.midnightconfig.multiplier": "Tamanho dos pontos de referência", 8 | "coordinatelist.midnightconfig.render_distance": "A distância até a qual o ponto de referência é visível (0 significa sem limite)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "Mostrar pontos de referência", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "Criar pontos de referência ao morrer", 11 | "coordinatelist.midnightconfig.waypoint_text_background": "Mostrar fundo atrás do nome do ponto de referência", 12 | "modmenu.summaryTranslation.coordinatelist": "Um mod fabric simples e minimalista para salvar suas coordenadas.", 13 | "modmenu.descriptionTranslation.coordinatelist": "Coordinate List (Lista de Coordenadas ou CList para abreviar) é um mod fabric simples e minimalista para salvar suas coordenadas. Sem mini-mapas. Apenas uma lista com pontos de referência no jogo.", 14 | "waypoint.last.death": "Última morte", 15 | "waypoint.new.waypoint": "Novo Ponto de Referência", 16 | "buttons.add.new.waypoint": "Adicionar um novo ponto de referência na posição atual", 17 | "tooltip.copy.waypoint.coordinates": "Clique para copiar as coordenadas dos pontos de referência selecionados", 18 | "chat.create.waypoint.message": "[Criar um ponto de referência]" 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "Сочетания Клавиш CList", 3 | "keybinds.waypoint.add": "Добавить путевую точку в текущей позиции", 4 | "keybinds.waypoints.menu": "Открыть меню путевых точек", 5 | "waypoint.last.death": "Последняя смерть", 6 | "waypoint.new.waypoint": "Новая Путевая Точка", 7 | "buttons.add.new.waypoint": "Создать новую путевую точку в текущей позиции" 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybinds.category.name": "CList 快捷键", 3 | "keybinds.waypoint.add": "在当前位置添加路径点", 4 | "keybinds.waypoints.menu": "打开路径点菜单", 5 | "keybinds.waypoints.toggle": "切换路径点可见性", 6 | "coordinatelist.midnightconfig.title": "CList 配置", 7 | "coordinatelist.midnightconfig.multiplier": "路径点大小", 8 | "coordinatelist.midnightconfig.render_distance": "路径点可见的距离(0 表示无限制)", 9 | "coordinatelist.midnightconfig.waypoints_toggled": "显示路径点", 10 | "coordinatelist.midnightconfig.can_place_deathpoints": "死亡时创建路径点", 11 | "coordinatelist.midnightconfig.waypoint_text_background": "在路径点名称后面显示背景", 12 | "modmenu.summaryTranslation.coordinatelist": "一个简单的极简主义Fabric模组,用于保存您的坐标。", 13 | "modmenu.descriptionTranslation.coordinatelist": "CoordinateList(简称CList)是一个简单的极简主义Fabric模组,用于保存您的坐标。没有小地图。只有一个包含于游戏的内路径点的列表。", 14 | "waypoint.last.death": "最后死亡点", 15 | "waypoint.new.waypoint": "新路径点", 16 | "buttons.add.new.waypoint": "在当前位置添加一个新路径点", 17 | "tooltip.copy.waypoint.coordinates": "点击复制选中的路径点坐标", 18 | "chat.create.waypoint.message": "[创建路径点]" 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/skull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/skull.png -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/change.png -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/not_visible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/not_visible.png -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/visible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/textures/gui/sprites/icon/visible.png -------------------------------------------------------------------------------- /src/main/resources/assets/coordinatelist/waypoint_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PouekDEV/CList/0b29e293fb68139f4c4803f1102d12351f0bea13/src/main/resources/assets/coordinatelist/waypoint_icon.png -------------------------------------------------------------------------------- /src/main/resources/coordinatelist.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "one.pouekdev.coordinatelist.mixin", 5 | "compatibilityLevel": "JAVA_21", 6 | "mixins": [ 7 | "CListChatGrabber" 8 | ], 9 | "injectors": { 10 | "defaultRequire": 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "coordinatelist", 4 | "version": "${version}", 5 | 6 | "name": "CList", 7 | "description": "Coordinate List (CList for short) is a simple minimalistic fabric mod for saving your coordinates. No minimaps. Just a list with in-game waypoints.", 8 | "authors": [ 9 | "PouekDEV" 10 | ], 11 | "contact": { 12 | "homepage": "https://modrinth.com/mod/clist", 13 | "sources": "https://github.com/PouekDEV/CList", 14 | "issues": "https://github.com/PouekDEV/CList/issues" 15 | }, 16 | 17 | "license": "MIT License", 18 | "icon": "assets/coordinatelist/icon.png", 19 | 20 | "environment": "client", 21 | "entrypoints": { 22 | "main": [ 23 | "one.pouekdev.coordinatelist.CList" 24 | ], 25 | "client": [ 26 | "one.pouekdev.coordinatelist.CListClient" 27 | ] 28 | }, 29 | "mixins": [ 30 | "coordinatelist.mixins.json" 31 | ], 32 | 33 | "depends": { 34 | "fabricloader": ">=0.16.10", 35 | "fabric-api": "*", 36 | "minecraft": "~1.21.5", 37 | "java": ">=21", 38 | "midnightlib": ">=1.7.1" 39 | }, 40 | 41 | "suggests": { 42 | "another-mod": "*" 43 | } 44 | } 45 | --------------------------------------------------------------------------------