├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── com │ └── chaosthedude │ └── explorerscompass │ ├── ExplorersCompass.java │ ├── client │ ├── ExplorersCompassAngle.java │ ├── ExplorersCompassAngleState.java │ ├── ExplorersCompassClient.java │ ├── ExplorersCompassOverlay.java │ └── OverlaySide.java │ ├── config │ └── ConfigHandler.java │ ├── gui │ ├── ExplorersCompassScreen.java │ ├── GuiWrapper.java │ ├── StructureSearchEntry.java │ ├── StructureSearchList.java │ ├── TransparentButton.java │ └── TransparentTextField.java │ ├── items │ └── ExplorersCompassItem.java │ ├── network │ ├── CompassSearchPacket.java │ ├── SyncPacket.java │ └── TeleportPacket.java │ ├── registry │ └── ExplorersCompassRegistry.java │ ├── sorting │ ├── DimensionSorting.java │ ├── GroupSorting.java │ ├── ISorting.java │ ├── NameSorting.java │ └── SourceSorting.java │ ├── util │ ├── CompassState.java │ ├── ItemUtils.java │ ├── PlayerUtils.java │ ├── RenderUtils.java │ └── StructureUtils.java │ └── worker │ ├── ConcentricRingsSearchWorker.java │ ├── GenericSearchWorker.java │ ├── RandomSpreadSearchWorker.java │ ├── SearchWorkerManager.java │ └── StructureSearchWorker.java └── resources ├── META-INF └── mods.toml ├── assets └── explorerscompass │ ├── items │ └── explorerscompass.json │ ├── lang │ ├── de_de.json │ ├── en_us.json │ ├── es_es.json │ ├── fr_fr.json │ ├── ja_jp.json │ ├── pt_br.json │ ├── ru_ru.json │ ├── zh_cn.json │ └── zh_tw.json │ ├── models │ └── item │ │ ├── explorerscompass_00.json │ │ ├── explorerscompass_01.json │ │ ├── explorerscompass_02.json │ │ ├── explorerscompass_03.json │ │ ├── explorerscompass_04.json │ │ ├── explorerscompass_05.json │ │ ├── explorerscompass_06.json │ │ ├── explorerscompass_07.json │ │ ├── explorerscompass_08.json │ │ ├── explorerscompass_09.json │ │ ├── explorerscompass_10.json │ │ ├── explorerscompass_11.json │ │ ├── explorerscompass_12.json │ │ ├── explorerscompass_13.json │ │ ├── explorerscompass_14.json │ │ ├── explorerscompass_15.json │ │ ├── explorerscompass_16.json │ │ ├── explorerscompass_17.json │ │ ├── explorerscompass_18.json │ │ ├── explorerscompass_19.json │ │ ├── explorerscompass_20.json │ │ ├── explorerscompass_21.json │ │ ├── explorerscompass_22.json │ │ ├── explorerscompass_23.json │ │ ├── explorerscompass_24.json │ │ ├── explorerscompass_25.json │ │ ├── explorerscompass_26.json │ │ ├── explorerscompass_27.json │ │ ├── explorerscompass_28.json │ │ ├── explorerscompass_29.json │ │ ├── explorerscompass_30.json │ │ └── explorerscompass_31.json │ └── textures │ └── item │ ├── explorerscompass_00.png │ ├── explorerscompass_01.png │ ├── explorerscompass_02.png │ ├── explorerscompass_03.png │ ├── explorerscompass_04.png │ ├── explorerscompass_05.png │ ├── explorerscompass_06.png │ ├── explorerscompass_07.png │ ├── explorerscompass_08.png │ ├── explorerscompass_09.png │ ├── explorerscompass_10.png │ ├── explorerscompass_11.png │ ├── explorerscompass_12.png │ ├── explorerscompass_13.png │ ├── explorerscompass_14.png │ ├── explorerscompass_15.png │ ├── explorerscompass_16.png │ ├── explorerscompass_17.png │ ├── explorerscompass_18.png │ ├── explorerscompass_19.png │ ├── explorerscompass_20.png │ ├── explorerscompass_21.png │ ├── explorerscompass_22.png │ ├── explorerscompass_23.png │ ├── explorerscompass_24.png │ ├── explorerscompass_25.png │ ├── explorerscompass_26.png │ ├── explorerscompass_27.png │ ├── explorerscompass_28.png │ ├── explorerscompass_29.png │ ├── explorerscompass_30.png │ └── explorerscompass_31.png ├── data ├── explorerscompass │ ├── advancement │ │ └── recipes │ │ │ └── explorers_compass.json │ └── recipe │ │ └── explorers_compass.json └── minecraft │ └── tags │ └── items │ └── compasses.json └── pack.mcmeta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | src/generated/**/.cache/cache text eol=lf 5 | src/generated/**/*.json text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Gradle 6 | /.gradle 7 | /build 8 | *.launch 9 | 10 | # ForgeGradle 11 | /run 12 | 13 | # Eclipse 14 | /.settings 15 | /.metadata 16 | /.classpath 17 | /.project 18 | /eclipse 19 | /bin 20 | 21 | # Folder config file 22 | Desktop.ini 23 | 24 | # Recycle Bin used on file shares 25 | $RECYCLE.BIN/ 26 | 27 | # Windows Installer files 28 | *.cab 29 | *.msi 30 | *.msm 31 | *.msp 32 | 33 | # Windows shortcuts 34 | *.lnk 35 | 36 | # OSX 37 | .DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | 41 | # Thumbnails 42 | ._* 43 | 44 | # Files that might appear in the root of a volume 45 | .DocumentRevisions-V100 46 | .fseventsd 47 | .Spotlight-V100 48 | .TemporaryItems 49 | .Trashes 50 | .VolumeIcon.icns 51 | 52 | # Directories potentially created on remote AFP share 53 | .AppleDB 54 | .AppleDesktop 55 | Network Trash Folder 56 | Temporary Items 57 | .apdisk -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Version 3.0.4 2 | #### NeoForge 1.21.5, 1.21.4, 1.21.3 3 | - Updated to NeoForge 1.21.5 4 | - Updated to NeoForge 1.21.4 5 | - Updated to NeoForge 1.21.3 6 | - Added French translations 7 | - Fixed compass also performing offhand item action after opening GUI 8 | 9 | ## Version 2.2.6 10 | #### Fabric 1.21.5, 1.21.4, 1.21.3 11 | - Updated to Fabric 1.21.5 12 | - Updated to Fabric 1.21.4 13 | - Updated to Fabric 1.21.3 14 | - Added French translations 15 | - Fixed compass also performing offhand item action after opening GUI 16 | 17 | ## Version 1.3.9 18 | #### Forge 1.21.5, 1.21.4, 1.21.3 19 | - Updated to Forge 1.21.5 20 | - Updated to Forge 1.21.4 21 | - Updated to Forge 1.21.3 22 | - Added French translations 23 | - Fixed compass also performing offhand item action after opening GUI 24 | 25 | ## Version 3.0.3 26 | #### NeoForge 1.21.1 27 | - Fixed uncraftable Explorer's Compass recipe 28 | 29 | ## Version 3.0.2 30 | #### NeoForge 1.21.1, 1.21 31 | - Updated to NeoForge 1.21.1 32 | - Fixed uncraftable Explorer's Compass recipe 33 | 34 | ## Version 2.2.5 35 | #### Fabric 1.21.1, 1.21 36 | - Updated to Fabric 1.21.1 37 | - Fixed uncraftable Explorer's Compass recipe 38 | 39 | ## Version 1.3.8 40 | #### Forge 1.21.1, 1.21 41 | - Updated to Forge 1.21.1 42 | - Fixed uncraftable Explorer's Compass recipe 43 | 44 | ## Version 3.0.1 45 | #### NeoForge 1.21, 1.20.6, 1.20.5 46 | - Updated to NeoForge 1.21 47 | - Updated to NeoForge 1.20.6 48 | - Updated to NeoForge 1.20.5 49 | - Hid structures with the c:hidden_from_locator_selection from appearing in the compass GUI 50 | 51 | ## Version 2.2.4 52 | #### Fabric 1.21, 1.20.6, 1.20.5 53 | - Updated to Fabric 1.21 54 | - Updated to Fabric 1.20.6 55 | - Updated to Fabric 1.20.5 56 | - Hid structures with the c:hidden_from_locator_selection from appearing in the compass GUI 57 | 58 | ## Version 1.3.7 59 | #### Forge 1.21, 1.20.6 60 | - Updated to Forge 1.21 61 | - Updated to Forge 1.20.6 62 | - Hid structures with the c:hidden_from_locator_selection from appearing in the compass GUI 63 | 64 | ## Version 3.0.0 65 | #### Forge 1.20.4, 1.20.2 66 | - Updated to NeoForge 1.20.4 67 | - Updated to NeoForge 1.20.2 68 | 69 | ## Version 1.3.6 70 | #### Forge 1.20.4, 1.20.2 71 | - Fixed compass HUD info being rendered twice when certain mods are installed 72 | 73 | ## Version 1.3.5 74 | #### Forge 1.20.4, 1.20.2 75 | - Fixed clients not being allowed to connect to servers that did not have Explorer's Compass installed 76 | - Added Portuguese translations 77 | - Added simplified Chinese translations 78 | 79 | ## Version 1.3.4 80 | #### Forge 1.20.4, 1.20.3, 1.20.2 81 | - Updated to Forge 1.20.4 82 | - Updated to Forge 1.20.3 83 | - Fixed clients not being allowed to connect to servers that did not have Explorer's Compass installed 84 | - Fixed some Russian translations 85 | 86 | ## Version 1.3.3 87 | #### Forge 1.20.2, 1.20.1 88 | - Updated to Forge 1.20.2 89 | - Added the compass to the minecraft:compasses tag 90 | - Fixed compass spinning when player's yaw goes from positive to negative or vice versa 91 | - Fixed a server hang and eventual crash that occurred when using the compass to teleport to coordinates with no blocks to stand on 92 | 93 | ## Version 2.2.3 94 | #### Fabric 1.20.4, 1.20.3, 1.20.2, 1.20.1 95 | - Updated to Fabric 1.20.4 96 | - Updated to Fabric 1.20.3 97 | - Updated to Fabric 1.20.2 98 | - Added the compass to the minecraft:compasses tag 99 | - Fixed compass spinning when player's yaw goes from positive to negative or vice versa 100 | - Fixed a server hang and eventual crash that occurred when using the compass to teleport to coordinates with no blocks to stand on 101 | 102 | ## Version 1.3.2 103 | #### Forge 1.20.1, 1.20 104 | - Updated to Forge 1.20.1 105 | - Updated to Forge 1.20 106 | - Fixed a bug which caused the Explorer's Compass recipe to unlock after picking up any item 107 | 108 | ## Version 2.2.2 109 | #### Fabric 1.20.1, 1.20 110 | - Updated to Fabric 1.20.1 111 | - Updated to Fabric 1.20 112 | - Fixed a bug which caused the Explorer's Compass recipe to unlock after picking up any item 113 | 114 | ## Version 1.3.1 115 | #### Forge 1.19.4 116 | - Updated to Forge 1.19.4 117 | - Added functionality to search for structures by source in the compass GUI using the @ prefix 118 | 119 | ## Version 2.2.1 120 | #### Fabric 1.19.4 121 | - Updated to Fabric 1.19.4 122 | - Added functionality to search for structures by source in the compass GUI using the @ prefix 123 | 124 | ## Version 1.3.0 125 | #### Forge 1.19.3, 1.19.2, 1.18.2 126 | - Updated to Forge 1.19.3 127 | - Optimized structure search to significantly reduce the time it takes to find most structures 128 | - Added a scroll bar to the structure list 129 | - Added Spanish translations 130 | 131 | ## Version 2.2.0 132 | #### Fabric 1.19.3, 1.19.2, 1.18.2 133 | - Updated to Fabric 1.19.3 134 | - Optimized structure search to significantly reduce the time it takes to find most structures 135 | - Added a scroll bar to the structure list 136 | - Added Spanish translations 137 | 138 | ## Version 1.2.4 139 | #### Forge 1.19.2, 1.19.1, 1.19 140 | - Updated to Forge 1.19.2 141 | - Updated to Forge 1.19.1 142 | - Fixed a bug in which some chunks were skipped when searching for a structure 143 | 144 | 145 | ## Version 2.1.2 146 | #### Fabric 1.19.2, 1.19.1, 1.19 147 | - Updated to Fabric 1.19.2 148 | - Updated to Fabric 1.19.1 149 | - Fixed a bug in which some chunks were skipped when searching for a structure 150 | 151 | ## Version 1.2.3 152 | #### Forge 1.19, 1.18.2 153 | - Fixed a crash that occurred infrequently upon client initialization 154 | 155 | ## Version 2.1.1 156 | #### Fabric 1.19 157 | - Updated to Fabric 1.19 158 | - Improved structure grouping so that structures will be listed under more specific groups 159 | - Fixed an issue in which clearing the compass state did not cancel the current search 160 | 161 | ## Version 1.2.2 162 | #### Forge 1.19 163 | - Updated to Forge 1.19 164 | - Improved structure grouping so that structures will be listed under more specific groups 165 | - Fixed an issue in which clearing the compass state did not cancel the current search 166 | 167 | ## Version 1.2.1 168 | #### Forge 1.18.2 169 | - Fixed a client crash that occurred after opening the compass GUI on a server 170 | 171 | ## Version 1.2.0 172 | #### Forge 1.18.2 173 | - Updated to Forge 1.18.2 174 | - Added a feature to allow searching for a group of related structures all at once 175 | 176 | ## Version 2.0.3 177 | #### Fabric 1.18.1 178 | - Added Russian translations 179 | - Added Japanese translations 180 | - Added traditional Chinese translations 181 | - Improved teleport functionality to place the player as close to ground level as possible 182 | - Fixed a bug that caused searching for a stronghold to always return not found 183 | - Fixed another crash that occurred infrequently when opening the compass GUI 184 | 185 | 186 | ## Version 1.1.3 187 | #### Forge 1.18.1 188 | - Added Russian translations 189 | - Added Japanese translations 190 | - Added traditional Chinese translations 191 | - Increased the maximum configurable value for samples 192 | - Improved teleport functionality to place the player as close to ground level as possible 193 | - Fixed a bug that caused searching for a stronghold to always return not found 194 | - Fixed another crash that occurred infrequently when opening the compass GUI 195 | 196 | ## Version 2.0.2 197 | #### Fabric 1.18.1, 1.18 198 | - Updated to Fabric 1.18.1 199 | - Updated to Fabric 1.18 200 | 201 | ## Version 1.1.2 202 | #### Forge 1.18.1, 1.18, 1.17.1, 1.16.5 203 | - Updated to Forge 1.18.1 204 | - Updated to Forge 1.18 205 | - Updated to Forge 1.17.1 206 | - Fixed a crash that occurred when searching for a structure that did not generate in the current dimension, but was expected to 207 | - Fixed a crash that occurred infrequently when opening the compass GUI 208 | - Fixed a bug that caused some structures to be listed as generating in incorrect dimensions 209 | - Slightly optimized the syncing of data to the client upon opening the compass GUI 210 | 211 | ## Version 2.0.1 212 | #### Fabric 1.17.1, 1.16.5 213 | - Fixed a crash that occurred when searching for a structure that did not generate in the current dimension, but was expected to 214 | - Fixed a crash that occurred infrequently when opening the compass GUI 215 | - Fixed a bug that caused some structures to be listed as generating in incorrect dimensions 216 | 217 | ## Version 2.0.0 218 | #### Fabric 1.17.1, 1.16.5 219 | - Updated to Fabric 1.17.1 220 | - Updated to Fabric 1.16.5 221 | 222 | ## Version 1.1.1 223 | #### Forge 1.16.5 224 | - Fixed a bug that prevented the Explorer's Compass recipe from being unlocked when one of its ingredients was obtained 225 | 226 | ## Version 1.1.0 227 | #### Forge 1.16.5 228 | - Added a config option to determine whether players can view the coordinates and distance to a located structure on the HUD 229 | - Added information about the dimensions a structure appears in to the compass GUI 230 | - Added a category to sort by dimension in the compass GUI 231 | - Fixed a crash that occurred infrequently while searching for a structure 232 | 233 | ## Version 1.0.0 234 | #### Forge 1.16.5 235 | - Initial release 236 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/LICENSE.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Explorer's Compass 2 | 3 | Explorer's Compass is a Minecraft mod that allows you to search for and locate structures anywhere in the world. It is the sister mod of [Nature's Compass](https://github.com/MattCzyr/NaturesCompass), which allows you to locate biomes. 4 | 5 | ## Download 6 | 7 | Downloads, installation instructions, and more information can be found on [CurseForge](https://www.curseforge.com/minecraft/mc-mods/explorers-compass). 8 | 9 | ## Develop 10 | 11 | ### Setup 12 | 13 | Fork this repository, then clone via SSH: 14 | ``` 15 | git clone git@github.com:/ExplorersCompass.git 16 | ``` 17 | 18 | Or, clone via HTTPS: 19 | ``` 20 | git clone https://github.com//ExplorersCompass.git 21 | ``` 22 | 23 | 2. In the root of the repository, run: 24 | ``` 25 | gradlew eclipse 26 | ``` 27 | 28 | Or, if you plan to use IntelliJ, run: 29 | ``` 30 | gradlew idea 31 | ``` 32 | 33 | 3. Run: 34 | ``` 35 | gradlew genEclipseRuns 36 | ``` 37 | 38 | Or, to use IntelliJ, run: 39 | ``` 40 | gradlew genIntellijRuns 41 | ``` 42 | 43 | 4. Open the project's parent directory in your IDE and import the project as an existing Gradle project. 44 | 45 | ### Build 46 | 47 | To build the project, configure `build.gradle` then run: 48 | ``` 49 | gradlew build 50 | ``` 51 | 52 | This will build a jar file in `build/libs`. 53 | 54 | ## License 55 | 56 | This mod is available under the [Creative Commons Attribution-NonCommercial ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode). -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'eclipse' 3 | id 'idea' 4 | id 'maven-publish' 5 | id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' 6 | } 7 | 8 | version = mod_version 9 | group = mod_group_id 10 | 11 | base { 12 | archivesName = mod_id 13 | } 14 | 15 | // Mojang ships Java 21 to end users in 1.20.5+, so your mod should target Java 21. 16 | java.toolchain.languageVersion = JavaLanguageVersion.of(21) 17 | 18 | println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" 19 | minecraft { 20 | // The mappings can be changed at any time and must be in the following format. 21 | // Channel: Version: 22 | // official MCVersion Official field/method names from Mojang mapping files 23 | // parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official 24 | // 25 | // You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. 26 | // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md 27 | // 28 | // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge 29 | // Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started 30 | // 31 | // Use non-default mappings at your own risk. They may not always work. 32 | // Simply re-run your setup task after changing the mappings to update your workspace. 33 | mappings channel: mapping_channel, version: mapping_version 34 | 35 | // Tell FG to not automtically create the reobf tasks, as we now use Official mappings at runtime, If you don't use them at dev time then you'll have to fix your reobf yourself. 36 | reobf = false 37 | 38 | // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game. 39 | // In most cases, it is not necessary to enable. 40 | // enableEclipsePrepareRuns = true 41 | // enableIdeaPrepareRuns = true 42 | 43 | // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game. 44 | // It is REQUIRED to be set to true for this template to function. 45 | // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html 46 | copyIdeResources = true 47 | 48 | // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations. 49 | // The folder name can be set on a run configuration using the "folderName" property. 50 | // By default, the folder name of a run configuration is the name of the Gradle project containing it. 51 | // generateRunFolders = true 52 | 53 | // This property enables access transformers for use in development. 54 | // They will be applied to the Minecraft artifact. 55 | // The access transformer file can be anywhere in the project. 56 | // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. 57 | // This default location is a best practice to automatically put the file in the right place in the final jar. 58 | // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. 59 | // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') 60 | 61 | // Default run configurations. 62 | // These can be tweaked, removed, or duplicated as needed. 63 | runs { 64 | // applies to all the run configs below 65 | configureEach { 66 | workingDirectory project.file('run') 67 | 68 | // Recommended logging data for a userdev environment 69 | // The markers can be added/remove as needed separated by commas. 70 | // "SCAN": For mods scan. 71 | // "REGISTRIES": For firing of registry events. 72 | // "REGISTRYDUMP": For getting the contents of all registries. 73 | property 'forge.logging.markers', 'REGISTRIES' 74 | 75 | // Recommended logging level for the console 76 | // You can set various levels here. 77 | // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels 78 | property 'forge.logging.console.level', 'debug' 79 | } 80 | 81 | client { 82 | // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. 83 | property 'forge.enabledGameTestNamespaces', mod_id 84 | } 85 | 86 | server { 87 | property 'forge.enabledGameTestNamespaces', mod_id 88 | args '--nogui' 89 | } 90 | 91 | // This run config launches GameTestServer and runs all registered gametests, then exits. 92 | // By default, the server will crash when no gametests are provided. 93 | // The gametest system is also enabled by default for other run configs under the /test command. 94 | gameTestServer { 95 | property 'forge.enabledGameTestNamespaces', mod_id 96 | } 97 | 98 | data { 99 | // example of overriding the workingDirectory set in configureEach above 100 | workingDirectory project.file('run-data') 101 | 102 | // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. 103 | args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') 104 | } 105 | } 106 | } 107 | 108 | // Include resources generated by data generators. 109 | sourceSets.main.resources { srcDir 'src/generated/resources' } 110 | 111 | repositories { 112 | // Put repositories for dependencies here 113 | // ForgeGradle automatically adds the Forge maven and Maven Central for you 114 | 115 | // If you have mod jar dependencies in ./libs, you can declare them as a repository like so. 116 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver 117 | // flatDir { 118 | // dir 'libs' 119 | // } 120 | } 121 | 122 | dependencies { 123 | // Specify the version of Minecraft to use. 124 | // Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact. 125 | // The "userdev" classifier will be requested and setup by ForgeGradle. 126 | // If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"], 127 | // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. 128 | minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" 129 | 130 | // Example mod dependency with JEI 131 | // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime 132 | // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" 133 | // compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}" 134 | // runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}" 135 | 136 | // Example mod dependency using a mod jar from ./libs with a flat dir repository 137 | // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar 138 | // The group id is ignored when searching -- in this case, it is "blank" 139 | // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") 140 | 141 | // For more info: 142 | // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html 143 | // http://www.gradle.org/docs/current/userguide/dependency_management.html 144 | } 145 | 146 | // This block of code expands all declared replace properties in the specified resource targets. 147 | // A missing property will result in an error. Properties are expanded using ${} Groovy notation. 148 | // When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. 149 | // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html 150 | tasks.named('processResources', ProcessResources).configure { 151 | var replaceProperties = [ 152 | minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range, 153 | forge_version: forge_version, forge_version_range: forge_version_range, 154 | loader_version_range: loader_version_range, 155 | mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, 156 | mod_authors: mod_authors, mod_description: mod_description, 157 | ] 158 | inputs.properties replaceProperties 159 | 160 | filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { 161 | expand replaceProperties + [project: project] 162 | } 163 | } 164 | 165 | // Example for how to get properties into the manifest for reading at runtime. 166 | tasks.named('jar', Jar).configure { 167 | manifest { 168 | attributes([ 169 | 'Specification-Title' : mod_id, 170 | 'Specification-Vendor' : mod_authors, 171 | 'Specification-Version' : '1', // We are version 1 of ourselves 172 | 'Implementation-Title' : project.name, 173 | 'Implementation-Version' : project.jar.archiveVersion, 174 | 'Implementation-Vendor' : mod_authors 175 | ]) 176 | } 177 | } 178 | 179 | // Example configuration to allow publishing using the maven-publish plugin 180 | publishing { 181 | publications { 182 | register('mavenJava', MavenPublication) { 183 | artifact jar 184 | } 185 | } 186 | repositories { 187 | maven { 188 | url "file://${project.projectDir}/mcmodsrepo" 189 | } 190 | } 191 | } 192 | 193 | tasks.withType(JavaCompile).configureEach { 194 | options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation 195 | } 196 | 197 | // IntelliJ no longer downloads javadocs and sources by default. 198 | // This tells Gradle to force IDEA to do it. 199 | idea.module { downloadJavadoc = downloadSources = true } 200 | 201 | eclipse { 202 | // Run everytime eclipse builds the code 203 | //autoBuildTasks genEclipseRuns 204 | // Run when importing the project 205 | synchronizationTasks 'genEclipseRuns' 206 | } 207 | 208 | // Merge the resources and classes into the same directory. 209 | // This is done because java expects modules to be in a single directory. 210 | // And if we have it in multiple we have to do performance intensive hacks like having the UnionFileSystem 211 | // This will eventually be migrated to ForgeGradle so modders don't need to manually do it. But that is later. 212 | sourceSets.each { 213 | def dir = layout.buildDirectory.dir("sourcesSets/$it.name") 214 | it.output.resourcesDir = dir 215 | it.java.destinationDirectory = dir 216 | } 217 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. 2 | # This is required to provide enough memory for the Minecraft decompilation process. 3 | org.gradle.jvmargs=-Xmx3G 4 | org.gradle.daemon=false 5 | 6 | 7 | ## Environment Properties 8 | 9 | # The Minecraft version must agree with the Forge version to get a valid artifact 10 | minecraft_version=1.21.5 11 | # The Minecraft version range can use any release version of Minecraft as bounds. 12 | # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly 13 | # as they do not follow standard versioning conventions. 14 | minecraft_version_range=[1.21.5,1.22) 15 | # The Forge version must agree with the Minecraft version to get a valid artifact 16 | forge_version=55.0.3 17 | # The Forge version range can use any version of Forge as bounds or match the loader version range 18 | forge_version_range=[0,) 19 | # The loader version range can only use the major version of Forge/FML as bounds 20 | loader_version_range=[0,) 21 | # The mapping channel to use for mappings. 22 | # The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. 23 | # Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. 24 | # 25 | # | Channel | Version | | 26 | # |-----------|----------------------|--------------------------------------------------------------------------------| 27 | # | official | MCVersion | Official field/method names from Mojang mapping files | 28 | # | parchment | YYYY.MM.DD-MCVersion | Open community-sourced parameter names and javadocs layered on top of official | 29 | # 30 | # You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. 31 | # See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md 32 | # 33 | # Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge. 34 | # Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started 35 | mapping_channel=official 36 | # The mapping version to query from the mapping channel. 37 | # This must match the format required by the mapping channel. 38 | mapping_version=1.21.5 39 | 40 | 41 | ## Mod Properties 42 | 43 | # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} 44 | # Must match the String constant located in the main mod class annotated with @Mod. 45 | mod_id=explorerscompass 46 | # The human-readable display name for the mod. 47 | mod_name=Explorer's Compass 48 | # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. 49 | mod_license=CC BY-NC-SA 4.0 50 | # The mod version. See https://semver.org/ 51 | mod_version=1.21.5-1.3.9-forge 52 | # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. 53 | # This should match the base package used for the mod sources. 54 | # See https://maven.apache.org/guides/mini/guide-naming-conventions.html 55 | mod_group_id=com.chaosthedude.explorerscompass 56 | # The authors of the mod. This is a simple text string that is used for display purposes in the mod list. 57 | mod_authors=ChaosTheDude 58 | # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. 59 | mod_description=Search for and locate structures anywhere in the world. -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/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 8 | -------------------------------------------------------------------------------- /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 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /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. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 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. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 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 | gradlePluginPortal() 4 | maven { 5 | name = 'MinecraftForge' 6 | url = 'https://maven.minecraftforge.net/' 7 | } 8 | } 9 | } 10 | 11 | plugins { 12 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' 13 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/ExplorersCompass.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | 11 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 12 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 13 | import com.chaosthedude.explorerscompass.network.CompassSearchPacket; 14 | import com.chaosthedude.explorerscompass.network.SyncPacket; 15 | import com.chaosthedude.explorerscompass.network.TeleportPacket; 16 | import com.google.common.collect.ArrayListMultimap; 17 | import com.google.common.collect.ListMultimap; 18 | import com.mojang.serialization.Codec; 19 | 20 | import net.minecraft.core.component.DataComponentType; 21 | import net.minecraft.network.codec.ByteBufCodecs; 22 | import net.minecraft.resources.ResourceLocation; 23 | import net.minecraft.world.item.CreativeModeTabs; 24 | import net.minecraft.world.item.ItemStack; 25 | import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; 26 | import net.minecraftforge.fml.ModLoadingContext; 27 | import net.minecraftforge.fml.common.Mod; 28 | import net.minecraftforge.fml.config.ModConfig; 29 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 30 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 31 | import net.minecraftforge.network.Channel; 32 | import net.minecraftforge.network.ChannelBuilder; 33 | import net.minecraftforge.network.SimpleChannel; 34 | 35 | @Mod(ExplorersCompass.MODID) 36 | public class ExplorersCompass { 37 | 38 | public static final String MODID = "explorerscompass"; 39 | 40 | public static final Logger LOGGER = LogManager.getLogger(MODID); 41 | 42 | public static SimpleChannel network; 43 | public static ExplorersCompassItem explorersCompass; 44 | 45 | public static final DataComponentType STRUCTURE_ID_COMPONENT = DataComponentType.builder().persistent(Codec.STRING).networkSynchronized(ByteBufCodecs.STRING_UTF8).build(); 46 | public static final DataComponentType COMPASS_STATE_COMPONENT = DataComponentType.builder().persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT).build(); 47 | public static final DataComponentType FOUND_X_COMPONENT = DataComponentType.builder().persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT).build(); 48 | public static final DataComponentType FOUND_Z_COMPONENT = DataComponentType.builder().persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT).build(); 49 | public static final DataComponentType SEARCH_RADIUS_COMPONENT = DataComponentType.builder().persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT).build(); 50 | public static final DataComponentType SAMPLES_COMPONENT = DataComponentType.builder().persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT).build(); 51 | public static final DataComponentType DISPLAY_COORDS_COMPONENT = DataComponentType.builder().persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL).build(); 52 | 53 | public static boolean canTeleport; 54 | public static List allowedStructureKeys; 55 | public static ListMultimap dimensionKeysForAllowedStructureKeys; 56 | public static Map structureKeysToTypeKeys; 57 | public static ListMultimap typeKeysToStructureKeys; 58 | 59 | public ExplorersCompass() { 60 | FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup); 61 | FMLJavaModLoadingContext.get().getModEventBus().addListener(this::buildCreativeTabContents); 62 | 63 | ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ConfigHandler.GENERAL_SPEC); 64 | ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ConfigHandler.CLIENT_SPEC); 65 | } 66 | 67 | private void commonSetup(FMLCommonSetupEvent event) { 68 | network = ChannelBuilder.named(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, ExplorersCompass.MODID)).networkProtocolVersion(1).optionalClient().clientAcceptedVersions(Channel.VersionTest.exact(1)).simpleChannel(); 69 | 70 | // Server packets 71 | network.messageBuilder(CompassSearchPacket.class).encoder(CompassSearchPacket::toBytes).decoder(CompassSearchPacket::new).consumerMainThread(CompassSearchPacket::handle).add(); 72 | network.messageBuilder(TeleportPacket.class).encoder(TeleportPacket::toBytes).decoder(TeleportPacket::new).consumerMainThread(TeleportPacket::handle).add(); 73 | 74 | // Client packet 75 | network.messageBuilder(SyncPacket.class).encoder(SyncPacket::toBytes).decoder(SyncPacket::new).consumerMainThread(SyncPacket::handle).add(); 76 | 77 | allowedStructureKeys = new ArrayList(); 78 | dimensionKeysForAllowedStructureKeys = ArrayListMultimap.create(); 79 | structureKeysToTypeKeys = new HashMap(); 80 | typeKeysToStructureKeys = ArrayListMultimap.create(); 81 | } 82 | 83 | private void buildCreativeTabContents(BuildCreativeModeTabContentsEvent event) { 84 | if (event.getTabKey() == CreativeModeTabs.TOOLS_AND_UTILITIES) { 85 | event.accept(new ItemStack(explorersCompass)); 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/client/ExplorersCompassAngle.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.client; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | import com.mojang.serialization.MapCodec; 6 | 7 | import net.minecraft.client.multiplayer.ClientLevel; 8 | import net.minecraft.client.renderer.item.properties.numeric.RangeSelectItemModelProperty; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.minecraft.world.item.ItemStack; 11 | import net.minecraftforge.api.distmarker.Dist; 12 | import net.minecraftforge.api.distmarker.OnlyIn; 13 | 14 | @OnlyIn(Dist.CLIENT) 15 | public class ExplorersCompassAngle implements RangeSelectItemModelProperty { 16 | 17 | public static final MapCodec MAP_CODEC = MapCodec.unit(new ExplorersCompassAngle()); 18 | private final ExplorersCompassAngleState state; 19 | 20 | public ExplorersCompassAngle() { 21 | this(new ExplorersCompassAngleState()); 22 | } 23 | 24 | private ExplorersCompassAngle(ExplorersCompassAngleState state) { 25 | this.state = state; 26 | } 27 | 28 | @Override 29 | public float get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) { 30 | return state.get(stack, level, entity, seed); 31 | } 32 | 33 | @Override 34 | public MapCodec type() { 35 | return MAP_CODEC; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/client/ExplorersCompassAngleState.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.client; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | import com.chaosthedude.explorerscompass.ExplorersCompass; 6 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 7 | import com.chaosthedude.explorerscompass.util.CompassState; 8 | 9 | import net.minecraft.client.multiplayer.ClientLevel; 10 | import net.minecraft.client.renderer.item.properties.numeric.NeedleDirectionHelper; 11 | import net.minecraft.core.BlockPos; 12 | import net.minecraft.core.GlobalPos; 13 | import net.minecraft.util.Mth; 14 | import net.minecraft.util.RandomSource; 15 | import net.minecraft.world.entity.Entity; 16 | import net.minecraft.world.entity.player.Player; 17 | import net.minecraft.world.item.ItemStack; 18 | import net.minecraft.world.phys.Vec3; 19 | import net.minecraftforge.api.distmarker.Dist; 20 | import net.minecraftforge.api.distmarker.OnlyIn; 21 | 22 | @OnlyIn(Dist.CLIENT) 23 | public class ExplorersCompassAngleState extends NeedleDirectionHelper { 24 | 25 | private final NeedleDirectionHelper.Wobbler wobbler; 26 | private final RandomSource random = RandomSource.create(); 27 | 28 | public ExplorersCompassAngleState() { 29 | super(true); 30 | wobbler = newWobbler(0.8F); 31 | } 32 | 33 | @Override 34 | protected float calculate(ItemStack stack, ClientLevel level, int seed, Entity entity) { 35 | GlobalPos pos = new GlobalPos(level.dimension(), level.getSharedSpawnPos()); 36 | if (stack.getItem() == ExplorersCompass.explorersCompass) { 37 | ExplorersCompassItem compassItem = (ExplorersCompassItem) stack.getItem(); 38 | if (compassItem.getState(stack) == CompassState.FOUND) { 39 | pos = new GlobalPos(level.dimension(), new BlockPos(compassItem.getFoundStructureX(stack), 0, compassItem.getFoundStructureZ(stack))); 40 | } 41 | } 42 | long gameTime = level.getGameTime(); 43 | return !isValidCompassTargetPos(entity, pos) ? getRandomlySpinningRotation(seed, gameTime) : getRotationTowardsCompassTarget(entity, gameTime, pos.pos()); 44 | } 45 | 46 | private float getRandomlySpinningRotation(int seed, long gameTime) { 47 | if (wobbler.shouldUpdate(gameTime)) { 48 | wobbler.update(gameTime, random.nextFloat()); 49 | } 50 | 51 | float f = wobbler.rotation() + (float) hash(seed) / 2.1474836E9F; 52 | return Mth.positiveModulo(f, 1.0F); 53 | } 54 | 55 | private float getRotationTowardsCompassTarget(Entity entity, long gameTime, BlockPos pos) { 56 | float f = (float) getAngleFromEntityToPos(entity, pos); 57 | float f1 = getWrappedVisualRotationY(entity); 58 | if (entity instanceof Player player && player.isLocalPlayer() && player.level().tickRateManager().runsNormally()) { 59 | if (wobbler.shouldUpdate(gameTime)) { 60 | wobbler.update(gameTime, 0.5F - (f1 - 0.25F)); 61 | } 62 | 63 | float f3 = f + wobbler.rotation(); 64 | return Mth.positiveModulo(f3, 1.0F); 65 | } 66 | 67 | float f2 = 0.5F - (f1 - 0.25F - f); 68 | return Mth.positiveModulo(f2, 1.0F); 69 | } 70 | 71 | private static boolean isValidCompassTargetPos(Entity entity, @Nullable GlobalPos pos) { 72 | return pos != null && pos.dimension() == entity.level().dimension() && !(pos.pos().distToCenterSqr(entity.position()) < 1.0E-5F); 73 | } 74 | 75 | private static double getAngleFromEntityToPos(Entity entity, BlockPos pos) { 76 | Vec3 vec3 = Vec3.atCenterOf(pos); 77 | return Math.atan2(vec3.z() - entity.getZ(), vec3.x() - entity.getX()) / (float) (Math.PI * 2); 78 | } 79 | 80 | private static float getWrappedVisualRotationY(Entity entity) { 81 | return Mth.positiveModulo(entity.getVisualRotationYInDegrees() / 360.0F, 1.0F); 82 | } 83 | 84 | private static int hash(int seed) { 85 | return seed * 1327217883; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/client/ExplorersCompassClient.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.client; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import com.chaosthedude.explorerscompass.ExplorersCompass; 6 | import com.mojang.serialization.MapCodec; 7 | 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.gui.Gui; 10 | import net.minecraft.client.gui.LayeredDraw; 11 | import net.minecraft.client.renderer.item.properties.numeric.RangeSelectItemModelProperties; 12 | import net.minecraft.client.renderer.item.properties.numeric.RangeSelectItemModelProperty; 13 | import net.minecraft.resources.ResourceLocation; 14 | import net.minecraft.util.ExtraCodecs; 15 | import net.minecraftforge.api.distmarker.Dist; 16 | import net.minecraftforge.eventbus.api.SubscribeEvent; 17 | import net.minecraftforge.fml.common.Mod; 18 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 19 | import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; 20 | import net.minecraftforge.fml.util.ObfuscationReflectionHelper; 21 | 22 | @Mod.EventBusSubscriber(modid = ExplorersCompass.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) 23 | public class ExplorersCompassClient { 24 | 25 | private static final Field LAYERS = ObfuscationReflectionHelper.findField(Gui.class, "layers"); 26 | private static final Field ID_MAPPER = ObfuscationReflectionHelper.findField(RangeSelectItemModelProperties.class, "ID_MAPPER"); 27 | 28 | @SubscribeEvent 29 | public static void clientInit(FMLClientSetupEvent event) { 30 | event.enqueueWork(() -> { 31 | Minecraft mc = Minecraft.getInstance(); 32 | try { 33 | LayeredDraw layers = (LayeredDraw) LAYERS.get(mc.gui); 34 | layers.add(new ExplorersCompassOverlay()); 35 | } catch (IllegalAccessException e) { 36 | ExplorersCompass.LOGGER.error("Failed to add Explorer's Compass GUI layer"); 37 | throw new RuntimeException("Failed to add layer"); 38 | } 39 | }); 40 | } 41 | 42 | @SubscribeEvent 43 | public static void constructMod(FMLConstructModEvent event) { 44 | event.enqueueWork(() -> { 45 | try { 46 | ExtraCodecs.LateBoundIdMapper> idMapper = (ExtraCodecs.LateBoundIdMapper>) ID_MAPPER.get(null); 47 | idMapper.put(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "angle"), ExplorersCompassAngle.MAP_CODEC); 48 | } catch (IllegalAccessException e) { 49 | ExplorersCompass.LOGGER.error("Failed to register Explorer's Compass model property"); 50 | throw new RuntimeException("Failed to register model property"); 51 | } 52 | }); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/client/ExplorersCompassOverlay.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.client; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 5 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 6 | import com.chaosthedude.explorerscompass.util.CompassState; 7 | import com.chaosthedude.explorerscompass.util.ItemUtils; 8 | import com.chaosthedude.explorerscompass.util.RenderUtils; 9 | import com.chaosthedude.explorerscompass.util.StructureUtils; 10 | 11 | import net.minecraft.client.DeltaTracker; 12 | import net.minecraft.client.Minecraft; 13 | import net.minecraft.client.gui.GuiGraphics; 14 | import net.minecraft.client.gui.LayeredDraw.Layer; 15 | import net.minecraft.client.gui.screens.ChatScreen; 16 | import net.minecraft.client.resources.language.I18n; 17 | import net.minecraft.world.entity.player.Player; 18 | import net.minecraft.world.item.ItemStack; 19 | import net.minecraftforge.api.distmarker.Dist; 20 | import net.minecraftforge.api.distmarker.OnlyIn; 21 | 22 | @OnlyIn(Dist.CLIENT) 23 | public class ExplorersCompassOverlay implements Layer { 24 | 25 | public static final Minecraft mc = Minecraft.getInstance(); 26 | 27 | @Override 28 | public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { 29 | if (mc.player != null && mc.level != null && !mc.options.hideGui && !mc.getDebugOverlay().showDebugScreen() && (mc.screen == null || (ConfigHandler.CLIENT.displayWithChatOpen.get() && mc.screen instanceof ChatScreen))) { 30 | final Player player = mc.player; 31 | final ItemStack stack = ItemUtils.getHeldItem(player, ExplorersCompass.explorersCompass); 32 | if (stack != null && stack.getItem() instanceof ExplorersCompassItem) { 33 | final ExplorersCompassItem compass = (ExplorersCompassItem) stack.getItem(); 34 | if (compass.getState(stack) == CompassState.SEARCHING) { 35 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.status"), 5, 5, 0xFFFFFF, 0); 36 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.searching"), 5, 5, 0xAAAAAA, 1); 37 | 38 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.structure"), 5, 5, 0xFFFFFF, 3); 39 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, StructureUtils.getPrettyStructureName(compass.getStructureKey(stack)), 5, 5, 0xAAAAAA, 4); 40 | 41 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.radius"), 5, 5, 0xFFFFFF, 6); 42 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, String.valueOf(compass.getSearchRadius(stack)), 5, 5, 0xAAAAAA, 7); 43 | } else if (compass.getState(stack) == CompassState.FOUND) { 44 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.status"), 5, 5, 0xFFFFFF, 0); 45 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.found"), 5, 5, 0xAAAAAA, 1); 46 | 47 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.structure"), 5, 5, 0xFFFFFF, 3); 48 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, StructureUtils.getPrettyStructureName(compass.getStructureKey(stack)), 5, 5, 0xAAAAAA, 4); 49 | 50 | if (compass.shouldDisplayCoordinates(stack)) { 51 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.coordinates"), 5, 5, 0xFFFFFF, 6); 52 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, compass.getFoundStructureX(stack) + ", " + compass.getFoundStructureZ(stack), 5, 5, 0xAAAAAA, 7); 53 | 54 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.distance"), 5, 5, 0xFFFFFF, 9); 55 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, String.valueOf(StructureUtils.getHorizontalDistanceToLocation(player, compass.getFoundStructureX(stack), compass.getFoundStructureZ(stack))), 5, 5, 0xAAAAAA, 10); 56 | } 57 | } else if (compass.getState(stack) == CompassState.NOT_FOUND) { 58 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.status"), 5, 5, 0xFFFFFF, 0); 59 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.notFound"), 5, 5, 0xAAAAAA, 1); 60 | 61 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.structure"), 5, 5, 0xFFFFFF, 3); 62 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, StructureUtils.getPrettyStructureName(compass.getStructureKey(stack)), 5, 5, 0xAAAAAA, 4); 63 | 64 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, I18n.get("string.explorerscompass.radius"), 5, 5, 0xFFFFFF, 6); 65 | RenderUtils.drawConfiguredStringOnHUD(guiGraphics, String.valueOf(compass.getSearchRadius(stack)), 5, 5, 0xAAAAAA, 7); 66 | } 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/client/OverlaySide.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.client; 2 | 3 | public enum OverlaySide { 4 | 5 | LEFT, RIGHT; 6 | 7 | public static OverlaySide fromString(String str) { 8 | if (str.equals("RIGHT")) { 9 | return RIGHT; 10 | } 11 | return LEFT; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/config/ConfigHandler.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.config; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import com.chaosthedude.explorerscompass.client.OverlaySide; 8 | 9 | import net.minecraftforge.common.ForgeConfigSpec; 10 | 11 | public class ConfigHandler { 12 | 13 | private static final ForgeConfigSpec.Builder GENERAL_BUILDER = new ForgeConfigSpec.Builder(); 14 | private static final ForgeConfigSpec.Builder CLIENT_BUILDER = new ForgeConfigSpec.Builder(); 15 | 16 | public static final General GENERAL = new General(GENERAL_BUILDER); 17 | public static final Client CLIENT = new Client(CLIENT_BUILDER); 18 | 19 | public static final ForgeConfigSpec GENERAL_SPEC = GENERAL_BUILDER.build(); 20 | public static final ForgeConfigSpec CLIENT_SPEC = CLIENT_BUILDER.build(); 21 | 22 | public static class General { 23 | public final ForgeConfigSpec.BooleanValue allowTeleport; 24 | public final ForgeConfigSpec.BooleanValue displayCoordinates; 25 | public final ForgeConfigSpec.IntValue maxRadius; 26 | public final ForgeConfigSpec.ConfigValue> structureBlacklist; 27 | public final ForgeConfigSpec.IntValue maxSamples; 28 | 29 | General(ForgeConfigSpec.Builder builder) { 30 | String desc; 31 | builder.push("General"); 32 | 33 | desc = "Allows a player to teleport to a located structure when in creative mode, opped, or in cheat mode."; 34 | allowTeleport = builder.comment(desc).define("allowTeleport", true); 35 | 36 | desc = "Allows players to view the precise coordinates and distance of a located structure on the HUD, rather than relying on the direction the compass is pointing."; 37 | displayCoordinates = builder.comment(desc).define("displayCoordinates", true); 38 | 39 | desc = "The maximum radius that will be searched for a structure. Raising this value will increase search accuracy but will potentially make the process more resource intensive."; 40 | maxRadius = builder.comment(desc).defineInRange("maxRadius", 10000, 0, 1000000); 41 | 42 | desc = "A list of structures that the compass will not display in the GUI and will not be able to search for. Wildcard character * can be used to match any number of characters, and ? can be used to match one character. Ex: [\"minecraft:stronghold\", \"minecraft:endcity\", \"minecraft:*village*\"]"; 43 | structureBlacklist = builder.comment(desc).define("structureBlacklist", new ArrayList()); 44 | 45 | desc = "The maximum number of samples to be taken when searching for a structure."; 46 | maxSamples = builder.comment(desc).defineInRange("maxSamples", 100000, 0, 100000000); 47 | 48 | builder.pop(); 49 | } 50 | } 51 | 52 | public static class Client { 53 | public final ForgeConfigSpec.BooleanValue displayWithChatOpen; 54 | public final ForgeConfigSpec.BooleanValue translateStructureNames; 55 | public final ForgeConfigSpec.EnumValue overlaySide; 56 | public final ForgeConfigSpec.IntValue overlayLineOffset; 57 | 58 | Client(ForgeConfigSpec.Builder builder) { 59 | String desc; 60 | builder.push("Client"); 61 | 62 | desc = "Displays Explorer's Compass information on the HUD even while chat is open."; 63 | displayWithChatOpen = builder.comment(desc).define("displayWithChatOpen", true); 64 | 65 | desc = "Attempts to translate structure names before fixing the unlocalized names. Translations may not be available for all structures."; 66 | translateStructureNames = builder.comment(desc).define("translateStructureNames", true); 67 | 68 | desc = "The line offset for information rendered on the HUD."; 69 | overlayLineOffset = builder.comment(desc).defineInRange("overlayLineOffset", 1, 0, 50); 70 | 71 | desc = "The side for information rendered on the HUD. Ex: LEFT, RIGHT"; 72 | overlaySide = builder.comment(desc).defineEnum("overlaySide", OverlaySide.LEFT); 73 | 74 | builder.pop(); 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/ExplorersCompassScreen.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.chaosthedude.explorerscompass.ExplorersCompass; 8 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 9 | import com.chaosthedude.explorerscompass.network.CompassSearchPacket; 10 | import com.chaosthedude.explorerscompass.network.TeleportPacket; 11 | import com.chaosthedude.explorerscompass.sorting.ISorting; 12 | import com.chaosthedude.explorerscompass.sorting.NameSorting; 13 | import com.chaosthedude.explorerscompass.util.CompassState; 14 | import com.chaosthedude.explorerscompass.util.StructureUtils; 15 | 16 | import net.minecraft.client.gui.GuiGraphics; 17 | import net.minecraft.client.gui.components.Button; 18 | import net.minecraft.client.gui.screens.Screen; 19 | import net.minecraft.network.chat.Component; 20 | import net.minecraft.resources.ResourceLocation; 21 | import net.minecraft.world.entity.player.Player; 22 | import net.minecraft.world.item.ItemStack; 23 | import net.minecraft.world.level.Level; 24 | import net.minecraftforge.api.distmarker.Dist; 25 | import net.minecraftforge.api.distmarker.OnlyIn; 26 | import net.minecraftforge.network.PacketDistributor; 27 | 28 | @OnlyIn(Dist.CLIENT) 29 | public class ExplorersCompassScreen extends Screen { 30 | 31 | private Level level; 32 | private Player player; 33 | private List allowedStructureKeys; 34 | private List structureKeysMatchingSearch; 35 | private ItemStack stack; 36 | private ExplorersCompassItem explorersCompass; 37 | private Button searchButton; 38 | private Button searchGroupButton; 39 | private Button sortByButton; 40 | private Button teleportButton; 41 | private Button cancelButton; 42 | private TransparentTextField searchTextField; 43 | private StructureSearchList selectionList; 44 | private ISorting sortingCategory; 45 | 46 | public ExplorersCompassScreen(Level level, Player player, ItemStack stack, ExplorersCompassItem explorersCompass, List allowedStructureKeys) { 47 | super(Component.translatable("string.explorerscompass.selectStructure")); 48 | this.level = level; 49 | this.player = player; 50 | this.stack = stack; 51 | this.explorersCompass = explorersCompass; 52 | 53 | this.allowedStructureKeys = new ArrayList(allowedStructureKeys); 54 | structureKeysMatchingSearch = new ArrayList(this.allowedStructureKeys); 55 | sortingCategory = new NameSorting(); 56 | } 57 | 58 | @Override 59 | public boolean mouseScrolled(double par1, double par2, double par3, double par4) { 60 | return selectionList.mouseScrolled(par1, par2, par3, par4); 61 | } 62 | 63 | @Override 64 | protected void init() { 65 | setupWidgets(); 66 | } 67 | 68 | @Override 69 | public void tick() { 70 | teleportButton.active = explorersCompass.getState(stack) == CompassState.FOUND; 71 | 72 | // Check if the allowed structure list has synced 73 | if (allowedStructureKeys.size() != ExplorersCompass.allowedStructureKeys.size()) { 74 | removeWidget(selectionList); 75 | allowedStructureKeys = new ArrayList(ExplorersCompass.allowedStructureKeys); 76 | structureKeysMatchingSearch = new ArrayList(allowedStructureKeys); 77 | selectionList = new StructureSearchList(this, minecraft, width + 110, height - 40, 40, 45); 78 | addRenderableWidget(selectionList); 79 | } 80 | } 81 | 82 | @Override 83 | public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 84 | super.render(guiGraphics, mouseX, mouseY, partialTicks); 85 | guiGraphics.drawCenteredString(font, title, 65, 15, 0xffffff); 86 | } 87 | 88 | @Override 89 | public boolean keyPressed(int par1, int par2, int par3) { 90 | boolean ret = super.keyPressed(par1, par2, par3); 91 | if (searchTextField.isFocused()) { 92 | processSearchTerm(); 93 | return true; 94 | } 95 | return ret; 96 | } 97 | 98 | @Override 99 | public boolean charTyped(char typedChar, int keyCode) { 100 | boolean ret = super.charTyped(typedChar, keyCode); 101 | if (searchTextField.isFocused()) { 102 | processSearchTerm(); 103 | return true; 104 | } 105 | return ret; 106 | } 107 | 108 | public void selectStructure(StructureSearchEntry entry) { 109 | boolean enable = entry != null; 110 | searchButton.active = enable; 111 | searchGroupButton.active = enable; 112 | } 113 | 114 | public void searchForStructure(ResourceLocation key) { 115 | ExplorersCompass.network.send(new CompassSearchPacket(key, List.of(key), player.blockPosition()), PacketDistributor.SERVER.noArg()); 116 | minecraft.setScreen(null); 117 | } 118 | 119 | public void searchForGroup(ResourceLocation key) { 120 | ExplorersCompass.network.send(new CompassSearchPacket(key, ExplorersCompass.typeKeysToStructureKeys.get(key), player.blockPosition()), PacketDistributor.SERVER.noArg()); 121 | minecraft.setScreen(null); 122 | } 123 | 124 | public void teleport() { 125 | ExplorersCompass.network.send(new TeleportPacket(), PacketDistributor.SERVER.noArg()); 126 | minecraft.setScreen(null); 127 | } 128 | 129 | public void processSearchTerm() { 130 | structureKeysMatchingSearch = new ArrayList(); 131 | String searchTerm = searchTextField.getValue().toLowerCase(); 132 | for (ResourceLocation key : allowedStructureKeys) { 133 | if (searchTerm.startsWith("@")) { 134 | if (StructureUtils.getPrettyStructureSource(key).toLowerCase().contains(searchTerm.substring(1))) { 135 | structureKeysMatchingSearch.add(key); 136 | } 137 | } else if (StructureUtils.getPrettyStructureName(key).toLowerCase().contains(searchTerm)) { 138 | structureKeysMatchingSearch.add(key); 139 | } 140 | } 141 | selectionList.refreshList(); 142 | } 143 | 144 | public List sortStructures() { 145 | final List structures = structureKeysMatchingSearch; 146 | Collections.sort(structures, new NameSorting()); 147 | Collections.sort(structures, sortingCategory); 148 | return structures; 149 | } 150 | 151 | private void setupWidgets() { 152 | clearWidgets(); 153 | searchButton = addRenderableWidget(new TransparentButton(10, 40, 110, 20, Component.translatable("string.explorerscompass.search"), (onPress) -> { 154 | if (selectionList.hasSelection()) { 155 | selectionList.getSelected().searchForStructure(); 156 | } 157 | })); 158 | searchGroupButton = addRenderableWidget(new TransparentButton(10, 65, 110, 20, Component.translatable("string.explorerscompass.searchForGroup"), (onPress) -> { 159 | if (selectionList.hasSelection()) { 160 | selectionList.getSelected().searchForGroup(); 161 | } 162 | })); 163 | sortByButton = addRenderableWidget(new TransparentButton(10, 90, 110, 20, Component.translatable("string.explorerscompass.sortBy").append(Component.literal(": " + sortingCategory.getLocalizedName())), (onPress) -> { 164 | sortingCategory = sortingCategory.next(); 165 | sortByButton.setMessage(Component.translatable("string.explorerscompass.sortBy").append(Component.literal(": " + sortingCategory.getLocalizedName()))); 166 | selectionList.refreshList(); 167 | })); 168 | cancelButton = addRenderableWidget(new TransparentButton(10, height - 30, 110, 20, Component.translatable("gui.cancel"), (onPress) -> { 169 | minecraft.setScreen(null); 170 | })); 171 | teleportButton = addRenderableWidget(new TransparentButton(width - 120, 10, 110, 20, Component.translatable("string.explorerscompass.teleport"), (onPress) -> { 172 | teleport(); 173 | })); 174 | 175 | searchButton.active = false; 176 | searchGroupButton.active = false; 177 | 178 | teleportButton.visible = ExplorersCompass.canTeleport; 179 | 180 | searchTextField = new TransparentTextField(font, width / 2 - 82, 10, 140, 20, Component.translatable("string.explorerscompass.search")); 181 | addRenderableWidget(searchTextField); 182 | 183 | if (selectionList == null) { 184 | selectionList = new StructureSearchList(this, minecraft, width + 110, height - 40, 40, 45); 185 | } 186 | addRenderableWidget(selectionList); 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/GuiWrapper.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 5 | 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.item.ItemStack; 9 | import net.minecraft.world.level.Level; 10 | 11 | public class GuiWrapper { 12 | 13 | public static void openGUI(Level level, Player player, ItemStack stack) { 14 | Minecraft.getInstance().setScreen(new ExplorersCompassScreen(level, player, stack, (ExplorersCompassItem) stack.getItem(), ExplorersCompass.allowedStructureKeys)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/StructureSearchEntry.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.util.StructureUtils; 5 | import com.mojang.blaze3d.systems.RenderSystem; 6 | 7 | import net.minecraft.Util; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.gui.GuiGraphics; 10 | import net.minecraft.client.gui.components.ObjectSelectionList; 11 | import net.minecraft.client.resources.sounds.SimpleSoundInstance; 12 | import net.minecraft.network.chat.Component; 13 | import net.minecraft.resources.ResourceLocation; 14 | import net.minecraft.sounds.SoundEvents; 15 | import net.minecraftforge.api.distmarker.Dist; 16 | import net.minecraftforge.api.distmarker.OnlyIn; 17 | 18 | @OnlyIn(Dist.CLIENT) 19 | public class StructureSearchEntry extends ObjectSelectionList.Entry { 20 | 21 | private final Minecraft mc; 22 | private final ExplorersCompassScreen parentScreen; 23 | private final ResourceLocation structureKey; 24 | private final StructureSearchList structuresList; 25 | private long lastClickTime; 26 | 27 | public StructureSearchEntry(StructureSearchList structuresList, ResourceLocation structureKey) { 28 | this.structuresList = structuresList; 29 | this.structureKey = structureKey; 30 | parentScreen = structuresList.getParentScreen(); 31 | mc = Minecraft.getInstance(); 32 | } 33 | 34 | @Override 35 | public void render(GuiGraphics guiGraphics, int par1, int par2, int par3, int par4, int par5, int par6, int par7, boolean par8, float par9) { 36 | guiGraphics.drawString(mc.font, Component.literal(StructureUtils.getPrettyStructureName(structureKey)), par3 + 1, par2 + 1, 0xffffff); 37 | guiGraphics.drawString(mc.font, Component.translatable(("string.explorerscompass.source")).append(Component.literal(": " + StructureUtils.getPrettyStructureSource(structureKey))), par3 + 1, par2 + mc.font.lineHeight + 3, 0x808080); 38 | guiGraphics.drawString(mc.font, Component.translatable(("string.explorerscompass.group")).append(Component.literal(": ")).append(Component.translatable(StructureUtils.getPrettyStructureName(ExplorersCompass.structureKeysToTypeKeys.get(structureKey)))), par3 + 1, par2 + mc.font.lineHeight + 14, 0x808080); 39 | guiGraphics.drawString(mc.font, Component.translatable(("string.explorerscompass.dimension")).append(Component.literal(": " + StructureUtils.dimensionKeysToString(ExplorersCompass.dimensionKeysForAllowedStructureKeys.get(structureKey)))), par3 + 1, par2 + mc.font.lineHeight + 25, 0x808080); 40 | RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); 41 | } 42 | 43 | @Override 44 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 45 | if (button == 0) { 46 | structuresList.selectStructure(this); 47 | if (Util.getMillis() - lastClickTime < 250L) { 48 | searchForStructure(); 49 | return true; 50 | } else { 51 | lastClickTime = Util.getMillis(); 52 | return false; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | @Override 59 | public Component getNarration() { 60 | return Component.literal(StructureUtils.getPrettyStructureName(structureKey)); 61 | } 62 | 63 | public void searchForStructure() { 64 | mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); 65 | parentScreen.searchForStructure(structureKey); 66 | } 67 | 68 | public void searchForGroup() { 69 | mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); 70 | parentScreen.searchForGroup(ExplorersCompass.structureKeysToTypeKeys.get(structureKey)); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/StructureSearchList.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import java.util.Objects; 4 | 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.components.ObjectSelectionList; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraft.util.Mth; 10 | import net.minecraftforge.api.distmarker.Dist; 11 | import net.minecraftforge.api.distmarker.OnlyIn; 12 | 13 | @OnlyIn(Dist.CLIENT) 14 | public class StructureSearchList extends ObjectSelectionList { 15 | 16 | private final ExplorersCompassScreen parentScreen; 17 | 18 | public StructureSearchList(ExplorersCompassScreen parentScreen, Minecraft mc, int width, int height, int top, int bottom) { 19 | super(mc, width, height, top, bottom); 20 | this.parentScreen = parentScreen; 21 | refreshList(); 22 | } 23 | 24 | @Override 25 | protected int scrollBarX() { 26 | return getRowLeft() + getRowWidth() - 2; 27 | } 28 | 29 | @Override 30 | public int getRowWidth() { 31 | return super.getRowWidth() + 50; 32 | } 33 | 34 | @Override 35 | protected boolean isSelectedItem(int slotIndex) { 36 | return slotIndex >= 0 && slotIndex < children().size() ? children().get(slotIndex).equals(getSelected()) : false; 37 | } 38 | 39 | @Override 40 | public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 41 | guiGraphics.fill(getRowLeft() - 4, getY(), getRowLeft() + getRowWidth() + 4, getY() + getHeight() + 4, 255 / 2 << 24); 42 | 43 | enableScissor(guiGraphics); 44 | for (int j = 0; j < getItemCount(); ++j) { 45 | int rowTop = getRowTop(j); 46 | int rowBottom = getRowBottom(j); 47 | if (rowBottom >= getY() && rowTop <= getBottom()) { 48 | int j1 = itemHeight - 4; 49 | StructureSearchEntry entry = getEntry(j); 50 | if (/*renderSelection*/ true && isSelectedItem(j)) { 51 | final int insideLeft = getX() + width / 2 - getRowWidth() / 2 + 2; 52 | guiGraphics.fill(insideLeft - 4, rowTop - 4, insideLeft + getRowWidth() + 4, rowTop + itemHeight, 255 / 2 << 24); 53 | } 54 | entry.render(guiGraphics, j, rowTop, getRowLeft(), getRowWidth(), j1, mouseX, mouseY, isMouseOver((double) mouseX, (double) mouseY) && Objects.equals(getEntryAtPosition((double) mouseX, (double) mouseY), entry), partialTicks); 55 | } 56 | } 57 | guiGraphics.disableScissor(); 58 | 59 | if (maxScrollAmount() > 0) { 60 | int left = scrollBarX(); 61 | int right = left + 6; 62 | int height = (int) ((float) ((getBottom() - getY()) * (getBottom() - getY())) / (float) contentHeight()); 63 | height = Mth.clamp(height, 32, getBottom() - getY() - 8); 64 | int top = (int) scrollAmount() * (getBottom() - getY() - height) / maxScrollAmount() + getY(); 65 | if (top < getY()) { 66 | top = getY(); 67 | } 68 | 69 | guiGraphics.fill(left, getY(), right, getBottom(), (int) (2.35F * 255.0F) / 2 << 24); 70 | guiGraphics.fill(left, top, right, top + height, (int) (1.9F * 255.0F) / 2 << 24); 71 | } 72 | } 73 | 74 | @Override 75 | protected void enableScissor(GuiGraphics guiGraphics) { 76 | guiGraphics.enableScissor(getX(), getY(), getRight(), getBottom()); 77 | } 78 | 79 | @Override 80 | public int getRowBottom(int index) { 81 | return getRowTop(index) + itemHeight; 82 | } 83 | 84 | public void refreshList() { 85 | clearEntries(); 86 | for (ResourceLocation key : parentScreen.sortStructures()) { 87 | addEntry(new StructureSearchEntry(this, key)); 88 | } 89 | selectStructure(null); 90 | setScrollAmount(0); 91 | } 92 | 93 | public void selectStructure(StructureSearchEntry entry) { 94 | setSelected(entry); 95 | parentScreen.selectStructure(entry); 96 | } 97 | 98 | public boolean hasSelection() { 99 | return getSelected() != null; 100 | } 101 | 102 | public ExplorersCompassScreen getParentScreen() { 103 | return parentScreen; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/TransparentButton.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.client.gui.components.Button; 6 | import net.minecraft.network.chat.Component; 7 | import net.minecraftforge.api.distmarker.Dist; 8 | import net.minecraftforge.api.distmarker.OnlyIn; 9 | 10 | @OnlyIn(Dist.CLIENT) 11 | public class TransparentButton extends Button { 12 | 13 | public TransparentButton(int x, int y, int width, int height, Component label, OnPress onPress) { 14 | super(x, y, width, height, label, onPress, DEFAULT_NARRATION); 15 | } 16 | 17 | @Override 18 | public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 19 | if (visible) { 20 | Minecraft mc = Minecraft.getInstance(); 21 | float state = 2; 22 | if (!active) { 23 | state = 5; 24 | } else if (isHovered) { 25 | state = 4; 26 | } 27 | final float f = state / 2 * 0.9F + 0.1F; 28 | final int color = (int) (255.0F * f); 29 | 30 | guiGraphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), color / 2 << 24); 31 | guiGraphics.drawCenteredString(mc.font, getMessage(), getX() + getWidth() / 2, getY() + (getHeight() - 8) / 2, 0xffffff); 32 | } 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/gui/TransparentTextField.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.gui; 2 | 3 | import net.minecraft.Util; 4 | import net.minecraft.client.gui.Font; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | import net.minecraft.client.gui.components.EditBox; 7 | import net.minecraft.client.renderer.RenderType; 8 | import net.minecraft.network.chat.Component; 9 | import net.minecraft.util.Mth; 10 | import net.minecraftforge.api.distmarker.Dist; 11 | import net.minecraftforge.api.distmarker.OnlyIn; 12 | 13 | @OnlyIn(Dist.CLIENT) 14 | public class TransparentTextField extends EditBox { 15 | 16 | private Font font; 17 | private Component label; 18 | private int labelColor = 0x808080; 19 | 20 | private boolean pseudoIsEnabled = true; 21 | private boolean pseudoEnableBackgroundDrawing = true; 22 | private int pseudoMaxStringLength = 32; 23 | private int pseudoLineScrollOffset; 24 | private int pseudoEnabledColor = 14737632; 25 | private int pseudoDisabledColor = 7368816; 26 | private int pseudoSelectionEnd; 27 | private long pseudoFocusedTime; 28 | 29 | public TransparentTextField(Font font, int x, int y, int width, int height, Component label) { 30 | super(font, x, y, width, height, label); 31 | this.font = font; 32 | this.label = label; 33 | } 34 | 35 | @Override 36 | public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 37 | if (isVisible()) { 38 | if (pseudoEnableBackgroundDrawing) { 39 | guiGraphics.fill(getX(), getY(), getX() + width, getY() + height, 255 / 2 << 24); 40 | } 41 | boolean showLabel = !isFocused() && getValue().isEmpty(); 42 | int i = showLabel ? labelColor : (pseudoIsEnabled ? pseudoEnabledColor : pseudoDisabledColor); 43 | int j = getCursorPosition() - pseudoLineScrollOffset; 44 | int k = pseudoSelectionEnd - pseudoLineScrollOffset; 45 | String text = showLabel ? label.getString() : getValue(); 46 | String s = font.plainSubstrByWidth(text.substring(pseudoLineScrollOffset), getWidth()); 47 | boolean flag = j >= 0 && j <= s.length(); 48 | boolean flag1 = isFocused() && (Util.getMillis() - pseudoFocusedTime) / 300L % 2L == 0L && flag; 49 | int l = pseudoEnableBackgroundDrawing ? getX() + 4 : getX(); 50 | int i1 = pseudoEnableBackgroundDrawing ? getY() + (getHeight() - 8) / 2 : getY(); 51 | int j1 = l; 52 | 53 | if (k > s.length()) { 54 | k = s.length(); 55 | } 56 | 57 | if (!s.isEmpty()) { 58 | String s1 = flag ? s.substring(0, j) : s; 59 | j1 = guiGraphics.drawString(font, s1, (float) l, (float) i1, i, true); 60 | } 61 | 62 | boolean flag2 = getCursorPosition() < getValue().length() || getValue().length() >= pseudoMaxStringLength; 63 | int k1 = j1; 64 | 65 | if (!flag) { 66 | k1 = j > 0 ? l + width : l; 67 | } else if (flag2) { 68 | k1 = j1 - 1; 69 | --j1; 70 | } 71 | 72 | if (!s.isEmpty() && flag && j < s.length()) { 73 | j1 = guiGraphics.drawString(font, s.substring(j), (float) j1, (float) i1, i, true); 74 | } 75 | 76 | if (flag1) { 77 | if (flag2) { 78 | guiGraphics.fill(RenderType.guiOverlay(), k1, i1 - 1, k1 + 1, i1 + 1 + font.lineHeight, -3092272); 79 | } else { 80 | guiGraphics.drawString(font, "_", (float) k1, (float) i1, i, true); 81 | } 82 | } 83 | 84 | if (k != j) { 85 | int l1 = l + font.width(s.substring(0, k)); 86 | drawSelectionBox(guiGraphics, k1, i1 - 1, l1 - 1, i1 + 1 + font.lineHeight); 87 | } 88 | } 89 | } 90 | 91 | @Override 92 | public void setEditable(boolean enabled) { 93 | super.setEditable(enabled); 94 | pseudoIsEnabled = enabled; 95 | } 96 | 97 | @Override 98 | public void setTextColor(int color) { 99 | super.setTextColor(color); 100 | pseudoEnabledColor = color; 101 | } 102 | 103 | @Override 104 | public void setTextColorUneditable(int color) { 105 | super.setTextColorUneditable(color); 106 | pseudoDisabledColor = color; 107 | } 108 | 109 | @Override 110 | public void setFocused(boolean isFocused) { 111 | if (isFocused && !isFocused()) { 112 | pseudoFocusedTime = Util.getMillis(); 113 | } 114 | super.setFocused(isFocused); 115 | } 116 | 117 | @Override 118 | public void setBordered(boolean enableBackgroundDrawing) { 119 | super.setBordered(enableBackgroundDrawing); 120 | pseudoEnableBackgroundDrawing = enableBackgroundDrawing; 121 | } 122 | 123 | @Override 124 | public void setMaxLength(int length) { 125 | super.setMaxLength(length); 126 | pseudoMaxStringLength = length; 127 | } 128 | 129 | @Override 130 | public void setHighlightPos(int position) { 131 | super.setHighlightPos(position); 132 | int i = getValue().length(); 133 | pseudoSelectionEnd = Mth.clamp(position, 0, i); 134 | if (font != null) { 135 | if (pseudoLineScrollOffset > i) { 136 | pseudoLineScrollOffset = i; 137 | } 138 | 139 | int j = getInnerWidth(); 140 | String s = font.plainSubstrByWidth(getValue().substring(this.pseudoLineScrollOffset), j, false); 141 | int k = s.length() + pseudoLineScrollOffset; 142 | if (pseudoSelectionEnd == pseudoLineScrollOffset) { 143 | pseudoLineScrollOffset -= font.plainSubstrByWidth(getValue(), j, true).length(); 144 | } 145 | 146 | if (pseudoSelectionEnd > k) { 147 | pseudoLineScrollOffset += pseudoSelectionEnd - k; 148 | } else if (pseudoSelectionEnd <= pseudoLineScrollOffset) { 149 | pseudoLineScrollOffset -= pseudoLineScrollOffset - pseudoSelectionEnd; 150 | } 151 | 152 | pseudoLineScrollOffset = Mth.clamp(pseudoLineScrollOffset, 0, i); 153 | } 154 | } 155 | 156 | public void setLabel(Component label) { 157 | this.label = label; 158 | } 159 | 160 | public void setLabelColor(int labelColor) { 161 | this.labelColor = labelColor; 162 | } 163 | 164 | private void drawSelectionBox(GuiGraphics guiGraphics, int startX, int startY, int endX, int endY) { 165 | if (startX < endX) { 166 | int i = startX; 167 | startX = endX; 168 | endX = i; 169 | } 170 | 171 | if (startY < endY) { 172 | int j = startY; 173 | startY = endY; 174 | endY = j; 175 | } 176 | 177 | if (endX > getX() + getWidth()) { 178 | endX = getX() + getWidth(); 179 | } 180 | 181 | if (startX > getX() + getWidth()) { 182 | startX = getX() + getWidth(); 183 | } 184 | 185 | guiGraphics.fill(RenderType.guiTextHighlight(), startX, startY, endX, endY, -16776961); 186 | } 187 | 188 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/items/ExplorersCompassItem.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.items; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.chaosthedude.explorerscompass.ExplorersCompass; 7 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 8 | import com.chaosthedude.explorerscompass.gui.GuiWrapper; 9 | import com.chaosthedude.explorerscompass.network.SyncPacket; 10 | import com.chaosthedude.explorerscompass.util.CompassState; 11 | import com.chaosthedude.explorerscompass.util.ItemUtils; 12 | import com.chaosthedude.explorerscompass.util.PlayerUtils; 13 | import com.chaosthedude.explorerscompass.util.StructureUtils; 14 | import com.chaosthedude.explorerscompass.worker.SearchWorkerManager; 15 | 16 | import net.minecraft.core.BlockPos; 17 | import net.minecraft.core.registries.BuiltInRegistries; 18 | import net.minecraft.resources.ResourceKey; 19 | import net.minecraft.resources.ResourceLocation; 20 | import net.minecraft.server.level.ServerLevel; 21 | import net.minecraft.server.level.ServerPlayer; 22 | import net.minecraft.world.InteractionHand; 23 | import net.minecraft.world.InteractionResult; 24 | import net.minecraft.world.entity.player.Player; 25 | import net.minecraft.world.item.Item; 26 | import net.minecraft.world.item.ItemStack; 27 | import net.minecraft.world.level.Level; 28 | import net.minecraft.world.level.levelgen.structure.Structure; 29 | import net.minecraftforge.network.PacketDistributor; 30 | 31 | public class ExplorersCompassItem extends Item { 32 | 33 | public static final String NAME = "explorerscompass"; 34 | 35 | public static final ResourceKey KEY = ResourceKey.create(BuiltInRegistries.ITEM.key(), ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, NAME)); 36 | 37 | private SearchWorkerManager workerManager; 38 | 39 | public ExplorersCompassItem() { 40 | super(new Properties().setId(KEY).stacksTo(1)); 41 | workerManager = new SearchWorkerManager(); 42 | } 43 | 44 | @Override 45 | public InteractionResult use(Level level, Player player, InteractionHand hand) { 46 | if (!player.isCrouching()) { 47 | if (level.isClientSide()) { 48 | final ItemStack stack = ItemUtils.getHeldItem(player, ExplorersCompass.explorersCompass); 49 | GuiWrapper.openGUI(level, player, stack); 50 | } else { 51 | final ServerLevel serverLevel = (ServerLevel) level; 52 | final ServerPlayer serverPlayer = (ServerPlayer) player; 53 | final boolean canTeleport = ConfigHandler.GENERAL.allowTeleport.get() && PlayerUtils.canTeleport(player.getServer(), player); 54 | ExplorersCompass.network.send(new SyncPacket(canTeleport, StructureUtils.getAllowedStructureKeys(serverLevel), StructureUtils.getGeneratingDimensionsForAllowedStructures(serverLevel), StructureUtils.getStructureKeysToTypeKeys(serverLevel), StructureUtils.getTypeKeysToStructureKeys(serverLevel)), PacketDistributor.PLAYER.with(serverPlayer)); 55 | } 56 | } else { 57 | workerManager.stop(); 58 | workerManager.clear(); 59 | setState(player.getItemInHand(hand), null, CompassState.INACTIVE, player); 60 | } 61 | return InteractionResult.CONSUME; 62 | } 63 | 64 | @Override 65 | public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { 66 | if (getState(oldStack) == getState(newStack)) { 67 | return false; 68 | } 69 | return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); 70 | } 71 | 72 | public void searchForStructure(Level level, Player player, ResourceLocation categoryKey, List structureKeys, BlockPos pos, ItemStack stack) { 73 | setSearching(stack, categoryKey, player); 74 | setSearchRadius(stack, 0, player); 75 | if (level instanceof ServerLevel) { 76 | ServerLevel serverLevel = (ServerLevel) level; 77 | List structures = new ArrayList(); 78 | for (ResourceLocation key : structureKeys) { 79 | structures.add(StructureUtils.getStructureForKey(serverLevel, key)); 80 | } 81 | workerManager.stop(); 82 | workerManager.createWorkers(serverLevel, player, stack, structures, pos); 83 | boolean started = workerManager.start(); 84 | if (!started) { 85 | setNotFound(stack, 0, 0); 86 | } 87 | } 88 | } 89 | 90 | public void succeed(ItemStack stack, ResourceLocation structureKey, int x, int z, int samples, boolean displayCoordinates) { 91 | setFound(stack, structureKey, x, z, samples); 92 | setDisplayCoordinates(stack, displayCoordinates); 93 | workerManager.clear(); 94 | } 95 | 96 | public void fail(ItemStack stack, int radius, int samples) { 97 | workerManager.pop(); 98 | boolean started = workerManager.start(); 99 | if (!started) { 100 | setNotFound(stack, radius, samples); 101 | } 102 | } 103 | 104 | public boolean isActive(ItemStack stack) { 105 | if (ItemUtils.isCompass(stack)) { 106 | return getState(stack) != CompassState.INACTIVE; 107 | } 108 | 109 | return false; 110 | } 111 | 112 | public void setSearching(ItemStack stack, ResourceLocation structureKey, Player player) { 113 | if (ItemUtils.isCompass(stack)) { 114 | stack.set(ExplorersCompass.STRUCTURE_ID_COMPONENT, structureKey.toString()); 115 | stack.set(ExplorersCompass.COMPASS_STATE_COMPONENT, CompassState.SEARCHING.getID()); 116 | } 117 | } 118 | 119 | public void setFound(ItemStack stack, ResourceLocation structureKey, int x, int z, int samples) { 120 | if (ItemUtils.isCompass(stack)) { 121 | stack.set(ExplorersCompass.COMPASS_STATE_COMPONENT, CompassState.FOUND.getID()); 122 | stack.set(ExplorersCompass.STRUCTURE_ID_COMPONENT, structureKey.toString()); 123 | stack.set(ExplorersCompass.FOUND_X_COMPONENT, x); 124 | stack.set(ExplorersCompass.FOUND_Z_COMPONENT, z); 125 | stack.set(ExplorersCompass.SAMPLES_COMPONENT, samples); 126 | } 127 | } 128 | 129 | public void setNotFound(ItemStack stack, int searchRadius, int samples) { 130 | if (ItemUtils.isCompass(stack)) { 131 | stack.set(ExplorersCompass.COMPASS_STATE_COMPONENT, CompassState.NOT_FOUND.getID()); 132 | stack.set(ExplorersCompass.SEARCH_RADIUS_COMPONENT, searchRadius); 133 | stack.set(ExplorersCompass.SAMPLES_COMPONENT, samples); 134 | } 135 | } 136 | 137 | public void setInactive(ItemStack stack, Player player) { 138 | if (ItemUtils.isCompass(stack)) { 139 | stack.set(ExplorersCompass.COMPASS_STATE_COMPONENT, CompassState.INACTIVE.getID()); 140 | } 141 | } 142 | 143 | public void setState(ItemStack stack, BlockPos pos, CompassState state, Player player) { 144 | if (ItemUtils.isCompass(stack)) { 145 | stack.set(ExplorersCompass.COMPASS_STATE_COMPONENT, state.getID()); 146 | } 147 | } 148 | 149 | public void setFoundStructureX(ItemStack stack, int x, Player player) { 150 | if (ItemUtils.isCompass(stack)) { 151 | stack.set(ExplorersCompass.FOUND_X_COMPONENT, x); 152 | } 153 | } 154 | 155 | public void setFoundStructureZ(ItemStack stack, int z, Player player) { 156 | if (ItemUtils.isCompass(stack)) { 157 | stack.set(ExplorersCompass.FOUND_Z_COMPONENT, z); 158 | } 159 | } 160 | 161 | public void setStructureKey(ItemStack stack, ResourceLocation structureKey, Player player) { 162 | if (ItemUtils.isCompass(stack)) { 163 | stack.set(ExplorersCompass.STRUCTURE_ID_COMPONENT, structureKey.toString()); 164 | } 165 | } 166 | 167 | public void setSearchRadius(ItemStack stack, int searchRadius, Player player) { 168 | if (ItemUtils.isCompass(stack)) { 169 | stack.set(ExplorersCompass.SEARCH_RADIUS_COMPONENT, searchRadius); 170 | } 171 | } 172 | 173 | public void setSamples(ItemStack stack, int samples, Player player) { 174 | if (ItemUtils.isCompass(stack)) { 175 | stack.set(ExplorersCompass.SAMPLES_COMPONENT, samples); 176 | } 177 | } 178 | 179 | public void setDisplayCoordinates(ItemStack stack, boolean displayPosition) { 180 | if (ItemUtils.isCompass(stack)) { 181 | stack.set(ExplorersCompass.DISPLAY_COORDS_COMPONENT, displayPosition); 182 | } 183 | } 184 | 185 | public CompassState getState(ItemStack stack) { 186 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.COMPASS_STATE_COMPONENT)) { 187 | return CompassState.fromID(stack.get(ExplorersCompass.COMPASS_STATE_COMPONENT)); 188 | } 189 | 190 | return null; 191 | } 192 | 193 | public int getFoundStructureX(ItemStack stack) { 194 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.FOUND_X_COMPONENT)) { 195 | return stack.get(ExplorersCompass.FOUND_X_COMPONENT); 196 | } 197 | 198 | return 0; 199 | } 200 | 201 | public int getFoundStructureZ(ItemStack stack) { 202 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.FOUND_Z_COMPONENT)) { 203 | return stack.get(ExplorersCompass.FOUND_Z_COMPONENT); 204 | } 205 | 206 | return 0; 207 | } 208 | 209 | public ResourceLocation getStructureKey(ItemStack stack) { 210 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.STRUCTURE_ID_COMPONENT)) { 211 | return ResourceLocation.parse(stack.get(ExplorersCompass.STRUCTURE_ID_COMPONENT)); 212 | } 213 | 214 | return ResourceLocation.fromNamespaceAndPath("", ""); 215 | } 216 | 217 | public int getSearchRadius(ItemStack stack) { 218 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.SEARCH_RADIUS_COMPONENT)) { 219 | return stack.get(ExplorersCompass.SEARCH_RADIUS_COMPONENT); 220 | } 221 | 222 | return -1; 223 | } 224 | 225 | public int getSamples(ItemStack stack) { 226 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.SAMPLES_COMPONENT)) { 227 | return stack.get(ExplorersCompass.SAMPLES_COMPONENT); 228 | } 229 | 230 | return -1; 231 | } 232 | 233 | public int getDistanceToBiome(Player player, ItemStack stack) { 234 | return StructureUtils.getHorizontalDistanceToLocation(player, getFoundStructureX(stack), getFoundStructureZ(stack)); 235 | } 236 | 237 | public boolean shouldDisplayCoordinates(ItemStack stack) { 238 | if (ItemUtils.isCompass(stack) && stack.has(ExplorersCompass.DISPLAY_COORDS_COMPONENT)) { 239 | return stack.get(ExplorersCompass.DISPLAY_COORDS_COMPONENT); 240 | } 241 | 242 | return true; 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/network/CompassSearchPacket.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.network; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.chaosthedude.explorerscompass.ExplorersCompass; 7 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 8 | import com.chaosthedude.explorerscompass.util.ItemUtils; 9 | 10 | import net.minecraft.core.BlockPos; 11 | import net.minecraft.network.FriendlyByteBuf; 12 | import net.minecraft.resources.ResourceLocation; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraftforge.event.network.CustomPayloadEvent; 15 | 16 | public class CompassSearchPacket { 17 | 18 | private ResourceLocation groupKey; 19 | private List structureKeys; 20 | private int x; 21 | private int y; 22 | private int z; 23 | 24 | public CompassSearchPacket() {} 25 | 26 | public CompassSearchPacket(ResourceLocation groupKey, List structureKeys, BlockPos pos) { 27 | this.groupKey = groupKey; 28 | this.structureKeys = structureKeys; 29 | 30 | this.x = pos.getX(); 31 | this.y = pos.getY(); 32 | this.z = pos.getZ(); 33 | } 34 | 35 | public CompassSearchPacket(FriendlyByteBuf buf) { 36 | groupKey = buf.readResourceLocation(); 37 | 38 | structureKeys = new ArrayList(); 39 | int numStructures = buf.readInt(); 40 | for (int i = 0; i < numStructures; i++) { 41 | structureKeys.add(buf.readResourceLocation()); 42 | } 43 | 44 | x = buf.readInt(); 45 | y = buf.readInt(); 46 | z = buf.readInt(); 47 | } 48 | 49 | public void toBytes(FriendlyByteBuf buf) { 50 | buf.writeResourceLocation(groupKey); 51 | 52 | buf.writeInt(structureKeys.size()); 53 | for (ResourceLocation key : structureKeys) { 54 | buf.writeResourceLocation(key); 55 | } 56 | 57 | buf.writeInt(x); 58 | buf.writeInt(y); 59 | buf.writeInt(z); 60 | } 61 | 62 | public static void handle(CompassSearchPacket packet, CustomPayloadEvent.Context ctx) { 63 | ctx.enqueueWork(() -> { 64 | final ItemStack stack = ItemUtils.getHeldItem(ctx.getSender(), ExplorersCompass.explorersCompass); 65 | if (!stack.isEmpty()) { 66 | final ExplorersCompassItem explorersCompass = (ExplorersCompassItem) stack.getItem(); 67 | explorersCompass.searchForStructure(ctx.getSender().serverLevel(), ctx.getSender(), packet.groupKey, packet.structureKeys, new BlockPos(packet.x, packet.y, packet.z), stack); 68 | } 69 | }); 70 | ctx.setPacketHandled(true); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/network/SyncPacket.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.network; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import com.chaosthedude.explorerscompass.ExplorersCompass; 9 | import com.google.common.collect.ArrayListMultimap; 10 | import com.google.common.collect.ListMultimap; 11 | 12 | import net.minecraft.network.FriendlyByteBuf; 13 | import net.minecraft.resources.ResourceLocation; 14 | import net.minecraftforge.event.network.CustomPayloadEvent; 15 | 16 | public class SyncPacket { 17 | 18 | private boolean canTeleport; 19 | private List allowedStructureKeys; 20 | private ListMultimap dimensionKeysForAllowedStructureKeys; 21 | private Map structureKeysToTypeKeys; 22 | private ListMultimap typeKeysToStructureKeys; 23 | 24 | public SyncPacket() {} 25 | 26 | public SyncPacket(boolean canTeleport, List allowedStructures, ListMultimap dimensionsForAllowedStructures, Map structureKeysToTypeKeys, ListMultimap typeKeysToStructureKeys) { 27 | this.canTeleport = canTeleport; 28 | this.allowedStructureKeys = allowedStructures; 29 | this.dimensionKeysForAllowedStructureKeys = dimensionsForAllowedStructures; 30 | this.structureKeysToTypeKeys = structureKeysToTypeKeys; 31 | this.typeKeysToStructureKeys = typeKeysToStructureKeys; 32 | } 33 | 34 | public SyncPacket(FriendlyByteBuf buf) { 35 | canTeleport = buf.readBoolean(); 36 | allowedStructureKeys = new ArrayList(); 37 | dimensionKeysForAllowedStructureKeys = ArrayListMultimap.create(); 38 | structureKeysToTypeKeys = new HashMap(); 39 | typeKeysToStructureKeys = ArrayListMultimap.create(); 40 | 41 | int numStructures = buf.readInt(); 42 | for (int i = 0; i < numStructures; i++) { 43 | ResourceLocation structureKey = buf.readResourceLocation(); 44 | int numDimensions = buf.readInt(); 45 | List dimensions = new ArrayList(); 46 | for (int j = 0; j < numDimensions; j++) { 47 | dimensions.add(buf.readResourceLocation()); 48 | } 49 | ResourceLocation typeKey = buf.readResourceLocation(); 50 | if (structureKey != null) { 51 | allowedStructureKeys.add(structureKey); 52 | dimensionKeysForAllowedStructureKeys.putAll(structureKey, dimensions); 53 | structureKeysToTypeKeys.put(structureKey, typeKey); 54 | } 55 | } 56 | 57 | int numTypes = buf.readInt(); 58 | for (int i = 0; i < numTypes; i++) { 59 | ResourceLocation typeKey = buf.readResourceLocation(); 60 | int numStructuresToAdd = buf.readInt(); 61 | for (int j = 0; j < numStructuresToAdd; j++) { 62 | ResourceLocation structureKey = buf.readResourceLocation(); 63 | typeKeysToStructureKeys.put(typeKey, structureKey); 64 | } 65 | } 66 | } 67 | 68 | public void toBytes(FriendlyByteBuf buf) { 69 | buf.writeBoolean(canTeleport); 70 | buf.writeInt(allowedStructureKeys.size()); 71 | for (ResourceLocation structureKey : allowedStructureKeys) { 72 | buf.writeResourceLocation(structureKey); 73 | List dimensions = dimensionKeysForAllowedStructureKeys.get(structureKey); 74 | buf.writeInt(dimensions.size()); 75 | for (ResourceLocation dimensionKey : dimensions) { 76 | buf.writeResourceLocation(dimensionKey); 77 | } 78 | ResourceLocation typeKey = structureKeysToTypeKeys.get(structureKey); 79 | buf.writeResourceLocation(typeKey); 80 | } 81 | 82 | buf.writeInt(typeKeysToStructureKeys.keySet().size()); 83 | for (ResourceLocation typeKey : typeKeysToStructureKeys.keySet()) { 84 | buf.writeResourceLocation(typeKey); 85 | List structureKeys = typeKeysToStructureKeys.get(typeKey); 86 | buf.writeInt(structureKeys.size()); 87 | for (ResourceLocation structureKey : structureKeys) { 88 | buf.writeResourceLocation(structureKey); 89 | } 90 | } 91 | } 92 | 93 | public static void handle(SyncPacket packet, CustomPayloadEvent.Context ctx) { 94 | ctx.enqueueWork(() -> { 95 | ExplorersCompass.canTeleport = packet.canTeleport; 96 | ExplorersCompass.allowedStructureKeys = packet.allowedStructureKeys; 97 | ExplorersCompass.dimensionKeysForAllowedStructureKeys = packet.dimensionKeysForAllowedStructureKeys; 98 | ExplorersCompass.structureKeysToTypeKeys = packet.structureKeysToTypeKeys; 99 | ExplorersCompass.typeKeysToStructureKeys = packet.typeKeysToStructureKeys; 100 | }); 101 | ctx.setPacketHandled(true); 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/network/TeleportPacket.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.network; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 5 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 6 | import com.chaosthedude.explorerscompass.util.CompassState; 7 | import com.chaosthedude.explorerscompass.util.ItemUtils; 8 | import com.chaosthedude.explorerscompass.util.PlayerUtils; 9 | 10 | import net.minecraft.core.BlockPos; 11 | import net.minecraft.network.FriendlyByteBuf; 12 | import net.minecraft.server.level.ServerPlayer; 13 | import net.minecraft.tags.BlockTags; 14 | import net.minecraft.world.item.ItemStack; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraftforge.event.network.CustomPayloadEvent; 17 | 18 | public class TeleportPacket { 19 | 20 | public TeleportPacket() {} 21 | 22 | public TeleportPacket(FriendlyByteBuf buf) {} 23 | 24 | public void fromBytes(FriendlyByteBuf buf) {} 25 | 26 | public void toBytes(FriendlyByteBuf buf) {} 27 | 28 | public static void handle(TeleportPacket packet, CustomPayloadEvent.Context ctx) { 29 | ctx.enqueueWork(() -> { 30 | final ItemStack stack = ItemUtils.getHeldItem(ctx.getSender(), ExplorersCompass.explorersCompass); 31 | if (!stack.isEmpty()) { 32 | final ExplorersCompassItem explorersCompass = (ExplorersCompassItem) stack.getItem(); 33 | final ServerPlayer player = ctx.getSender(); 34 | if (ConfigHandler.GENERAL.allowTeleport.get() && PlayerUtils.canTeleport(player.getServer(), player)) { 35 | if (explorersCompass.getState(stack) == CompassState.FOUND) { 36 | final int x = explorersCompass.getFoundStructureX(stack); 37 | final int z = explorersCompass.getFoundStructureZ(stack); 38 | final int y = packet.findValidTeleportHeight(player.level(), x, z); 39 | 40 | player.stopRiding(); 41 | player.connection.teleport(x, y, z, player.getYRot(), player.getXRot()); 42 | 43 | if (!player.isFallFlying()) { 44 | player.setDeltaMovement(player.getDeltaMovement().x(), 0, player.getDeltaMovement().z()); 45 | player.setOnGround(true); 46 | } 47 | } 48 | } else { 49 | ExplorersCompass.LOGGER.warn("Player " + player.getDisplayName().getString() + " tried to teleport but does not have permission."); 50 | } 51 | } 52 | }); 53 | ctx.setPacketHandled(true); 54 | } 55 | 56 | private int findValidTeleportHeight(Level level, int x, int z) { 57 | int upY = level.getSeaLevel(); 58 | int downY = level.getSeaLevel(); 59 | while ((!level.isOutsideBuildHeight(upY) || !level.isOutsideBuildHeight(downY)) && !(isValidTeleportPosition(level, new BlockPos(x, upY, z)) || isValidTeleportPosition(level, new BlockPos(x, downY, z)))) { 60 | upY++; 61 | downY--; 62 | } 63 | BlockPos upPos = new BlockPos(x, upY, z); 64 | BlockPos downPos = new BlockPos(x, downY, z); 65 | if (isValidTeleportPosition(level, upPos)) { 66 | return upY; 67 | } 68 | if (isValidTeleportPosition(level, downPos)) { 69 | return downY; 70 | } 71 | return 256; 72 | } 73 | 74 | private boolean isValidTeleportPosition(Level level, BlockPos pos) { 75 | return isFree(level, pos) && isFree(level, pos.above()) && !isFree(level, pos.below()); 76 | } 77 | 78 | private boolean isFree(Level level, BlockPos pos) { 79 | return level.getBlockState(pos).isAir() || level.getBlockState(pos).is(BlockTags.FIRE) || level.getBlockState(pos).liquid() || level.getBlockState(pos).canBeReplaced(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/registry/ExplorersCompassRegistry.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.registry; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 5 | 6 | import net.minecraft.core.registries.BuiltInRegistries; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraftforge.eventbus.api.SubscribeEvent; 9 | import net.minecraftforge.fml.common.Mod.EventBusSubscriber; 10 | import net.minecraftforge.registries.ForgeRegistries; 11 | import net.minecraftforge.registries.RegisterEvent; 12 | 13 | @EventBusSubscriber(modid = ExplorersCompass.MODID, bus = EventBusSubscriber.Bus.MOD) 14 | public class ExplorersCompassRegistry { 15 | 16 | @SubscribeEvent 17 | public static void registerItems(RegisterEvent e) { 18 | e.register(ForgeRegistries.Keys.ITEMS, helper -> { 19 | ExplorersCompass.explorersCompass = new ExplorersCompassItem(); 20 | helper.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, ExplorersCompassItem.NAME), ExplorersCompass.explorersCompass); 21 | }); 22 | 23 | e.register(BuiltInRegistries.DATA_COMPONENT_TYPE.key(), registry -> { 24 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "structure_id"), ExplorersCompass.STRUCTURE_ID_COMPONENT); 25 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "compass_state"), ExplorersCompass.COMPASS_STATE_COMPONENT); 26 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "found_x"), ExplorersCompass.FOUND_X_COMPONENT); 27 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "found_z"), ExplorersCompass.FOUND_Z_COMPONENT); 28 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "search_radius"), ExplorersCompass.SEARCH_RADIUS_COMPONENT); 29 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "samples"), ExplorersCompass.SAMPLES_COMPONENT); 30 | registry.register(ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "display_coords"), ExplorersCompass.DISPLAY_COORDS_COMPONENT); 31 | }); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/sorting/DimensionSorting.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.sorting; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | import com.chaosthedude.explorerscompass.util.StructureUtils; 5 | 6 | import net.minecraft.client.resources.language.I18n; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraftforge.api.distmarker.Dist; 9 | import net.minecraftforge.api.distmarker.OnlyIn; 10 | 11 | @OnlyIn(Dist.CLIENT) 12 | public class DimensionSorting implements ISorting { 13 | 14 | @Override 15 | public int compare(ResourceLocation key1, ResourceLocation key2) { 16 | return StructureUtils.dimensionKeysToString(ExplorersCompass.dimensionKeysForAllowedStructureKeys.get(key1)).compareTo(StructureUtils.dimensionKeysToString(ExplorersCompass.dimensionKeysForAllowedStructureKeys.get(key2))); 17 | } 18 | 19 | @Override 20 | public Object getValue(ResourceLocation key) { 21 | return StructureUtils.dimensionKeysToString(ExplorersCompass.dimensionKeysForAllowedStructureKeys.get(key)); 22 | } 23 | 24 | @Override 25 | public ISorting next() { 26 | return new GroupSorting(); 27 | } 28 | 29 | @Override 30 | public String getLocalizedName() { 31 | return I18n.get("string.explorerscompass.dimension"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/sorting/GroupSorting.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.sorting; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | 5 | import net.minecraft.client.resources.language.I18n; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraftforge.api.distmarker.Dist; 8 | import net.minecraftforge.api.distmarker.OnlyIn; 9 | 10 | @OnlyIn(Dist.CLIENT) 11 | public class GroupSorting implements ISorting { 12 | 13 | @Override 14 | public int compare(ResourceLocation key1, ResourceLocation key2) { 15 | return ExplorersCompass.structureKeysToTypeKeys.get(key1).compareTo(ExplorersCompass.structureKeysToTypeKeys.get(key2)); 16 | } 17 | 18 | @Override 19 | public Object getValue(ResourceLocation key) { 20 | return ExplorersCompass.structureKeysToTypeKeys.get(key); 21 | } 22 | 23 | @Override 24 | public ISorting next() { 25 | return new NameSorting(); 26 | } 27 | 28 | @Override 29 | public String getLocalizedName() { 30 | return I18n.get("string.explorerscompass.group"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/sorting/ISorting.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.sorting; 2 | 3 | import java.util.Comparator; 4 | 5 | import net.minecraft.resources.ResourceLocation; 6 | import net.minecraftforge.api.distmarker.Dist; 7 | import net.minecraftforge.api.distmarker.OnlyIn; 8 | 9 | @OnlyIn(Dist.CLIENT) 10 | public interface ISorting extends Comparator { 11 | 12 | @Override 13 | public int compare(ResourceLocation key1, ResourceLocation key2); 14 | 15 | public Object getValue(ResourceLocation key); 16 | 17 | public ISorting next(); 18 | 19 | public String getLocalizedName(); 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/sorting/NameSorting.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.sorting; 2 | 3 | import com.chaosthedude.explorerscompass.util.StructureUtils; 4 | 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.resources.language.I18n; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraftforge.api.distmarker.Dist; 9 | import net.minecraftforge.api.distmarker.OnlyIn; 10 | 11 | @OnlyIn(Dist.CLIENT) 12 | public class NameSorting implements ISorting { 13 | 14 | @Override 15 | public int compare(ResourceLocation key1, ResourceLocation key2) { 16 | return StructureUtils.getPrettyStructureName(key1).compareTo(StructureUtils.getPrettyStructureName(key2)); 17 | } 18 | 19 | @Override 20 | public Object getValue(ResourceLocation key) { 21 | return StructureUtils.getPrettyStructureName(key); 22 | } 23 | 24 | @Override 25 | public ISorting next() { 26 | return new SourceSorting(); 27 | } 28 | 29 | @Override 30 | public String getLocalizedName() { 31 | return I18n.get("string.explorerscompass.name"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/sorting/SourceSorting.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.sorting; 2 | 3 | import com.chaosthedude.explorerscompass.util.StructureUtils; 4 | 5 | import net.minecraft.client.resources.language.I18n; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraftforge.api.distmarker.Dist; 8 | import net.minecraftforge.api.distmarker.OnlyIn; 9 | 10 | @OnlyIn(Dist.CLIENT) 11 | public class SourceSorting implements ISorting { 12 | 13 | @Override 14 | public int compare(ResourceLocation key1, ResourceLocation key2) { 15 | return StructureUtils.getPrettyStructureSource(key1).compareTo(StructureUtils.getPrettyStructureSource(key2)); 16 | } 17 | 18 | @Override 19 | public Object getValue(ResourceLocation key) { 20 | return StructureUtils.getPrettyStructureSource(key); 21 | } 22 | 23 | @Override 24 | public ISorting next() { 25 | return new DimensionSorting(); 26 | } 27 | 28 | @Override 29 | public String getLocalizedName() { 30 | return I18n.get("string.explorerscompass.source"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/util/CompassState.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.util; 2 | 3 | public enum CompassState { 4 | 5 | INACTIVE(0), SEARCHING(1), FOUND(2), NOT_FOUND(3); 6 | 7 | private int id; 8 | 9 | CompassState(int id) { 10 | this.id = id; 11 | } 12 | 13 | public int getID() { 14 | return id; 15 | } 16 | 17 | public static CompassState fromID(int id) { 18 | for (CompassState state : values()) { 19 | if (state.getID() == id) { 20 | return state; 21 | } 22 | } 23 | 24 | return null; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/util/ItemUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.util; 2 | 3 | import com.chaosthedude.explorerscompass.ExplorersCompass; 4 | 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.item.Item; 7 | import net.minecraft.world.item.ItemStack; 8 | 9 | public class ItemUtils { 10 | 11 | public static boolean isCompass(ItemStack stack) { 12 | return !stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass; 13 | } 14 | 15 | public static ItemStack getHeldItem(Player player, Item item) { 16 | if (!player.getMainHandItem().isEmpty() && player.getMainHandItem().getItem() == item) { 17 | return player.getMainHandItem(); 18 | } else if (!player.getOffhandItem().isEmpty() && player.getOffhandItem().getItem() == item) { 19 | return player.getOffhandItem(); 20 | } 21 | 22 | return ItemStack.EMPTY; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/util/PlayerUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.util; 2 | 3 | import net.minecraft.server.MinecraftServer; 4 | import net.minecraft.server.level.ServerPlayer; 5 | import net.minecraft.server.players.ServerOpListEntry; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.level.storage.LevelData; 8 | import net.minecraft.world.level.storage.ServerLevelData; 9 | 10 | public class PlayerUtils { 11 | 12 | public static boolean canTeleport(MinecraftServer server, Player player) { 13 | return cheatModeEnabled(server, player) || isOp(player); 14 | } 15 | 16 | public static boolean cheatModeEnabled(MinecraftServer server, Player player) { 17 | if (server != null && server.isSingleplayer()) { 18 | LevelData levelData = server.getLevel(player.level().dimension()).getLevelData(); 19 | if (levelData instanceof ServerLevelData) { 20 | return ((ServerLevelData) levelData).isAllowCommands(); 21 | } 22 | } 23 | 24 | return false; 25 | } 26 | 27 | public static boolean isOp(Player player) { 28 | if (player instanceof ServerPlayer) { 29 | final ServerOpListEntry userEntry = ((ServerPlayer) player).getServer().getPlayerList().getOps().get(player.getGameProfile()); 30 | return userEntry != null; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/util/RenderUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.util; 2 | 3 | import com.chaosthedude.explorerscompass.client.OverlaySide; 4 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 5 | import com.mojang.blaze3d.vertex.PoseStack; 6 | 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.Font; 9 | import net.minecraft.client.gui.GuiGraphics; 10 | import net.minecraftforge.api.distmarker.Dist; 11 | import net.minecraftforge.api.distmarker.OnlyIn; 12 | 13 | @OnlyIn(Dist.CLIENT) 14 | public class RenderUtils { 15 | 16 | private static final Minecraft mc = Minecraft.getInstance(); 17 | private static final Font font = mc.font; 18 | 19 | public static void drawStringLeft(GuiGraphics guiGraphics, String string, Font font, int x, int y, int color) { 20 | guiGraphics.drawString(font, string, x, y, color, true); 21 | } 22 | 23 | public static void drawStringRight(GuiGraphics guiGraphics, String string, Font font, int x, int y, int color) { 24 | guiGraphics.drawString(font, string, x - font.width(string), y, color, true); 25 | } 26 | 27 | public static void drawConfiguredStringOnHUD(GuiGraphics guiGraphics, String string, int xOffset, int yOffset, int color, int relLineOffset) { 28 | yOffset += (relLineOffset + ConfigHandler.CLIENT.overlayLineOffset.get()) * 9; 29 | if (ConfigHandler.CLIENT.overlaySide.get() == OverlaySide.LEFT) { 30 | drawStringLeft(guiGraphics, string, font, xOffset + 2, yOffset + 2, color); 31 | } else { 32 | drawStringRight(guiGraphics, string, font, mc.getWindow().getGuiScaledWidth() - xOffset - 2, yOffset + 2, color); 33 | } 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/util/StructureUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | import java.util.Set; 10 | 11 | import org.apache.commons.lang3.text.WordUtils; 12 | 13 | import com.chaosthedude.explorerscompass.ExplorersCompass; 14 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 15 | import com.google.common.collect.ArrayListMultimap; 16 | import com.google.common.collect.ListMultimap; 17 | 18 | import net.minecraft.Util; 19 | import net.minecraft.client.resources.language.I18n; 20 | import net.minecraft.core.BlockPos; 21 | import net.minecraft.core.Holder; 22 | import net.minecraft.core.Registry; 23 | import net.minecraft.core.registries.Registries; 24 | import net.minecraft.resources.ResourceLocation; 25 | import net.minecraft.server.level.ServerLevel; 26 | import net.minecraft.util.Mth; 27 | import net.minecraft.world.entity.player.Player; 28 | import net.minecraft.world.level.biome.Biome; 29 | import net.minecraft.world.level.chunk.ChunkGenerator; 30 | import net.minecraft.world.level.levelgen.structure.Structure; 31 | import net.minecraft.world.level.levelgen.structure.StructureSet; 32 | import net.minecraft.world.level.levelgen.structure.StructureSet.StructureSelectionEntry; 33 | import net.minecraft.world.level.levelgen.structure.StructureType; 34 | import net.minecraftforge.api.distmarker.Dist; 35 | import net.minecraftforge.api.distmarker.OnlyIn; 36 | import net.minecraftforge.fml.ModContainer; 37 | import net.minecraftforge.fml.ModList; 38 | 39 | public class StructureUtils { 40 | 41 | public static ListMultimap getTypeKeysToStructureKeys(ServerLevel level) { 42 | ListMultimap typeKeysToStructureKeys = ArrayListMultimap.create(); 43 | for (Structure structure : getStructureRegistry(level)) { 44 | typeKeysToStructureKeys.put(getTypeForStructure(level, structure), getKeyForStructure(level, structure)); 45 | } 46 | return typeKeysToStructureKeys; 47 | } 48 | 49 | public static Map getStructureKeysToTypeKeys(ServerLevel level) { 50 | Map structureKeysToStructureKeys = new HashMap(); 51 | for (Structure structure : getStructureRegistry(level)) { 52 | structureKeysToStructureKeys.put(getKeyForStructure(level, structure), getTypeForStructure(level, structure)); 53 | } 54 | return structureKeysToStructureKeys; 55 | } 56 | 57 | public static ResourceLocation getTypeForStructure(ServerLevel level, Structure structure) { 58 | Registry registry = getStructureSetRegistry(level); 59 | for (StructureSet set : registry) { 60 | for (StructureSelectionEntry entry : set.structures()) { 61 | if (entry.structure().get().equals(structure)) { 62 | return registry.getKey(set); 63 | } 64 | } 65 | } 66 | return ResourceLocation.fromNamespaceAndPath(ExplorersCompass.MODID, "none"); 67 | } 68 | 69 | public static ResourceLocation getKeyForStructure(ServerLevel level, Structure structure) { 70 | return getStructureRegistry(level).getKey(structure); 71 | } 72 | 73 | public static Structure getStructureForKey(ServerLevel level, ResourceLocation key) { 74 | return getStructureRegistry(level).getValue(key); 75 | } 76 | 77 | public static Holder getHolderForStructure(ServerLevel level, Structure structure) { 78 | return getStructureRegistry(level).wrapAsHolder(structure); 79 | } 80 | 81 | public static List getAllowedStructureKeys(ServerLevel level) { 82 | final List structures = new ArrayList(); 83 | for (Structure structure : getStructureRegistry(level)) { 84 | if (structure != null && getKeyForStructure(level, structure) != null && !structureIsBlacklisted(level, structure) && !structureIsHidden(level, structure)) { 85 | structures.add(getKeyForStructure(level, structure)); 86 | } 87 | } 88 | return structures; 89 | } 90 | 91 | public static boolean structureIsBlacklisted(ServerLevel level, Structure structure) { 92 | final List structureBlacklist = ConfigHandler.GENERAL.structureBlacklist.get(); 93 | for (String structureKey : structureBlacklist) { 94 | if (getKeyForStructure(level, structure).toString().matches(convertToRegex(structureKey))) { 95 | return true; 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | public static boolean structureIsHidden(ServerLevel level, Structure structure) { 102 | final Registry structureRegistry = getStructureRegistry(level); 103 | return structureRegistry.wrapAsHolder(structure).getTagKeys().anyMatch(tag -> tag.location().getPath().equals("c:hidden_from_locator_selection")); 104 | } 105 | 106 | public static List getGeneratingDimensionKeys(ServerLevel serverLevel, Structure structure) { 107 | final List dimensions = new ArrayList(); 108 | for (ServerLevel level : serverLevel.getServer().getAllLevels()) { 109 | ChunkGenerator chunkGenerator = level.getChunkSource().getGenerator(); 110 | Set> biomeSet = chunkGenerator.getBiomeSource().possibleBiomes(); 111 | if (!structure.biomes().stream().noneMatch(biomeSet::contains)) { 112 | dimensions.add(level.dimension().location()); 113 | } 114 | } 115 | // Fix empty dimensions for stronghold 116 | if (structure == StructureType.STRONGHOLD && dimensions.isEmpty()) { 117 | dimensions.add(ResourceLocation.parse("minecraft:overworld")); 118 | } 119 | return dimensions; 120 | } 121 | 122 | public static ListMultimap getGeneratingDimensionsForAllowedStructures(ServerLevel serverLevel) { 123 | ListMultimap dimensionsForAllowedStructures = ArrayListMultimap.create(); 124 | for (ResourceLocation structureKey : getAllowedStructureKeys(serverLevel)) { 125 | Structure structure = getStructureForKey(serverLevel, structureKey); 126 | dimensionsForAllowedStructures.putAll(structureKey, getGeneratingDimensionKeys(serverLevel, structure)); 127 | } 128 | return dimensionsForAllowedStructures; 129 | } 130 | 131 | public static int getHorizontalDistanceToLocation(Player player, int x, int z) { 132 | return getHorizontalDistanceToLocation(player.blockPosition(), x, z); 133 | } 134 | 135 | public static int getHorizontalDistanceToLocation(BlockPos startPos, int x, int z) { 136 | return (int) Mth.sqrt((float) startPos.distSqr(new BlockPos(x, startPos.getY(), z))); 137 | } 138 | 139 | @OnlyIn(Dist.CLIENT) 140 | public static String getPrettyStructureName(ResourceLocation key) { 141 | String name = key.toString(); 142 | if (ConfigHandler.CLIENT.translateStructureNames.get()) { 143 | name = I18n.get(Util.makeDescriptionId("structure", key)); 144 | } 145 | if (name.equals(Util.makeDescriptionId("structure", key)) || !ConfigHandler.CLIENT.translateStructureNames.get()) { 146 | name = key.toString(); 147 | if (name.contains(":")) { 148 | name = name.substring(name.indexOf(":") + 1); 149 | } 150 | name = WordUtils.capitalize(name.replace('_', ' ')); 151 | } 152 | return name; 153 | } 154 | 155 | @OnlyIn(Dist.CLIENT) 156 | public static String getPrettyStructureSource(ResourceLocation key) { 157 | if (key == null) { 158 | return ""; 159 | } 160 | String registryEntry = key.toString(); 161 | String modid = registryEntry.substring(0, registryEntry.indexOf(":")); 162 | if (modid.equals("minecraft")) { 163 | return "Minecraft"; 164 | } 165 | Optional sourceContainer = ModList.get().getModContainerById(modid); 166 | if (sourceContainer.isPresent()) { 167 | return sourceContainer.get().getModInfo().getDisplayName(); 168 | } 169 | return modid; 170 | } 171 | 172 | @OnlyIn(Dist.CLIENT) 173 | public static String dimensionKeysToString(List dimensions) { 174 | Set dimensionNames = new HashSet(); 175 | dimensions.forEach((key) -> dimensionNames.add(getDimensionName(key))); 176 | return String.join(", ", dimensionNames); 177 | } 178 | 179 | @OnlyIn(Dist.CLIENT) 180 | private static String getDimensionName(ResourceLocation dimensionKey) { 181 | String name = I18n.get(Util.makeDescriptionId("dimension", dimensionKey)); 182 | if (name.equals(Util.makeDescriptionId("dimension", dimensionKey))) { 183 | name = dimensionKey.toString(); 184 | if (name.contains(":")) { 185 | name = name.substring(name.indexOf(":") + 1); 186 | } 187 | name = WordUtils.capitalize(name.replace('_', ' ')); 188 | } 189 | return name; 190 | } 191 | 192 | private static Registry getStructureRegistry(ServerLevel level) { 193 | return level.registryAccess().lookupOrThrow(Registries.STRUCTURE); 194 | } 195 | 196 | private static Registry getStructureSetRegistry(ServerLevel level) { 197 | return level.registryAccess().lookupOrThrow(Registries.STRUCTURE_SET); 198 | } 199 | 200 | private static String convertToRegex(String glob) { 201 | String regex = "^"; 202 | for (char i = 0; i < glob.length(); i++) { 203 | char c = glob.charAt(i); 204 | if (c == '*') { 205 | regex += ".*"; 206 | } else if (c == '?') { 207 | regex += "."; 208 | } else if (c == '.') { 209 | regex += "\\."; 210 | } else { 211 | regex += c; 212 | } 213 | } 214 | regex += "$"; 215 | return regex; 216 | } 217 | 218 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/worker/ConcentricRingsSearchWorker.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.worker; 2 | 3 | import java.util.List; 4 | 5 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 6 | import com.mojang.datafixers.util.Pair; 7 | 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.core.BlockPos.MutableBlockPos; 10 | import net.minecraft.core.SectionPos; 11 | import net.minecraft.server.level.ServerLevel; 12 | import net.minecraft.world.entity.player.Player; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.level.ChunkPos; 15 | import net.minecraft.world.level.levelgen.structure.Structure; 16 | import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; 17 | 18 | public class ConcentricRingsSearchWorker extends StructureSearchWorker { 19 | 20 | private List potentialChunks; 21 | private int chunkIndex; 22 | private double minDistance; 23 | private Pair closest; 24 | 25 | public ConcentricRingsSearchWorker(ServerLevel level, Player player, ItemStack stack, BlockPos startPos, ConcentricRingsStructurePlacement placement, List structureSet, String managerId) { 26 | super(level, player, stack, startPos, placement, structureSet, managerId); 27 | 28 | minDistance = Double.MAX_VALUE; 29 | chunkIndex = 0; 30 | potentialChunks = level.getChunkSource().getGeneratorState().getRingPositionsFor(placement); 31 | 32 | finished = !level.getServer().getWorldData().worldGenOptions().generateStructures() || potentialChunks == null || potentialChunks.isEmpty(); 33 | } 34 | 35 | @Override 36 | public boolean hasWork() { 37 | // Samples for this placement are not necessarily in order of closest to furthest, so disregard radius 38 | return !finished && samples < ConfigHandler.GENERAL.maxSamples.get() && chunkIndex < potentialChunks.size(); 39 | } 40 | 41 | @Override 42 | public boolean doWork() { 43 | super.doWork(); 44 | if (hasWork()) { 45 | ChunkPos chunkPos = potentialChunks.get(chunkIndex); 46 | currentPos = new BlockPos(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 0, SectionPos.sectionToBlockCoord(chunkPos.z, 8)); 47 | double distance = startPos.distSqr(currentPos); 48 | 49 | if (closest == null || distance < minDistance) { 50 | Pair pair = getStructureGeneratingAt(chunkPos); 51 | if (pair != null) { 52 | minDistance = distance; 53 | closest = pair; 54 | } 55 | } 56 | 57 | samples++; 58 | chunkIndex++; 59 | } 60 | 61 | if (hasWork()) { 62 | return true; 63 | } 64 | 65 | if (closest != null) { 66 | succeed(closest.getFirst(), closest.getSecond()); 67 | } else if (!finished) { 68 | fail(); 69 | } 70 | 71 | return false; 72 | } 73 | 74 | @Override 75 | protected String getName() { 76 | return "ConcentricRingsSearchWorker"; 77 | } 78 | 79 | @Override 80 | public boolean shouldLogRadius() { 81 | return false; 82 | } 83 | 84 | // Non-optimized method to get the closest structure, for testing purposes 85 | private Pair getClosest() { 86 | List list = level.getChunkSource().getGeneratorState().getRingPositionsFor(placement); 87 | if (list == null) { 88 | return null; 89 | } else { 90 | Pair closestPair = null; 91 | double minDistance = Double.MAX_VALUE; 92 | MutableBlockPos sampleBlockPos = new MutableBlockPos(); 93 | for (ChunkPos chunkPos : list) { 94 | sampleBlockPos.set(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z, 8)); 95 | double distance = sampleBlockPos.distSqr(startPos); 96 | if (closestPair == null || distance < minDistance) { 97 | Pair pair = getStructureGeneratingAt(chunkPos); 98 | if (pair != null) { 99 | closestPair = pair; 100 | minDistance = distance; 101 | } 102 | } 103 | } 104 | 105 | return closestPair; 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/worker/GenericSearchWorker.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.worker; 2 | 3 | import java.util.List; 4 | 5 | import com.chaosthedude.explorerscompass.ExplorersCompass; 6 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 7 | import com.mojang.datafixers.util.Pair; 8 | 9 | import net.minecraft.core.BlockPos; 10 | import net.minecraft.core.Direction; 11 | import net.minecraft.core.SectionPos; 12 | import net.minecraft.server.level.ServerLevel; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.item.ItemStack; 15 | import net.minecraft.world.level.ChunkPos; 16 | import net.minecraft.world.level.levelgen.structure.Structure; 17 | import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; 18 | 19 | public class GenericSearchWorker extends StructureSearchWorker { 20 | 21 | public int chunkX; 22 | public int chunkZ; 23 | public int length; 24 | public double nextLength; 25 | public Direction direction; 26 | 27 | public GenericSearchWorker(ServerLevel level, Player player, ItemStack stack, BlockPos startPos, StructurePlacement placement, List structureSet, String managerId) { 28 | super(level, player, stack, startPos, placement, structureSet, managerId); 29 | chunkX = startPos.getX() >> 4; 30 | chunkZ = startPos.getZ() >> 4; 31 | nextLength = 1; 32 | length = 0; 33 | direction = Direction.UP; 34 | } 35 | 36 | @Override 37 | public boolean doWork() { 38 | if (hasWork()) { 39 | if (direction == Direction.NORTH) { 40 | chunkZ--; 41 | } else if (direction == Direction.EAST) { 42 | chunkX++; 43 | } else if (direction == Direction.SOUTH) { 44 | chunkZ++; 45 | } else if (direction == Direction.WEST) { 46 | chunkX--; 47 | } 48 | 49 | ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); 50 | currentPos = new BlockPos(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 0, SectionPos.sectionToBlockCoord(chunkPos.z, 8)); 51 | 52 | Pair pair = getStructureGeneratingAt(chunkPos); 53 | if (pair != null) { 54 | succeed(pair.getFirst(), pair.getSecond()); 55 | } 56 | 57 | samples++; 58 | length++; 59 | if (length >= (int)nextLength) { 60 | if (direction != Direction.UP) { 61 | nextLength += 0.5; 62 | direction = direction.getClockWise(); 63 | } else { 64 | direction = Direction.NORTH; 65 | } 66 | length = 0; 67 | } 68 | 69 | int radius = getRadius(); 70 | if (radius > 250 && radius / 250 > lastRadiusThreshold) { 71 | if (!stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass) { 72 | ((ExplorersCompassItem) stack.getItem()).setSearchRadius(stack, roundRadius(radius, 250), player); 73 | } 74 | lastRadiusThreshold = radius / 250; 75 | } 76 | } 77 | 78 | if (hasWork()) { 79 | return true; 80 | } 81 | 82 | if (!finished) { 83 | fail(); 84 | } 85 | 86 | return false; 87 | } 88 | 89 | @Override 90 | protected String getName() { 91 | return "GenericSearchWorker"; 92 | } 93 | 94 | @Override 95 | public boolean shouldLogRadius() { 96 | return true; 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/worker/RandomSpreadSearchWorker.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.worker; 2 | 3 | import java.util.List; 4 | 5 | import com.mojang.datafixers.util.Pair; 6 | 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.SectionPos; 9 | import net.minecraft.server.level.ServerLevel; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.item.ItemStack; 12 | import net.minecraft.world.level.ChunkPos; 13 | import net.minecraft.world.level.levelgen.structure.Structure; 14 | import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement; 15 | 16 | public class RandomSpreadSearchWorker extends StructureSearchWorker { 17 | 18 | private int spacing; 19 | private int length; 20 | private int startSectionPosX; 21 | private int startSectionPosZ; 22 | private int x; 23 | private int z; 24 | 25 | public RandomSpreadSearchWorker(ServerLevel level, Player player, ItemStack stack, BlockPos startPos, RandomSpreadStructurePlacement placement, List structureSet, String managerId) { 26 | super(level, player, stack, startPos, placement, structureSet, managerId); 27 | 28 | spacing = placement.spacing(); 29 | startSectionPosX = SectionPos.blockToSectionCoord(startPos.getX()); 30 | startSectionPosZ = SectionPos.blockToSectionCoord(startPos.getZ()); 31 | x = 0; 32 | z = 0; 33 | length = 0; 34 | 35 | finished = !level.getServer().getWorldData().worldGenOptions().generateStructures(); 36 | } 37 | 38 | @Override 39 | public boolean hasWork() { 40 | return super.hasWork(); 41 | } 42 | 43 | @Override 44 | public boolean doWork() { 45 | super.doWork(); 46 | if (hasWork()) { 47 | boolean shouldSampleX = x == -length || x == length; 48 | boolean shouldSampleZ = z == -length || z == length; 49 | 50 | if (shouldSampleX || shouldSampleZ) { 51 | int sampleX = startSectionPosX + (spacing * x); 52 | int sampleZ = startSectionPosZ + (spacing * z); 53 | 54 | ChunkPos chunkPos = placement.getPotentialStructureChunk(level.getSeed(), sampleX, sampleZ); 55 | currentPos = new BlockPos(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 0, SectionPos.sectionToBlockCoord(chunkPos.z, 8)); 56 | 57 | Pair pair = getStructureGeneratingAt(chunkPos); 58 | samples++; 59 | if (pair != null) { 60 | succeed(pair.getFirst(), pair.getSecond()); 61 | } 62 | } 63 | 64 | z++; 65 | if (z > length) { 66 | z = -length; 67 | x++; 68 | if (x > length) { 69 | x = -length; 70 | length++; 71 | } 72 | } 73 | } else { 74 | if (!finished) { 75 | fail(); 76 | } 77 | } 78 | 79 | if (hasWork()) { 80 | return true; 81 | } 82 | 83 | if (!finished) { 84 | fail(); 85 | } 86 | 87 | return false; 88 | } 89 | 90 | @Override 91 | protected String getName() { 92 | return "RandomSpreadSearchWorker"; 93 | } 94 | 95 | @Override 96 | public boolean shouldLogRadius() { 97 | return true; 98 | } 99 | 100 | // Non-optimized method to get the closest structure, for testing purposes 101 | private Pair getClosest() { 102 | for (int x = -length; x <= length; ++x) { 103 | boolean shouldSampleX = x == -length || x == length; 104 | for (int z = -length; z <= length; ++z) { 105 | boolean shouldSampleZ = z == -length || z == length; 106 | if (shouldSampleX || shouldSampleZ) { 107 | int sampleX = startSectionPosX + (spacing * x); 108 | int sampleZ = startSectionPosZ + (spacing * z); 109 | ChunkPos chunkPos = placement.getPotentialStructureChunk(level.getSeed(), sampleX, sampleZ); 110 | Pair pair = getStructureGeneratingAt(chunkPos); 111 | if (pair != null) { 112 | return pair; 113 | } 114 | } 115 | } 116 | } 117 | 118 | return null; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/worker/SearchWorkerManager.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.worker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.lang3.RandomStringUtils; 8 | 9 | import com.chaosthedude.explorerscompass.util.StructureUtils; 10 | 11 | import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; 12 | import it.unimi.dsi.fastutil.objects.ObjectArrayList; 13 | import net.minecraft.core.BlockPos; 14 | import net.minecraft.server.level.ServerLevel; 15 | import net.minecraft.world.entity.player.Player; 16 | import net.minecraft.world.item.ItemStack; 17 | import net.minecraft.world.level.levelgen.structure.Structure; 18 | import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; 19 | import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement; 20 | import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; 21 | 22 | public class SearchWorkerManager { 23 | 24 | private final String id = RandomStringUtils.random(8, "0123456789abcdef"); 25 | 26 | private List> workers; 27 | 28 | public SearchWorkerManager() { 29 | workers = new ArrayList>(); 30 | } 31 | 32 | public void createWorkers(ServerLevel level, Player player, ItemStack stack, List structures, BlockPos startPos) { 33 | workers.clear(); 34 | 35 | Map> placementToStructuresMap = new Object2ObjectArrayMap<>(); 36 | 37 | for (Structure structure : structures) { 38 | for (StructurePlacement structureplacement : level.getChunkSource().getGeneratorState().getPlacementsForStructure(StructureUtils.getHolderForStructure(level, structure))) { 39 | placementToStructuresMap.computeIfAbsent(structureplacement, (holderSet) -> { 40 | return new ObjectArrayList(); 41 | }).add(structure); 42 | } 43 | } 44 | 45 | for (Map.Entry> entry : placementToStructuresMap.entrySet()) { 46 | StructurePlacement placement = entry.getKey(); 47 | if (placement instanceof ConcentricRingsStructurePlacement) { 48 | workers.add(new ConcentricRingsSearchWorker(level, player, stack, startPos, (ConcentricRingsStructurePlacement) placement, entry.getValue(), id)); 49 | } else if (placement instanceof RandomSpreadStructurePlacement) { 50 | workers.add(new RandomSpreadSearchWorker(level, player, stack, startPos, (RandomSpreadStructurePlacement) placement, entry.getValue(), id)); 51 | } else { 52 | workers.add(new GenericSearchWorker(level, player, stack, startPos, placement, entry.getValue(), id)); 53 | } 54 | } 55 | } 56 | 57 | // Returns true if a worker starts, false otherwise 58 | public boolean start() { 59 | if (!workers.isEmpty()) { 60 | workers.get(0).start(); 61 | return true; 62 | } 63 | return false; 64 | } 65 | 66 | public void pop() { 67 | if (!workers.isEmpty()) { 68 | workers.remove(0); 69 | } 70 | } 71 | 72 | public void stop() { 73 | for (StructureSearchWorker worker : workers) { 74 | worker.stop(); 75 | } 76 | } 77 | 78 | public void clear() { 79 | workers.clear(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/chaosthedude/explorerscompass/worker/StructureSearchWorker.java: -------------------------------------------------------------------------------- 1 | package com.chaosthedude.explorerscompass.worker; 2 | 3 | import java.util.List; 4 | 5 | import com.chaosthedude.explorerscompass.ExplorersCompass; 6 | import com.chaosthedude.explorerscompass.config.ConfigHandler; 7 | import com.chaosthedude.explorerscompass.items.ExplorersCompassItem; 8 | import com.chaosthedude.explorerscompass.util.StructureUtils; 9 | import com.mojang.datafixers.util.Pair; 10 | 11 | import net.minecraft.core.BlockPos; 12 | import net.minecraft.core.SectionPos; 13 | import net.minecraft.server.level.ServerLevel; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.minecraft.world.level.ChunkPos; 17 | import net.minecraft.world.level.chunk.ChunkAccess; 18 | import net.minecraft.world.level.chunk.status.ChunkStatus; 19 | import net.minecraft.world.level.levelgen.structure.Structure; 20 | import net.minecraft.world.level.levelgen.structure.StructureCheckResult; 21 | import net.minecraft.world.level.levelgen.structure.StructureStart; 22 | import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; 23 | import net.minecraftforge.common.WorldWorkerManager; 24 | 25 | public abstract class StructureSearchWorker implements WorldWorkerManager.IWorker { 26 | 27 | protected String managerId; 28 | protected ServerLevel level; 29 | protected Player player; 30 | protected ItemStack stack; 31 | protected BlockPos startPos; 32 | protected BlockPos currentPos; 33 | protected T placement; 34 | protected List structureSet; 35 | protected int samples; 36 | protected boolean finished; 37 | protected int lastRadiusThreshold; 38 | 39 | public StructureSearchWorker(ServerLevel level, Player player, ItemStack stack, BlockPos startPos, T placement, List structureSet, String managerId) { 40 | this.level = level; 41 | this.player = player; 42 | this.stack = stack; 43 | this.startPos = startPos; 44 | this.structureSet = structureSet; 45 | this.placement = placement; 46 | this.managerId = managerId; 47 | 48 | currentPos = startPos; 49 | samples = 0; 50 | 51 | finished = !level.getServer().getWorldData().worldGenOptions().generateStructures(); 52 | } 53 | 54 | public void start() { 55 | if (!stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass) { 56 | if (ConfigHandler.GENERAL.maxRadius.get() > 0) { 57 | ExplorersCompass.LOGGER.info("SearchWorkerManager " + managerId + ": " + getName() + " starting with " + (shouldLogRadius() ? ConfigHandler.GENERAL.maxRadius.get() + " max radius, " : "") + ConfigHandler.GENERAL.maxSamples.get() + " max samples"); 58 | WorldWorkerManager.addWorker(this); 59 | } else { 60 | fail(); 61 | } 62 | } 63 | } 64 | 65 | @Override 66 | public boolean hasWork() { 67 | return !finished && getRadius() < ConfigHandler.GENERAL.maxRadius.get() && samples < ConfigHandler.GENERAL.maxSamples.get(); 68 | } 69 | 70 | @Override 71 | public boolean doWork() { 72 | int radius = getRadius(); 73 | if (radius > 250 && radius / 250 > lastRadiusThreshold) { 74 | if (!stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass) { 75 | ((ExplorersCompassItem) stack.getItem()).setSearchRadius(stack, roundRadius(radius, 250), player); 76 | } 77 | lastRadiusThreshold = radius / 250; 78 | } 79 | return false; 80 | } 81 | 82 | protected Pair getStructureGeneratingAt(ChunkPos chunkPos) { 83 | for (Structure structure : structureSet) { 84 | StructureCheckResult result = level.structureManager().checkStructurePresence(chunkPos, structure, placement, false); 85 | if (result != StructureCheckResult.START_NOT_PRESENT) { 86 | if (result == StructureCheckResult.START_PRESENT) { 87 | return Pair.of(placement.getLocatePos(chunkPos), structure); 88 | } 89 | 90 | ChunkAccess chunkAccess = level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS); 91 | StructureStart structureStart = level.structureManager().getStartForStructure(SectionPos.bottomOf(chunkAccess), structure, chunkAccess); 92 | if (structureStart != null && structureStart.isValid()) { 93 | return Pair.of(placement.getLocatePos(structureStart.getChunkPos()), structure); 94 | } 95 | } 96 | } 97 | 98 | return null; 99 | } 100 | 101 | protected void succeed(BlockPos pos, Structure structure) { 102 | ExplorersCompass.LOGGER.info("SearchWorkerManager " + managerId + ": " + getName() + " succeeded with " + (shouldLogRadius() ? getRadius() + " radius, " : "") + samples + " samples"); 103 | if (!stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass) { 104 | ((ExplorersCompassItem) stack.getItem()).succeed(stack, StructureUtils.getKeyForStructure(level, structure), pos.getX(), pos.getZ(), samples, ConfigHandler.GENERAL.displayCoordinates.get()); 105 | } else { 106 | ExplorersCompass.LOGGER.error("SearchWorkerManager " + managerId + ": " + getName() + " found invalid compass after successful search"); 107 | } 108 | finished = true; 109 | } 110 | 111 | protected void fail() { 112 | ExplorersCompass.LOGGER.info("SearchWorkerManager " + managerId + ": " + getName() + " failed with " + (shouldLogRadius() ? getRadius() + " radius, " : "") + samples + " samples"); 113 | if (!stack.isEmpty() && stack.getItem() == ExplorersCompass.explorersCompass) { 114 | ((ExplorersCompassItem) stack.getItem()).fail(stack, roundRadius(getRadius(), 250), samples); 115 | } else { 116 | ExplorersCompass.LOGGER.error("SearchWorkerManager " + managerId + ": " + getName() + " found invalid compass after failed search"); 117 | } 118 | finished = true; 119 | } 120 | 121 | public void stop() { 122 | ExplorersCompass.LOGGER.info("SearchWorkerManager " + managerId + ": " + getName() + " stopped with " + (shouldLogRadius() ? getRadius() + " radius, " : "") + samples + " samples"); 123 | finished = true; 124 | } 125 | 126 | protected int getRadius() { 127 | return StructureUtils.getHorizontalDistanceToLocation(startPos, currentPos.getX(), currentPos.getZ()); 128 | } 129 | 130 | protected int roundRadius(int radius, int roundTo) { 131 | return ((int) radius / roundTo) * roundTo; 132 | } 133 | 134 | protected abstract String getName(); 135 | 136 | protected abstract boolean shouldLogRadius(); 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[55,)" 3 | license="CC BY-NC-SA 4.0" 4 | issueTrackerURL="https://github.com/MattCzyr/ExplorersCompass/issues" 5 | [[mods]] 6 | modId="explorerscompass" 7 | version="1.21.5-1.3.9-forge" 8 | displayName="Explorer's Compass" 9 | displayURL="https://github.com/MattCzyr/ExplorersCompass" 10 | authors="ChaosTheDude" 11 | description=''' 12 | Search for and locate structures anywhere in the world. 13 | ''' 14 | 15 | [[dependencies.explorerscompass]] 16 | modId="forge" 17 | mandatory=true 18 | versionRange="[55,)" 19 | ordering="NONE" 20 | side="BOTH" 21 | [[dependencies.explorerscompass]] 22 | modId="minecraft" 23 | mandatory=true 24 | versionRange="[1.21.5,)" 25 | ordering="NONE" 26 | side="BOTH" 27 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/items/explorerscompass.json: -------------------------------------------------------------------------------- 1 | { 2 | "model": { 3 | "type": "minecraft:range_dispatch", 4 | "property": "explorerscompass:angle", 5 | "scale": 32, 6 | 7 | "entries": [ 8 | { 9 | "model": { 10 | "type": "minecraft:model", 11 | "model": "explorerscompass:item/explorerscompass_16" 12 | }, 13 | "threshold": 0 14 | }, 15 | { 16 | "model": { 17 | "type": "minecraft:model", 18 | "model": "explorerscompass:item/explorerscompass_17" 19 | }, 20 | "threshold": 0.5 21 | }, 22 | { 23 | "model": { 24 | "type": "minecraft:model", 25 | "model": "explorerscompass:item/explorerscompass_18" 26 | }, 27 | "threshold": 1.5 28 | }, 29 | { 30 | "model": { 31 | "type": "minecraft:model", 32 | "model": "explorerscompass:item/explorerscompass_19" 33 | }, 34 | "threshold": 2.5 35 | }, 36 | { 37 | "model": { 38 | "type": "minecraft:model", 39 | "model": "explorerscompass:item/explorerscompass_20" 40 | }, 41 | "threshold": 3.5 42 | }, 43 | { 44 | "model": { 45 | "type": "minecraft:model", 46 | "model": "explorerscompass:item/explorerscompass_21" 47 | }, 48 | "threshold": 4.5 49 | }, 50 | { 51 | "model": { 52 | "type": "minecraft:model", 53 | "model": "explorerscompass:item/explorerscompass_22" 54 | }, 55 | "threshold": 5.5 56 | }, 57 | { 58 | "model": { 59 | "type": "minecraft:model", 60 | "model": "explorerscompass:item/explorerscompass_23" 61 | }, 62 | "threshold": 6.5 63 | }, 64 | { 65 | "model": { 66 | "type": "minecraft:model", 67 | "model": "explorerscompass:item/explorerscompass_24" 68 | }, 69 | "threshold": 7.5 70 | }, 71 | { 72 | "model": { 73 | "type": "minecraft:model", 74 | "model": "explorerscompass:item/explorerscompass_25" 75 | }, 76 | "threshold": 8.5 77 | }, 78 | { 79 | "model": { 80 | "type": "minecraft:model", 81 | "model": "explorerscompass:item/explorerscompass_26" 82 | }, 83 | "threshold": 9.5 84 | }, 85 | { 86 | "model": { 87 | "type": "minecraft:model", 88 | "model": "explorerscompass:item/explorerscompass_27" 89 | }, 90 | "threshold": 10.5 91 | }, 92 | { 93 | "model": { 94 | "type": "minecraft:model", 95 | "model": "explorerscompass:item/explorerscompass_28" 96 | }, 97 | "threshold": 11.5 98 | }, 99 | { 100 | "model": { 101 | "type": "minecraft:model", 102 | "model": "explorerscompass:item/explorerscompass_29" 103 | }, 104 | "threshold": 12.5 105 | }, 106 | { 107 | "model": { 108 | "type": "minecraft:model", 109 | "model": "explorerscompass:item/explorerscompass_30" 110 | }, 111 | "threshold": 13.5 112 | }, 113 | { 114 | "model": { 115 | "type": "minecraft:model", 116 | "model": "explorerscompass:item/explorerscompass_31" 117 | }, 118 | "threshold": 14.5 119 | }, 120 | { 121 | "model": { 122 | "type": "minecraft:model", 123 | "model": "explorerscompass:item/explorerscompass_00" 124 | }, 125 | "threshold": 15.5 126 | }, 127 | { 128 | "model": { 129 | "type": "minecraft:model", 130 | "model": "explorerscompass:item/explorerscompass_01" 131 | }, 132 | "threshold": 16.5 133 | }, 134 | { 135 | "model": { 136 | "type": "minecraft:model", 137 | "model": "explorerscompass:item/explorerscompass_02" 138 | }, 139 | "threshold": 17.5 140 | }, 141 | { 142 | "model": { 143 | "type": "minecraft:model", 144 | "model": "explorerscompass:item/explorerscompass_03" 145 | }, 146 | "threshold": 18.5 147 | }, 148 | { 149 | "model": { 150 | "type": "minecraft:model", 151 | "model": "explorerscompass:item/explorerscompass_04" 152 | }, 153 | "threshold": 19.5 154 | }, 155 | { 156 | "model": { 157 | "type": "minecraft:model", 158 | "model": "explorerscompass:item/explorerscompass_05" 159 | }, 160 | "threshold": 20.5 161 | }, 162 | { 163 | "model": { 164 | "type": "minecraft:model", 165 | "model": "explorerscompass:item/explorerscompass_06" 166 | }, 167 | "threshold": 21.5 168 | }, 169 | { 170 | "model": { 171 | "type": "minecraft:model", 172 | "model": "explorerscompass:item/explorerscompass_07" 173 | }, 174 | "threshold": 22.5 175 | }, 176 | { 177 | "model": { 178 | "type": "minecraft:model", 179 | "model": "explorerscompass:item/explorerscompass_08" 180 | }, 181 | "threshold": 23.5 182 | }, 183 | { 184 | "model": { 185 | "type": "minecraft:model", 186 | "model": "explorerscompass:item/explorerscompass_09" 187 | }, 188 | "threshold": 24.5 189 | }, 190 | { 191 | "model": { 192 | "type": "minecraft:model", 193 | "model": "explorerscompass:item/explorerscompass_10" 194 | }, 195 | "threshold": 25.5 196 | }, 197 | { 198 | "model": { 199 | "type": "minecraft:model", 200 | "model": "explorerscompass:item/explorerscompass_11" 201 | }, 202 | "threshold": 26.5 203 | }, 204 | { 205 | "model": { 206 | "type": "minecraft:model", 207 | "model": "explorerscompass:item/explorerscompass_12" 208 | }, 209 | "threshold": 27.5 210 | }, 211 | { 212 | "model": { 213 | "type": "minecraft:model", 214 | "model": "explorerscompass:item/explorerscompass_13" 215 | }, 216 | "threshold": 28.5 217 | }, 218 | { 219 | "model": { 220 | "type": "minecraft:model", 221 | "model": "explorerscompass:item/explorerscompass_14" 222 | }, 223 | "threshold": 29.5 224 | }, 225 | { 226 | "model": { 227 | "type": "minecraft:model", 228 | "model": "explorerscompass:item/explorerscompass_15" 229 | }, 230 | "threshold": 30.5 231 | }, 232 | { 233 | "model": { 234 | "type": "minecraft:model", 235 | "model": "explorerscompass:item/explorerscompass_16" 236 | }, 237 | "threshold": 31.5 238 | } 239 | ] 240 | } 241 | } -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/de_de.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Sprachdatei", 3 | "_comment": "DEUTSCHLAND - DEUTSCH", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Kompass des Entdeckers", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Zurück", 10 | "string.explorerscompass.searchForGroup": "Suche nach Gruppe", 11 | "string.explorerscompass.selectStructure": "Bauwerk auswählen", 12 | "string.explorerscompass.teleport": "Teleportieren", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Bauwerk", 16 | "string.explorerscompass.category": "Kategorie", 17 | "string.explorerscompass.coordinates": "Koordinaten", 18 | "string.explorerscompass.dimension": "Dimension", 19 | "string.explorerscompass.distance": "Distanz", 20 | "string.explorerscompass.found": "Gefunden", 21 | "string.explorerscompass.group": "Gruppe", 22 | "string.explorerscompass.name": "Name", 23 | "string.explorerscompass.notFound": "Nicht Gefunden", 24 | "string.explorerscompass.radius": "Radius", 25 | "string.explorerscompass.samples": "Stichproben", 26 | "string.explorerscompass.search": "Suchen", 27 | "string.explorerscompass.searching": "Suche", 28 | "string.explorerscompass.sortBy": "Sortiere nach", 29 | "string.explorerscompass.source": "Quelle", 30 | "string.explorerscompass.status": "Status", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Roh-Generierung", 34 | "string.explorerscompass.lakes": "Seen", 35 | "string.explorerscompass.local_modifications": "Lokale Modifikationen", 36 | "string.explorerscompass.underground_structures": "Unterirdisch", 37 | "string.explorerscompass.surface_structures": "Oberfläche", 38 | "string.explorerscompass.strongholds": "Festungen", 39 | "string.explorerscompass.underground_ores": "Erze", 40 | "string.explorerscompass.underground_decoration": "Unterirdisch", 41 | "string.explorerscompass.vegetal_decoration": "Vegetation", 42 | "string.explorerscompass.top_layer_modification": "Oberste Schicht", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Bastionsruine", 46 | "structure.minecraft.buried_treasure": "Vergrabener Schatz", 47 | "structure.minecraft.desert_pyramid": "Wüstentempel", 48 | "structure.minecraft.endcity": "Endsiedlung", 49 | "structure.minecraft.end_city": "Endsiedlung", 50 | "structure.minecraft.fortress": "Netherfestung", 51 | "structure.minecraft.igloo": "Iglu", 52 | "structure.minecraft.jungle_pyramid": "Dschungeltempel", 53 | "structure.minecraft.mansion": "Waldanwesen", 54 | "structure.minecraft.mineshaft": "Mine", 55 | "structure.minecraft.mineshaft_mesa": "Mine Mesa", 56 | "structure.minecraft.monument": "Ozeanmonument", 57 | "structure.minecraft.nether_fossil": "Nether-Fossil", 58 | "structure.minecraft.ocean_ruin": "Ozeanruine", 59 | "structure.minecraft.ocean_ruin_cold": "Ozeanruine Kalt", 60 | "structure.minecraft.ocean_ruin_warm": "Ozeanruine Warm", 61 | "structure.minecraft.pillager_outpost": "Plünderer-Außenposten", 62 | "structure.minecraft.ruined_portal": "Portalruine", 63 | "structure.minecraft.ruined_portal_desert": "Portalruine Wüste", 64 | "structure.minecraft.ruined_portal_jungle": "Portalruine Dschungel", 65 | "structure.minecraft.ruined_portal_mountain": "Portalruine Berg", 66 | "structure.minecraft.ruined_portal_nether": "Portalruine Nether", 67 | "structure.minecraft.ruined_portal_ocean": "Portalruine Ozean", 68 | "structure.minecraft.ruined_portal_swamp": "Portalruine Sump", 69 | "structure.minecraft.shipwreck": "Shiffswrack", 70 | "structure.minecraft.shipwreck_beached": "Schiffswrack Gestrandet", 71 | "structure.minecraft.stronghold": "Festung", 72 | "structure.minecraft.swamp_hut": "Sumpfhütte", 73 | "structure.minecraft.village": "Dorf", 74 | "structure.minecraft.village_desert": "Dorf Wüste", 75 | "structure.minecraft.village_plains": "Dorf Ebenen", 76 | "structure.minecraft.village_savanna": "Dorf Savanne", 77 | "structure.minecraft.village_snowy": "Dorf Schneebedeckt", 78 | "structure.minecraft.village_taiga": "Dorf Taiga" 79 | } -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Language File", 3 | "_comment": "UNITED STATES - ENGLISH", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Explorer's Compass", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Back", 10 | "string.explorerscompass.searchForGroup": "Search for Group", 11 | "string.explorerscompass.selectStructure": "Select Structure", 12 | "string.explorerscompass.teleport": "Teleport", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Structure", 16 | "string.explorerscompass.category": "Category", 17 | "string.explorerscompass.coordinates": "Coordinates", 18 | "string.explorerscompass.dimension": "Dimension", 19 | "string.explorerscompass.distance": "Distance", 20 | "string.explorerscompass.found": "Found", 21 | "string.explorerscompass.group": "Group", 22 | "string.explorerscompass.name": "Name", 23 | "string.explorerscompass.notFound": "Not Found", 24 | "string.explorerscompass.radius": "Radius", 25 | "string.explorerscompass.samples": "Samples", 26 | "string.explorerscompass.search": "Search", 27 | "string.explorerscompass.searching": "Searching", 28 | "string.explorerscompass.sortBy": "Sort By", 29 | "string.explorerscompass.source": "Source", 30 | "string.explorerscompass.status": "Status", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Raw Generation", 34 | "string.explorerscompass.lakes": "Lakes", 35 | "string.explorerscompass.local_modifications": "Local Modifications", 36 | "string.explorerscompass.underground_structures": "Underground", 37 | "string.explorerscompass.surface_structures": "Surface", 38 | "string.explorerscompass.strongholds": "Strongholds", 39 | "string.explorerscompass.underground_ores": "Ores", 40 | "string.explorerscompass.underground_decoration": "Underground", 41 | "string.explorerscompass.vegetal_decoration": "Vegetation", 42 | "string.explorerscompass.top_layer_modification": "Top Layer", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Bastion Remnant", 46 | "structure.minecraft.buried_treasure": "Buried Treasure", 47 | "structure.minecraft.desert_pyramid": "Desert Pyramid", 48 | "structure.minecraft.end_city": "End City", 49 | "structure.minecraft.endcity": "End City", 50 | "structure.minecraft.fortress": "Fortress", 51 | "structure.minecraft.igloo": "Igloo", 52 | "structure.minecraft.jungle_pyramid": "Jungle Pyramid", 53 | "structure.minecraft.mansion": "Mansion", 54 | "structure.minecraft.mineshaft": "Mineshaft", 55 | "structure.minecraft.mineshaft_mesa": "Mineshaft Mesa", 56 | "structure.minecraft.monument": "Monument", 57 | "structure.minecraft.nether_fossil": "Nether Fossil", 58 | "structure.minecraft.ocean_ruin": "Ocean Ruin", 59 | "structure.minecraft.ocean_ruin_cold": "Ocean Ruin Cold", 60 | "structure.minecraft.ocean_ruin_warm": "Ocean Ruin Warm", 61 | "structure.minecraft.pillager_outpost": "Pillager Outpost", 62 | "structure.minecraft.ruined_portal": "Ruined Portal", 63 | "structure.minecraft.ruined_portal_desert": "Ruined Portal Desert", 64 | "structure.minecraft.ruined_portal_jungle": "Ruined Portal Jungle", 65 | "structure.minecraft.ruined_portal_mountain": "Ruined Portal Mountain", 66 | "structure.minecraft.ruined_portal_nether": "Ruined Portal Nether", 67 | "structure.minecraft.ruined_portal_ocean": "Ruined Portal Ocean", 68 | "structure.minecraft.ruined_portal_swamp": "Ruined Portal Swamp", 69 | "structure.minecraft.shipwreck": "Shipwreck", 70 | "structure.minecraft.shipwreck_beached": "Shipwreck Beached", 71 | "structure.minecraft.stronghold": "Stronghold", 72 | "structure.minecraft.swamp_hut": "Swamp Hut", 73 | "structure.minecraft.village": "Village", 74 | "structure.minecraft.village_desert": "Village Desert", 75 | "structure.minecraft.village_plains": "Village Plains", 76 | "structure.minecraft.village_savanna": "Village Savanna", 77 | "structure.minecraft.village_snowy": "Village Snowy", 78 | "structure.minecraft.village_taiga": "Village Taiga" 79 | } -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Language File", 3 | "_comment": "ESPAÑA - ESPAÑOL", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Brújula de exploración", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Volver", 10 | "string.explorerscompass.searchForGroup": "Busqueda de grupo", 11 | "string.explorerscompass.selectStructure": "Seleccionar estructura", 12 | "string.explorerscompass.teleport": "Teletransportarse", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Estructura", 16 | "string.explorerscompass.category": "Categoria", 17 | "string.explorerscompass.coordinates": "Coordenadas", 18 | "string.explorerscompass.dimension": "Dimensión", 19 | "string.explorerscompass.distance": "Distancia", 20 | "string.explorerscompass.found": "Encontrado", 21 | "string.explorerscompass.group": "Grupo", 22 | "string.explorerscompass.name": "Nombre", 23 | "string.explorerscompass.notFound": "No Encontrado", 24 | "string.explorerscompass.radius": "Radio", 25 | "string.explorerscompass.samples": "Muestras", 26 | "string.explorerscompass.search": "Buscar", 27 | "string.explorerscompass.searching": "Buscando", 28 | "string.explorerscompass.sortBy": "Ordenar por", 29 | "string.explorerscompass.source": "Fuente", 30 | "string.explorerscompass.status": "Estado", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Estructuras generadas", 34 | "string.explorerscompass.lakes": "Lagos", 35 | "string.explorerscompass.local_modifications": "Modificaciones", 36 | "string.explorerscompass.underground_structures": "Bajo tierra", 37 | "string.explorerscompass.surface_structures": "Superficie", 38 | "string.explorerscompass.strongholds": "Fortalezas", 39 | "string.explorerscompass.underground_ores": "Minerales", 40 | "string.explorerscompass.underground_decoration": "Bajo tierra", 41 | "string.explorerscompass.vegetal_decoration": "Vegetación", 42 | "string.explorerscompass.top_layer_modification": "Capa superior", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Bastión en ruinas", 46 | "structure.minecraft.buried_treasure": "Tesoro enterrado", 47 | "structure.minecraft.desert_pyramid": "Pirámide del desierto", 48 | "structure.minecraft.end_city": "Ciudad del End", 49 | "structure.minecraft.endcity": "Ciudad del End", 50 | "structure.minecraft.fortress": "Fortaleza del nether", 51 | "structure.minecraft.igloo": "Iglú", 52 | "structure.minecraft.jungle_pyramid": "Templo de jungla", 53 | "structure.minecraft.mansion": "Mansión del bosque", 54 | "structure.minecraft.mineshaft": "Mina abandonada", 55 | "structure.minecraft.mineshaft_mesa": "Mina abandonada (mesa)", 56 | "structure.minecraft.monument": "Monumento oceánico", 57 | "structure.minecraft.nether_fossil": "Fósil del nether", 58 | "structure.minecraft.ocean_ruin": "Ruina oceánica", 59 | "structure.minecraft.ocean_ruin_cold": "Ruina oceánica fria", 60 | "structure.minecraft.ocean_ruin_warm": "Ruina oceánica calida", 61 | "structure.minecraft.pillager_outpost": "Puesto de saqueadores", 62 | "structure.minecraft.ruined_portal": "Portal en ruinas", 63 | "structure.minecraft.ruined_portal_desert": "Portal en ruinas en el desierto", 64 | "structure.minecraft.ruined_portal_jungle": "Portal en ruinas en la jungla", 65 | "structure.minecraft.ruined_portal_mountain": "Portal en ruinas en la montaña", 66 | "structure.minecraft.ruined_portal_nether": "Portal en ruinas en el nether", 67 | "structure.minecraft.ruined_portal_ocean": "Portal en ruinas en el oceáno", 68 | "structure.minecraft.ruined_portal_swamp": "Portal en ruinas en el pantano", 69 | "structure.minecraft.shipwreck": "Naufragio", 70 | "structure.minecraft.shipwreck_beached": "Naufragio en la playa", 71 | "structure.minecraft.stronghold": "Fortaleza", 72 | "structure.minecraft.swamp_hut": "Cabaña de pantano", 73 | "structure.minecraft.village": "Aldea", 74 | "structure.minecraft.village_desert": "Aldea en desierto", 75 | "structure.minecraft.village_plains": "Aldea en llanura", 76 | "structure.minecraft.village_savanna": "Aldea en sabana", 77 | "structure.minecraft.village_snowy": "Aldea nevada", 78 | "structure.minecraft.village_taiga": "Aldea en taiga" 79 | } -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Language File", 3 | "_comment": "FRANCE - FRENCH", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Boussole de l'explorateur", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Retour", 10 | "string.explorerscompass.searchForGroup": "Rechercher par Groupe", 11 | "string.explorerscompass.selectStructure": "Sélectionner la structure", 12 | "string.explorerscompass.teleport": "Se téléporter", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Structure", 16 | "string.explorerscompass.category": "Catégorie", 17 | "string.explorerscompass.coordinates": "Coordonnées", 18 | "string.explorerscompass.dimension": "Dimension", 19 | "string.explorerscompass.distance": "Distance", 20 | "string.explorerscompass.found": "Trouvée", 21 | "string.explorerscompass.group": "Groupe", 22 | "string.explorerscompass.name": "Nom", 23 | "string.explorerscompass.notFound": "Non trouvée", 24 | "string.explorerscompass.radius": "Rayon", 25 | "string.explorerscompass.samples": "Echantillons", 26 | "string.explorerscompass.search": "Rechercher", 27 | "string.explorerscompass.searching": "En cours de recherche", 28 | "string.explorerscompass.sortBy": "Trier par ", 29 | "string.explorerscompass.source": "Source", 30 | "string.explorerscompass.status": "Statut", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Génération Brute", 34 | "string.explorerscompass.lakes": "Lacs", 35 | "string.explorerscompass.local_modifications": "Modifications Locales", 36 | "string.explorerscompass.underground_structures": "Souterrain", 37 | "string.explorerscompass.surface_structures": "Surface", 38 | "string.explorerscompass.strongholds": "Forts", 39 | "string.explorerscompass.underground_ores": "Minerais", 40 | "string.explorerscompass.underground_decoration": "Souterrain", 41 | "string.explorerscompass.vegetal_decoration": "Végétation", 42 | "string.explorerscompass.top_layer_modification": "Couche Supérieure", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Vestiges de bastion", 46 | "structure.minecraft.buried_treasure": "Trésor enfoui", 47 | "structure.minecraft.desert_pyramid": "Pyramide", 48 | "structure.minecraft.end_city": "Cité de l'End", 49 | "structure.minecraft.endcity": "Cité de l'End", 50 | "structure.minecraft.fortress": "Forteresse", 51 | "structure.minecraft.igloo": "Igloo", 52 | "structure.minecraft.jungle_pyramid": "Temple de la jungle", 53 | "structure.minecraft.mansion": "Manoir", 54 | "structure.minecraft.mineshaft": "Puits de mine abandonné", 55 | "structure.minecraft.mineshaft_mesa": "Puits de mine abandonné Mesa", 56 | "structure.minecraft.monument": "Monument sous-marin", 57 | "structure.minecraft.nether_fossil": "Fossile du Nether", 58 | "structure.minecraft.ocean_ruin": "Ruines sous-marines", 59 | "structure.minecraft.ocean_ruin_cold": "Ruines sous-marines froides", 60 | "structure.minecraft.ocean_ruin_warm": "Ruines sous-marines chaudes", 61 | "structure.minecraft.pillager_outpost": "Avant-poste de pillards", 62 | "structure.minecraft.ruined_portal": "Portail en ruine", 63 | "structure.minecraft.ruined_portal_desert": "Portail en ruine du Désert", 64 | "structure.minecraft.ruined_portal_jungle": "Portail en ruine de la Jungle", 65 | "structure.minecraft.ruined_portal_mountain": "Portail en ruine de la Montagne", 66 | "structure.minecraft.ruined_portal_nether": "Portail en ruine du Nether", 67 | "structure.minecraft.ruined_portal_ocean": "Portail en ruine de l'Océan", 68 | "structure.minecraft.ruined_portal_swamp": "Portail en ruine du Marais", 69 | "structure.minecraft.shipwreck": "Épave de navire", 70 | "structure.minecraft.shipwreck_beached": "Épave de navire échouée", 71 | "structure.minecraft.stronghold": "Fort", 72 | "structure.minecraft.swamp_hut": "Cabane abandonnée", 73 | "structure.minecraft.village": "Village", 74 | "structure.minecraft.village_desert": "Village du Désert", 75 | "structure.minecraft.village_plains": "Village des Plaines", 76 | "structure.minecraft.village_savanna": "Village de la Savanne", 77 | "structure.minecraft.village_snowy": "Village enneigé", 78 | "structure.minecraft.village_taiga": "Village de Taiga" 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/ja_jp.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Nature's Compass - Language File", 3 | "_comment": "JAPAN - JAPANESE", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "冒険者のコンパス", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "戻る", 10 | "string.explorerscompass.searchForGroup": "グループを検索", 11 | "string.explorerscompass.selectStructure": "構造物を選ぶ", 12 | "string.explorerscompass.teleport": "テレポート", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "構造物", 16 | "string.explorerscompass.category": "カテゴリー", 17 | "string.explorerscompass.coordinates": "座標", 18 | "string.explorerscompass.dimension": "ディメンション", 19 | "string.explorerscompass.distance": "距離", 20 | "string.explorerscompass.found": "発見済み", 21 | "string.explorerscompass.group": "グループ", 22 | "string.explorerscompass.name": "名前", 23 | "string.explorerscompass.notFound": "未発見", 24 | "string.explorerscompass.radius": "半径", 25 | "string.explorerscompass.samples": "サンプル", 26 | "string.explorerscompass.search": "検索", 27 | "string.explorerscompass.searching": "検索中", 28 | "string.explorerscompass.sortBy": "並び替え", 29 | "string.explorerscompass.source": "ソース", 30 | "string.explorerscompass.status": "ステータス", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "生の生成", 34 | "string.explorerscompass.lakes": "湖", 35 | "string.explorerscompass.local_modifications": "ローカル変更", 36 | "string.explorerscompass.underground_structures": "地下", 37 | "string.explorerscompass.surface_structures": "地表", 38 | "string.explorerscompass.strongholds": "要塞", 39 | "string.explorerscompass.underground_ores": "鉱石", 40 | "string.explorerscompass.underground_decoration": "地下", 41 | "string.explorerscompass.vegetal_decoration": "植生", 42 | "string.explorerscompass.top_layer_modification": "地面のレイヤー", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "砦の遺跡", 46 | "structure.minecraft.buried_treasure": "埋もれた宝", 47 | "structure.minecraft.desert_pyramid": "砂漠のピラミッド", 48 | "structure.minecraft.endcity": "エンドシティ", 49 | "structure.minecraft.end_city": "エンドシティ", 50 | "structure.minecraft.fortress": "ネザー要塞", 51 | "structure.minecraft.igloo": "イグルー", 52 | "structure.minecraft.jungle_pyramid": "ジャングルの寺院", 53 | "structure.minecraft.mansion": "森の洋館", 54 | "structure.minecraft.mineshaft": "廃坑", 55 | "structure.minecraft.mineshaft_mesa": "マインシャフトメサ", 56 | "structure.minecraft.monument": "海底神殿", 57 | "structure.minecraft.nether_fossil": "ネザーの化石", 58 | "structure.minecraft.ocean_ruin": "海底遺跡", 59 | "structure.minecraft.ocean_ruin_cold": "オーシャン遺跡コールド", 60 | "structure.minecraft.ocean_ruin_warm": "オーシャン遺跡ウォーム", 61 | "structure.minecraft.pillager_outpost": "ピりジャーの前哨基地", 62 | "structure.minecraft.ruined_portal": "荒廃したポータル", 63 | "structure.minecraft.ruined_portal_desert": "廃墟のポータル砂漠", 64 | "structure.minecraft.ruined_portal_jungle": "廃墟のポータルジャングル", 65 | "structure.minecraft.ruined_portal_mountain": "廃墟のポータルマウンテン", 66 | "structure.minecraft.ruined_portal_nether": "廃墟のポータルネザー", 67 | "structure.minecraft.ruined_portal_ocean": "廃墟のポータルオーシャン", 68 | "structure.minecraft.ruined_portal_swamp": "廃墟のポータル沼", 69 | "structure.minecraft.shipwreck": "難破船", 70 | "structure.minecraft.shipwreck_beached": "難破船の浜", 71 | "structure.minecraft.stronghold": "要塞", 72 | "structure.minecraft.swamp_hut": "沼地の小屋", 73 | "structure.minecraft.village": "村", 74 | "structure.minecraft.village_desert": "村の砂漠", 75 | "structure.minecraft.village_plains": "村の平原", 76 | "structure.minecraft.village_savanna": "ヴィレッジサバンナ", 77 | "structure.minecraft.village_snowy": "雪に覆われた村", 78 | "structure.minecraft.village_taiga": "ヴィレッジタイガ" 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/pt_br.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Language File", 3 | "_comment": "BRAZIL - PORTUGUES", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Bússola do Explorador", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Voltar", 10 | "string.explorerscompass.searchForGroup": "Buscar grupo", 11 | "string.explorerscompass.selectStructure": "Selecione a Estrutura", 12 | "string.explorerscompass.teleport": "Teleportar", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Estrutura", 16 | "string.explorerscompass.category": "Categoria", 17 | "string.explorerscompass.coordinates": "Coordenadas", 18 | "string.explorerscompass.dimension": "Dimensão", 19 | "string.explorerscompass.distance": "Distância", 20 | "string.explorerscompass.found": "Encontrado", 21 | "string.explorerscompass.group": "Grupo", 22 | "string.explorerscompass.name": "Nome", 23 | "string.explorerscompass.notFound": "Não encontrado", 24 | "string.explorerscompass.radius": "Raio", 25 | "string.explorerscompass.samples": "Amostras", 26 | "string.explorerscompass.search": "Buscar", 27 | "string.explorerscompass.searching": "Buscando", 28 | "string.explorerscompass.sortBy": "Ordenar Por", 29 | "string.explorerscompass.source": "Fonte", 30 | "string.explorerscompass.status": "Status", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Geração Bruta", 34 | "string.explorerscompass.lakes": "Lagos", 35 | "string.explorerscompass.local_modifications": "Modificações Locais", 36 | "string.explorerscompass.underground_structures": "Estruturas Subterrâneas", 37 | "string.explorerscompass.surface_structures": "Superfície", 38 | "string.explorerscompass.strongholds": "Fortalezas", 39 | "string.explorerscompass.underground_ores": "Minérios Subterrâneos", 40 | "string.explorerscompass.underground_decoration": "Decoração Subterrânea", 41 | "string.explorerscompass.vegetal_decoration": "Vegetação", 42 | "string.explorerscompass.top_layer_modification": "Modificação da Camada Superior", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Bastião em Ruínas", 46 | "structure.minecraft.buried_treasure": "Tesouro Enterrado", 47 | "structure.minecraft.desert_pyramid": "Pirâmide no Deserto", 48 | "structure.minecraft.end_city": "Cidade do End", 49 | "structure.minecraft.endcity": "Cidade do End", 50 | "structure.minecraft.fortress": "Fortaleza", 51 | "structure.minecraft.igloo": "Iglu", 52 | "structure.minecraft.jungle_pyramid": "Pirâmide da Selva", 53 | "structure.minecraft.mansion": "Mansão", 54 | "structure.minecraft.mineshaft": "Minas", 55 | "structure.minecraft.mineshaft_mesa": "Minas do Mesa", 56 | "structure.minecraft.monument": "Monumento", 57 | "structure.minecraft.nether_fossil": "Fóssil do Nether", 58 | "structure.minecraft.ocean_ruin": "Ruínas Submarinas", 59 | "structure.minecraft.ocean_ruin_cold": "Ruínas Submarinas Frio", 60 | "structure.minecraft.ocean_ruin_warm": "Ruínas Submarinas Quente", 61 | "structure.minecraft.pillager_outpost": "Posto Avançado de Saqueadores", 62 | "structure.minecraft.ruined_portal": "Portal em Ruínas", 63 | "structure.minecraft.ruined_portal_desert": "Portal em Ruínas do Deserto", 64 | "structure.minecraft.ruined_portal_jungle": "Portal em Ruínas da Selva", 65 | "structure.minecraft.ruined_portal_mountain": "Portal em Ruínas da Montanha", 66 | "structure.minecraft.ruined_portal_nether": "Portal em Ruínas do Nether", 67 | "structure.minecraft.ruined_portal_ocean": "Portal em Ruínas do Oceano", 68 | "structure.minecraft.ruined_portal_swamp": "Portal em Ruínas do Pântano", 69 | "structure.minecraft.shipwreck": "Naufrágio", 70 | "structure.minecraft.shipwreck_beached": "Naufrágio Encalhado", 71 | "structure.minecraft.stronghold": "Fortaleza", 72 | "structure.minecraft.swamp_hut": "Cabana do Pântano", 73 | "structure.minecraft.village": "Vila", 74 | "structure.minecraft.village_desert": "Vila do Deserto", 75 | "structure.minecraft.village_plains": "Vila das Planícies", 76 | "structure.minecraft.village_savanna": "Vila da Savana", 77 | "structure.minecraft.village_snowy": "Vila da Neve", 78 | "structure.minecraft.village_taiga": "Vila da Taiga" 79 | } -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Языковой файл — Explorer's Compass", 3 | "_comment": "RUSSIAN FEDERATION — РУССКИЙ ЯЗЫК", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Компас исследователя", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "Назад", 10 | "string.explorerscompass.searchForGroup": "Поиск группы", 11 | "string.explorerscompass.selectStructure": "Выбрать структуру", 12 | "string.explorerscompass.teleport": "Телепортироваться", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "Структура", 16 | "string.explorerscompass.category": "Категория", 17 | "string.explorerscompass.coordinates": "Координаты", 18 | "string.explorerscompass.dimension": "Измерение", 19 | "string.explorerscompass.distance": "Расстояние", 20 | "string.explorerscompass.found": "Найдено", 21 | "string.explorerscompass.group": "Группа", 22 | "string.explorerscompass.name": "Название", 23 | "string.explorerscompass.notFound": "Не найдено", 24 | "string.explorerscompass.radius": "Радиус", 25 | "string.explorerscompass.samples": "Список", 26 | "string.explorerscompass.search": "Поиск", 27 | "string.explorerscompass.searching": "Идёт поиск…", 28 | "string.explorerscompass.sortBy": "Сортировка", 29 | "string.explorerscompass.source": "Добавлен", 30 | "string.explorerscompass.status": "Статус", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Первичная генерация", 34 | "string.explorerscompass.lakes": "Озера", 35 | "string.explorerscompass.local_modifications": "Локальные изменения", 36 | "string.explorerscompass.underground_structures": "Подземные структуры", 37 | "string.explorerscompass.surface_structures": "Поверхностный структуры", 38 | "string.explorerscompass.strongholds": "Крепости", 39 | "string.explorerscompass.underground_ores": "Руды", 40 | "string.explorerscompass.underground_decoration": "Подземные декорации", 41 | "string.explorerscompass.vegetal_decoration": "Растительность", 42 | "string.explorerscompass.top_layer_modification": "Верхний слой", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "Развалины бастиона", 46 | "structure.minecraft.buried_treasure": "Зарытый клад", 47 | "structure.minecraft.desert_pyramid": "Пустынная пирамида", 48 | "structure.minecraft.endcity": "Город Энда", 49 | "structure.minecraft.end_city": "Город Энда", 50 | "structure.minecraft.fortress": "Крепость Незера", 51 | "structure.minecraft.igloo": "Иглу", 52 | "structure.minecraft.jungle_pyramid": "Пирамида в джунглях", 53 | "structure.minecraft.mansion": "Особняк", 54 | "structure.minecraft.mineshaft": "Заброшенная шахта", 55 | "structure.minecraft.mineshaft_mesa": "Шахты в бесплодных землях", 56 | "structure.minecraft.monument": "Океанский монумент", 57 | "structure.minecraft.nether_fossil": "Ископаемые останки в Незере", 58 | "structure.minecraft.ocean_ruin": "Подводные руины", 59 | "structure.minecraft.ocean_ruin_cold": "Руины холодного океана", 60 | "structure.minecraft.ocean_ruin_warm": "Руины тепловатого океана", 61 | "structure.minecraft.pillager_outpost": "Аванпост разбойников", 62 | "structure.minecraft.ruined_portal": "Разрушенный портал", 63 | "structure.minecraft.ruined_portal_desert": "Разрушенный пустынный портал", 64 | "structure.minecraft.ruined_portal_jungle": "Разрушенный портал в джунглях", 65 | "structure.minecraft.ruined_portal_mountain": "Разрушенный портал в горах", 66 | "structure.minecraft.ruined_portal_nether": "Разрушенный портал в Незере", 67 | "structure.minecraft.ruined_portal_ocean": "Разрушенный портал в океане", 68 | "structure.minecraft.ruined_portal_swamp": "Разрушенный портал в болоте", 69 | "structure.minecraft.shipwreck": "Затонувший корабль", 70 | "structure.minecraft.shipwreck_beached": "Затонувший корабль на пляже", 71 | "structure.minecraft.stronghold": "Крепость в Энд", 72 | "structure.minecraft.swamp_hut": "Хижина ведьмы", 73 | "structure.minecraft.village": "Деревня", 74 | "structure.minecraft.village_desert": "Пустынная деревня", 75 | "structure.minecraft.village_plains": "Равнинная деревня", 76 | "structure.minecraft.village_savanna": "Саванная деревня", 77 | "structure.minecraft.village_snowy": "Заснеженная деревня", 78 | "structure.minecraft.village_taiga": "Таёжная деревня" 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "结构罗盘 - 语言文件", 3 | "_comment": "中国大陆 - 简体中文", 4 | 5 | "_comment": "物品", 6 | "item.explorerscompass.explorerscompass": "结构罗盘", 7 | 8 | "_comment": "字符串 - 按钮", 9 | "string.explorerscompass.back": "返回", 10 | "string.explorerscompass.searchForGroup": "搜索组", 11 | "string.explorerscompass.selectStructure": "选择结构", 12 | "string.explorerscompass.teleport": "传送", 13 | 14 | "_comment": "字符串 - 用户界面", 15 | "string.explorerscompass.structure": "结构", 16 | "string.explorerscompass.category": "类别", 17 | "string.explorerscompass.coordinates": "坐标", 18 | "string.explorerscompass.dimension": "维度", 19 | "string.explorerscompass.distance": "距离", 20 | "string.explorerscompass.found": "已找到", 21 | "string.explorerscompass.group": "组", 22 | "string.explorerscompass.name": "名称", 23 | "string.explorerscompass.notFound": "未找到", 24 | "string.explorerscompass.radius": "半径", 25 | "string.explorerscompass.samples": "样本范围", 26 | "string.explorerscompass.search": "搜索", 27 | "string.explorerscompass.searching": "正在搜索", 28 | "string.explorerscompass.sortBy": "排序方式", 29 | "string.explorerscompass.source": "来源", 30 | "string.explorerscompass.status": "状态", 31 | 32 | "_comment": "字符串 - 类别", 33 | "string.explorerscompass.raw_generation": "原始生成", 34 | "string.explorerscompass.lakes": "湖泊", 35 | "string.explorerscompass.local_modifications": "本地修改", 36 | "string.explorerscompass.underground_structures": "地下结构", 37 | "string.explorerscompass.surface_structures": "地表结构", 38 | "string.explorerscompass.strongholds": "地牢", 39 | "string.explorerscompass.underground_ores": "地下矿物", 40 | "string.explorerscompass.underground_decoration": "地下装饰", 41 | "string.explorerscompass.vegetal_decoration": "植被", 42 | "string.explorerscompass.top_layer_modification": "顶层", 43 | 44 | "_comment": "字符串 - 结构", 45 | "structure.minecraft.ancient_city": "远古城市", 46 | "structure.minecraft.bastion_remnant": "堡垒遗迹", 47 | "structure.minecraft.buried_treasure": "埋藏的宝藏", 48 | "structure.minecraft.desert_pyramid": "沙漠神殿", 49 | "structure.minecraft.end_city": "末地城", 50 | "structure.minecraft.endcity": "末地城", 51 | "structure.minecraft.fortress": "下界要塞", 52 | "structure.minecraft.igloo": "雪屋", 53 | "structure.minecraft.jungle_pyramid": "丛林神庙", 54 | "structure.minecraft.mansion": "林地府邸", 55 | "structure.minecraft.mineshaft": "废弃矿井", 56 | "structure.minecraft.mineshaft_mesa": "平顶山废弃矿井", 57 | "structure.minecraft.monument": "海底神殿", 58 | "structure.minecraft.nether_fossil": "下界化石", 59 | "structure.minecraft.ocean_ruin": "海底废墟", 60 | "structure.minecraft.ocean_ruin_cold": "冷水海底废墟", 61 | "structure.minecraft.ocean_ruin_warm": "温水海底废墟", 62 | "structure.minecraft.pillager_outpost": "掠夺者前哨站", 63 | "structure.minecraft.ruined_portal": "废弃传送门", 64 | "structure.minecraft.ruined_portal_desert": "沙漠废弃传送门", 65 | "structure.minecraft.ruined_portal_jungle": "丛林废弃传送门", 66 | "structure.minecraft.ruined_portal_mountain": "山地废弃传送门", 67 | "structure.minecraft.ruined_portal_nether": "下界废弃传送门", 68 | "structure.minecraft.ruined_portal_ocean": "海洋废弃传送门", 69 | "structure.minecraft.ruined_portal_swamp": "沼泽废弃传送门", 70 | "structure.minecraft.shipwreck": "沉船", 71 | "structure.minecraft.shipwreck_beached": "海滩沉船", 72 | "structure.minecraft.stronghold": "要塞", 73 | "structure.minecraft.swamp_hut": "沼泽小屋", 74 | "structure.minecraft.trail_ruins": "古迹废墟", 75 | "structure.minecraft.village": "村庄", 76 | "structure.minecraft.village_desert": "沙漠村庄", 77 | "structure.minecraft.village_plains": "平原村庄", 78 | "structure.minecraft.village_savanna": "热带草原村庄", 79 | "structure.minecraft.village_snowy": "雪原村庄", 80 | "structure.minecraft.village_taiga": "针叶林村庄" 81 | } 82 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/lang/zh_tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Explorer's Compass - Language File", 3 | "_comment": "TAIWAN - CHINESE", 4 | 5 | "_comment": "ITEMS", 6 | "item.explorerscompass.explorerscompass": "Explorer's Compass", 7 | 8 | "_comment": "STRINGS - BUTTONS", 9 | "string.explorerscompass.back": "返回", 10 | "string.explorerscompass.searchForGroup": "搜索組", 11 | "string.explorerscompass.selectStructure": "選擇結構", 12 | "string.explorerscompass.teleport": "傳送", 13 | 14 | "_comment": "STRINGS - GUI", 15 | "string.explorerscompass.structure": "結構", 16 | "string.explorerscompass.category": "類別", 17 | "string.explorerscompass.coordinates": "座標", 18 | "string.explorerscompass.dimension": "維度", 19 | "string.explorerscompass.distance": "距離", 20 | "string.explorerscompass.found": "已發現", 21 | "string.explorerscompass.group": "團體", 22 | "string.explorerscompass.name": "名稱", 23 | "string.explorerscompass.notFound": "未發現", 24 | "string.explorerscompass.radius": "半徑", 25 | "string.explorerscompass.samples": "樣本", 26 | "string.explorerscompass.search": "搜尋", 27 | "string.explorerscompass.searching": "正在搜尋", 28 | "string.explorerscompass.sortBy": "排序方式", 29 | "string.explorerscompass.source": "來源", 30 | "string.explorerscompass.status": "狀態", 31 | 32 | "_comment": "STRINGS - CATEGORIES", 33 | "string.explorerscompass.raw_generation": "Raw Generation", 34 | "string.explorerscompass.lakes": "湖泊", 35 | "string.explorerscompass.local_modifications": "Local Modifications", 36 | "string.explorerscompass.underground_structures": "地下", 37 | "string.explorerscompass.surface_structures": "地表", 38 | "string.explorerscompass.strongholds": "要塞", 39 | "string.explorerscompass.underground_ores": "礦", 40 | "string.explorerscompass.underground_decoration": "地下", 41 | "string.explorerscompass.vegetal_decoration": "Vegetation", 42 | "string.explorerscompass.top_layer_modification": "Top Layer", 43 | 44 | "_comment": "STRINGS - STRUCTURES", 45 | "structure.minecraft.bastion_remnant": "堡壘遺跡", 46 | "structure.minecraft.buried_treasure": "寶藏", 47 | "structure.minecraft.desert_pyramid": "沙漠金字塔", 48 | "structure.minecraft.endcity": "終末都市", 49 | "structure.minecraft.end_city": "終末都市", 50 | "structure.minecraft.fortress": "地獄要塞", 51 | "structure.minecraft.igloo": "雪屋", 52 | "structure.minecraft.jungle_pyramid": "叢林神廟", 53 | "structure.minecraft.mansion": "林地府邸", 54 | "structure.minecraft.mineshaft": "礦坑", 55 | "structure.minecraft.mineshaft_mesa": "礦井檯面", 56 | "structure.minecraft.monument": "海底廢墟", 57 | "structure.minecraft.nether_fossil": "地獄化石", 58 | "structure.minecraft.ocean_ruin": "海底廢墟", 59 | "structure.minecraft.ocean_ruin_cold": "海洋遺跡寒冷", 60 | "structure.minecraft.ocean_ruin_warm": "海洋廢墟溫暖", 61 | "structure.minecraft.pillager_outpost": "掠奪者前哨站", 62 | "structure.minecraft.ruined_portal": "廢棄傳送門", 63 | "structure.minecraft.ruined_portal_desert": "被破壞的傳送門沙漠", 64 | "structure.minecraft.ruined_portal_jungle": "Д被破壞的傳送門叢林", 65 | "structure.minecraft.ruined_portal_mountain": "破敗的傳送門山", 66 | "structure.minecraft.ruined_portal_nether": "被破壞的傳送門下界", 67 | "structure.minecraft.ruined_portal_ocean": "被破壞的傳送門海洋", 68 | "structure.minecraft.ruined_portal_swamp": "被破壞的傳送門沼澤", 69 | "structure.minecraft.shipwreck": "沉船", 70 | "structure.minecraft.shipwreck_beached": "沉船擱淺", 71 | "structure.minecraft.stronghold": "要塞", 72 | "structure.minecraft.swamp_hut": "沼澤小屋", 73 | "structure.minecraft.village": "村莊", 74 | "structure.minecraft.village_desert": "村莊沙漠", 75 | "structure.minecraft.village_plains": "鄉村平原", 76 | "structure.minecraft.village_savanna": "村莊稀樹草原", 77 | "structure.minecraft.village_snowy": "Д雪村", 78 | "structure.minecraft.village_taiga": "大河村" 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_00.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_00" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_01.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_01" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_02.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_02" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_03.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_03" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_04.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_04" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_05.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_05" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_06.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_06" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_07.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_07" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_08.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_08" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_09.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_09" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_10.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_10" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_11.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_11" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_12.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_12" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_13.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_13" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_14.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_14" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_15.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_15" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_16.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_16" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_17.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_17" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_18.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_18" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_19.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_19" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_20.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_20" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_21.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_21" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_22.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_22" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_23.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_23" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_24.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_24" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_25.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_25" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_26.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_26" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_27.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_27" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_28.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_28" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_29.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_29" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_30.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_30" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/models/item/explorerscompass_31.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "explorerscompass:item/explorerscompass_31" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_00.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_01.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_02.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_03.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_04.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_05.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_06.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_07.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_08.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_09.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_10.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_11.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_12.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_13.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_14.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_15.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_16.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_17.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_18.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_19.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_20.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_21.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_22.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_23.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_24.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_25.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_26.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_27.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_28.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_29.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_30.png -------------------------------------------------------------------------------- /src/main/resources/assets/explorerscompass/textures/item/explorerscompass_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCzyr/ExplorersCompass/d2c42ba0d9929f8e2dd5b21f5818f0129089049f/src/main/resources/assets/explorerscompass/textures/item/explorerscompass_31.png -------------------------------------------------------------------------------- /src/main/resources/data/explorerscompass/advancement/recipes/explorers_compass.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:recipes/root", 3 | "criteria": { 4 | "has_item": { 5 | "trigger": "minecraft:inventory_changed", 6 | "conditions": { 7 | "items": [ 8 | { 9 | "items": [ 10 | "minecraft:compass" 11 | ] 12 | } 13 | ] 14 | } 15 | }, 16 | "has_recipe": { 17 | "trigger": "minecraft:recipe_unlocked", 18 | "conditions": { 19 | "recipe": "explorerscompass:explorers_compass" 20 | } 21 | } 22 | }, 23 | "requirements": [ 24 | [ 25 | "has_item", 26 | "has_recipe" 27 | ] 28 | ], 29 | "rewards": { 30 | "recipes": [ 31 | "explorerscompass:explorers_compass" 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/resources/data/explorerscompass/recipe/explorers_compass.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "crafting_shaped", 3 | "group": "tools", 4 | "pattern": [ 5 | "WSW", 6 | "SCS", 7 | "WSW" 8 | ], 9 | "key": { 10 | "W": "minecraft:cobweb", 11 | "S": "minecraft:cracked_stone_bricks", 12 | "C": "minecraft:compass" 13 | }, 14 | "result": { 15 | "id": "explorerscompass:explorerscompass" 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/items/compasses.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "explorerscompass:explorerscompass" 5 | ] 6 | } -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Explorer's Compass resources", 4 | "pack_format": 55 5 | } 6 | } 7 | --------------------------------------------------------------------------------