A Minecraft server-side mod that adds various teleportation related commands
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add NeoForge support!

Added support for NeoForge and did some cleanup with the commands

+1338 -883
+6 -4
.github/workflows/build.yml
··· 12 12 matrix: 13 13 # Use these Java versions 14 14 java: [ 15 - 21, # Currently min for minecraft 15 + 17, # Currently min for minecraft 16 16 ] 17 17 runs-on: ubuntu-22.04 18 18 steps: ··· 24 24 uses: actions/setup-java@v4 25 25 with: 26 26 java-version: ${{ matrix.java }} 27 - distribution: 'temurin' 27 + distribution: temurin 28 28 - name: make gradle wrapper executable 29 29 run: chmod +x ./gradlew 30 30 - name: build 31 31 run: ./gradlew build 32 32 - name: capture build artifacts 33 - if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java 33 + if: ${{ matrix.java == '17' }} # Only upload artifacts built from latest java 34 34 uses: actions/upload-artifact@v4 35 35 with: 36 36 name: Artifacts 37 - path: build/libs/ 37 + path: | 38 + */build/libs 39 + if-no-files-found: error
+7 -24
.gitignore
··· 1 1 # gradle 2 - 3 2 .gradle/ 4 3 build/ 5 4 out/ 6 5 classes/ 7 6 8 - # eclipse 9 - 10 - *.launch 11 - 12 7 # idea 13 - 14 - .idea/ 15 - *.iml 8 + out 16 9 *.ipr 17 10 *.iws 11 + *.iml 12 + .idea/* 13 + !.idea/scopes 18 14 19 - # vscode 20 - 21 - .settings/ 22 - .vscode/ 23 - bin/ 24 - .classpath 25 - .project 26 - 27 - # macos 28 - 29 - *.DS_Store 30 - 31 - # fabric 32 - 33 - run/ 15 + # other 16 + run 17 + runs 34 18 35 19 # java 36 - 37 20 hs_err_*.log 38 21 replay_*.log 39 22 *.hprof
+1 -1
README.md
··· 1 1 # Teleport Commands <img src="https://raw.githubusercontent.com/MrSn0wy/TeleportCommands/main/src/main/resources/assets/teleport_commands/icon.png" alt="Teleport Commands Logo" width="30"/> 2 2 3 3 4 - A Minecraft fabric server-side mod that adds various teleportation related commands, like /home /tpa and /back 4 + A Minecraft Fabric and NeoForge server-side mod that adds various teleportation related commands, like /home /tpa and /back 5 5 6 6 ### This mod is still in beta, if there are any problems then let me know! 7 7
+3 -85
build.gradle
··· 1 - plugins { 2 - id 'fabric-loom' version '1.6-SNAPSHOT' 3 - id 'maven-publish' 4 - } 5 - 6 - version = project.mod_version 7 - group = project.maven_group 8 - 9 - base { 10 - archivesName = project.archives_base_name 11 - } 12 - 13 - repositories { 14 - // Add repositories to retrieve artifacts from in here. 15 - // You should only use this when depending on other mods because 16 - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 17 - // See https://docs.gradle.org/current/userguide/declaring_repositories.html 18 - // for more information about repositories. 19 - } 20 - 21 - loom { 22 - splitEnvironmentSourceSets() 23 - 24 - mods { 25 - "teleport_commands" { 26 - sourceSet sourceSets.main 27 - } 28 - } 29 - 30 - } 31 - 32 - dependencies { 33 - // To change the versions see the gradle.properties file 34 - minecraft "com.mojang:minecraft:${project.minecraft_version}" 35 - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 36 - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 37 - 38 - // Fabric API. This is technically optional, but you probably want it anyway. 39 - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 40 - 41 - } 42 - 43 - processResources { 44 - inputs.property "version", project.version 45 - 46 - filesMatching("fabric.mod.json") { 47 - expand "version": project.version 48 - } 49 - } 50 - 51 - tasks.withType(JavaCompile).configureEach { 52 - it.options.release = 17 53 - } 54 - 55 - java { 56 - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 57 - // if it is present. 58 - // If you remove this line, sources will not be generated. 59 - withSourcesJar() 60 - 61 - sourceCompatibility = JavaVersion.VERSION_17 62 - targetCompatibility = JavaVersion.VERSION_17 63 - } 64 - 65 - jar { 66 - from("LICENSE") { 67 - rename { "${it}_${project.base.archivesName.get()}"} 68 - } 69 - } 70 - 71 - // configure the maven publication 72 - publishing { 73 - publications { 74 - create("mavenJava", MavenPublication) { 75 - from components.java 76 - } 77 - } 78 - 79 - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 80 - repositories { 81 - // Add repositories to publish to here. 82 - // Notice: This block does NOT have the same function as the block in the top level. 83 - // The repositories here will be used for publishing your artifact, not for 84 - // retrieving dependencies. 85 - } 1 + plugins { 2 + // Required for NeoGradle 3 + id "org.jetbrains.gradle.plugin.idea-ext" version "1.1.7" 86 4 }
+3
buildSrc/build.gradle
··· 1 + plugins { 2 + id 'groovy-gradle-plugin' 3 + }
+111
buildSrc/src/main/groovy/multiloader-common.gradle
··· 1 + plugins { 2 + id 'java-library' 3 + id 'maven-publish' 4 + } 5 + 6 + base { 7 + archivesName = "${mod_id}-${project.name}-${minecraft_version}" 8 + } 9 + 10 + java { 11 + toolchain.languageVersion = JavaLanguageVersion.of(java_version) 12 + withSourcesJar() 13 + withJavadocJar() 14 + } 15 + 16 + repositories { 17 + mavenCentral() 18 + // https://docs.gradle.org/current/userguide/declaring_repositories.html#declaring_content_exclusively_found_in_one_repository 19 + exclusiveContent { 20 + forRepository { 21 + maven { 22 + name = 'Sponge' 23 + url = 'https://repo.spongepowered.org/repository/maven-public' 24 + } 25 + } 26 + filter { includeGroupAndSubgroups("org.spongepowered") } 27 + } 28 + maven { 29 + name = 'BlameJared' 30 + url = 'https://maven.blamejared.com' 31 + } 32 + } 33 + 34 + dependencies { 35 + implementation 'org.jetbrains:annotations:24.1.0' 36 + } 37 + 38 + // Declare capabilities on the outgoing configurations. 39 + // Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component 40 + ['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> 41 + configurations."$variant".outgoing { 42 + capability("$group:$mod_id-${project.name}-${minecraft_version}:$version") 43 + capability("$group:$mod_id:$version") 44 + } 45 + publishing.publications.configureEach { 46 + suppressPomMetadataWarningsFor(variant) 47 + } 48 + } 49 + 50 + sourcesJar { 51 + from(rootProject.file("LICENSE")) { 52 + rename { "${it}_${mod_name}" } 53 + } 54 + } 55 + 56 + jar { 57 + from(rootProject.file("LICENSE")) { 58 + rename { "${it}_${mod_name}" } 59 + } 60 + 61 + manifest { 62 + attributes([ 63 + 'Specification-Title' : mod_name, 64 + 'Specification-Vendor' : mod_author, 65 + 'Specification-Version' : project.jar.archiveVersion, 66 + 'Implementation-Title' : project.name, 67 + 'Implementation-Version': project.jar.archiveVersion, 68 + 'Implementation-Vendor' : mod_author, 69 + 'Built-On-Minecraft' : minecraft_version 70 + ]) 71 + } 72 + } 73 + 74 + processResources { 75 + def expandProps = [ 76 + "version": version, 77 + "group": project.group, //Else we target the task's group. 78 + "minecraft_version": minecraft_version, 79 + "minecraft_version_range": minecraft_version_range, 80 + "fabric_version": fabric_version, 81 + "fabric_loader_version": fabric_loader_version, 82 + "mod_name": mod_name, 83 + "mod_author": mod_author, 84 + "mod_id": mod_id, 85 + "license": license, 86 + "description": project.description, 87 + "neoforge_version": neoforge_version, 88 + "neoforge_loader_version_range": neoforge_loader_version_range, 89 + "credits": credits, 90 + "java_version": java_version 91 + ] 92 + 93 + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', '*.mixins.json']) { 94 + expand expandProps 95 + } 96 + inputs.properties(expandProps) 97 + } 98 + 99 + publishing { 100 + publications { 101 + register('mavenJava', MavenPublication) { 102 + artifactId base.archivesName.get() 103 + from components.java 104 + } 105 + } 106 + repositories { 107 + maven { 108 + url System.getenv("local_maven_url") 109 + } 110 + } 111 + }
+44
buildSrc/src/main/groovy/multiloader-loader.gradle
··· 1 + plugins { 2 + id 'multiloader-common' 3 + } 4 + 5 + configurations { 6 + commonJava{ 7 + canBeResolved = true 8 + } 9 + commonResources{ 10 + canBeResolved = true 11 + } 12 + } 13 + 14 + dependencies { 15 + compileOnly(project(':common')) { 16 + capabilities { 17 + requireCapability "$group:$mod_id" 18 + } 19 + } 20 + commonJava project(path: ':common', configuration: 'commonJava') 21 + commonResources project(path: ':common', configuration: 'commonResources') 22 + } 23 + 24 + tasks.named('compileJava', JavaCompile) { 25 + dependsOn(configurations.commonJava) 26 + source(configurations.commonJava) 27 + } 28 + 29 + processResources { 30 + dependsOn(configurations.commonResources) 31 + from(configurations.commonResources) 32 + } 33 + 34 + tasks.named('javadoc', Javadoc).configure { 35 + dependsOn(configurations.commonJava) 36 + source(configurations.commonJava) 37 + } 38 + 39 + tasks.named("sourcesJar", Jar) { 40 + dependsOn(configurations.commonJava) 41 + from(configurations.commonJava) 42 + dependsOn(configurations.commonResources) 43 + from(configurations.commonResources) 44 + }
+33
common/build.gradle
··· 1 + plugins { 2 + id 'multiloader-common' 3 + id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' 4 + } 5 + 6 + minecraft { 7 + version(minecraft_version) 8 + def aw = file("src/main/resources/${mod_id}.accesswidener") 9 + if(aw.exists()){ 10 + accessWideners(aw) 11 + } 12 + } 13 + 14 + dependencies { 15 + compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5' 16 + } 17 + 18 + configurations { 19 + commonJava { 20 + canBeResolved = false 21 + canBeConsumed = true 22 + } 23 + commonResources { 24 + canBeResolved = false 25 + canBeConsumed = true 26 + } 27 + } 28 + 29 + artifacts { 30 + commonJava sourceSets.main.java.sourceDirectories.singleFile 31 + commonResources sourceSets.main.resources.sourceDirectories.singleFile 32 + } 33 +
+57
common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java
··· 1 + package dev.mrsnowy.teleport_commands; 2 + 3 + import dev.mrsnowy.teleport_commands.storage.StorageManager; 4 + import dev.mrsnowy.teleport_commands.commands.*; 5 + import net.minecraft.commands.Commands; 6 + import net.minecraft.server.MinecraftServer; 7 + import net.minecraft.server.level.ServerPlayer; 8 + import net.minecraft.world.level.storage.LevelResource; 9 + import org.slf4j.Logger; 10 + import org.slf4j.LoggerFactory; 11 + import java.nio.file.Path; 12 + import java.nio.file.Paths; 13 + import java.util.Objects; 14 + 15 + import static dev.mrsnowy.teleport_commands.utils.tools.DeathLocationUpdater; 16 + 17 + public class TeleportCommands { 18 + 19 + public static final String MOD_ID = "teleport_commands"; 20 + public static final String MOD_NAME = "Teleport Commands"; 21 + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); 22 + public static String MOD_LOADER; 23 + public static Path SAVE_DIR; 24 + public static Path CONFIG_DIR; 25 + public static MinecraftServer Server; 26 + 27 + public static void initializeMod(MinecraftServer server, String ModLoader) { 28 + // initialize da variables 29 + 30 + MOD_LOADER = ModLoader; 31 + 32 + SAVE_DIR = Path.of(String.valueOf(server.getWorldPath(LevelResource.ROOT))); 33 + 34 + // Construct the game directory path 35 + CONFIG_DIR = Paths.get(System.getProperty("user.dir")).resolve("config"); 36 + 37 + Server = server; 38 + 39 + // initialize commands, also allows me to easily disable any when there is a config 40 + Commands commandManager = server.getCommands(); 41 + back.register(commandManager); 42 + home.register(commandManager); 43 + tpa.register(commandManager); 44 + 45 + StorageManager.StorageInit(); 46 + } 47 + 48 + public static void onPlayerDeath(ServerPlayer player) { 49 + try { 50 + // update /back command position 51 + DeathLocationUpdater(player.position(), player.serverLevel(), player.getStringUUID()); 52 + 53 + } catch (Exception e) { 54 + throw new RuntimeException(e); 55 + } 56 + } 57 + }
+60
common/src/main/java/dev/mrsnowy/teleport_commands/commands/back.java
··· 1 + package dev.mrsnowy.teleport_commands.commands; 2 + 3 + import dev.mrsnowy.teleport_commands.TeleportCommands; 4 + import dev.mrsnowy.teleport_commands.storage.StorageManager; 5 + import java.util.Objects; 6 + import net.minecraft.ChatFormatting; 7 + import net.minecraft.commands.Commands; 8 + import net.minecraft.network.chat.Component; 9 + import net.minecraft.server.level.ServerLevel; 10 + import net.minecraft.server.level.ServerPlayer; 11 + import net.minecraft.world.phys.Vec3; 12 + 13 + import static dev.mrsnowy.teleport_commands.storage.StorageManager.GetPlayerStorage; 14 + import static dev.mrsnowy.teleport_commands.utils.tools.Teleporter; 15 + 16 + public class back { 17 + 18 + public static void register(Commands commandManager) { 19 + 20 + commandManager.getDispatcher().register(Commands.literal("back").executes(context -> { 21 + ServerPlayer player = context.getSource().getPlayer(); 22 + 23 + if (player == null) { 24 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 25 + return 1; 26 + } 27 + 28 + try { 29 + player.displayClientMessage(Component.literal("Teleporting"), true); 30 + ToDeathLocation(player); 31 + } catch (Exception e) { 32 + TeleportCommands.LOGGER.error(String.valueOf(e)); 33 + player.displayClientMessage(Component.literal("Error Teleporting!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 34 + return 1; 35 + } 36 + return 0; 37 + })); 38 + } 39 + 40 + 41 + 42 + private static void ToDeathLocation(ServerPlayer player) throws Exception { 43 + StorageManager.StorageClass.Player playerStorage = GetPlayerStorage(player.getStringUUID()).playerStorage; 44 + 45 + Vec3 pos = new Vec3(playerStorage.deathLocation.x, playerStorage.deathLocation.y, playerStorage.deathLocation.z); 46 + 47 + boolean found = false; 48 + for (ServerLevel currentWorld : Objects.requireNonNull(player.getServer()).getAllLevels()) { 49 + if (Objects.equals(currentWorld.dimension().location().toString(), playerStorage.deathLocation.world)) { 50 + Teleporter(player, currentWorld, pos); 51 + found = true; 52 + break; 53 + } 54 + } 55 + 56 + if (!found) { 57 + player.displayClientMessage(Component.literal("No Location Found!"), true); 58 + } 59 + } 60 + }
+404
common/src/main/java/dev/mrsnowy/teleport_commands/commands/home.java
··· 1 + package dev.mrsnowy.teleport_commands.commands; 2 + 3 + import com.mojang.brigadier.arguments.StringArgumentType; 4 + import dev.mrsnowy.teleport_commands.TeleportCommands; 5 + import dev.mrsnowy.teleport_commands.storage.StorageManager; 6 + import dev.mrsnowy.teleport_commands.suggestions.HomesuggestionProvider; 7 + import java.util.Objects; 8 + import net.minecraft.ChatFormatting; 9 + import net.minecraft.commands.Commands; 10 + import net.minecraft.network.chat.ClickEvent; 11 + import net.minecraft.network.chat.Component; 12 + import net.minecraft.server.level.ServerLevel; 13 + import net.minecraft.server.level.ServerPlayer; 14 + import net.minecraft.world.phys.Vec3; 15 + 16 + import static net.minecraft.commands.Commands.argument; 17 + import static dev.mrsnowy.teleport_commands.storage.StorageManager.GetPlayerStorage; 18 + import static dev.mrsnowy.teleport_commands.storage.StorageManager.StorageSaver; 19 + import static dev.mrsnowy.teleport_commands.utils.tools.Teleporter; 20 + 21 + public class home { 22 + public static void register(Commands commandManager) { 23 + 24 + commandManager.getDispatcher().register(Commands.literal("sethome") 25 + .then(argument("name", StringArgumentType.string()) 26 + .executes(context -> { 27 + final String name = StringArgumentType.getString(context, "name"); 28 + ServerPlayer player = context.getSource().getPlayer(); 29 + 30 + if (player == null) { 31 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 32 + return 1; 33 + } 34 + 35 + try { 36 + player.displayClientMessage(Component.literal("Home Set"), true); 37 + SetHome(player, name); 38 + 39 + } catch (Exception e) { 40 + TeleportCommands.LOGGER.error(String.valueOf(e)); 41 + player.displayClientMessage(Component.literal("Error Setting Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 42 + return 1; 43 + } 44 + return 0; 45 + }))); 46 + 47 + 48 + commandManager.getDispatcher().register(Commands.literal("home") 49 + .executes(context -> { 50 + ServerPlayer player = context.getSource().getPlayer(); 51 + 52 + if (player == null) { 53 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 54 + return 1; 55 + } 56 + 57 + try { 58 + player.displayClientMessage(Component.literal("Going Home"), true); 59 + GoHome(player, ""); 60 + 61 + } catch (Exception e) { 62 + TeleportCommands.LOGGER.error(String.valueOf(e)); 63 + player.displayClientMessage(Component.literal("Error Going Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 64 + return 1; 65 + } 66 + return 0; 67 + }) 68 + .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 69 + .executes(context -> { 70 + final String name = StringArgumentType.getString(context, "name"); 71 + ServerPlayer player = context.getSource().getPlayer(); 72 + 73 + if (player == null) { 74 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 75 + return 1; 76 + } 77 + 78 + try { 79 + player.displayClientMessage(Component.literal("Going Home"), true); 80 + GoHome(player, name); 81 + 82 + } catch (Exception e) { 83 + player.displayClientMessage(Component.literal("Error Going Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 84 + TeleportCommands.LOGGER.error(String.valueOf(e)); 85 + return 1; 86 + } 87 + return 0; 88 + }))); 89 + 90 + commandManager.getDispatcher().register(Commands.literal("delhome") 91 + .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 92 + .executes(context -> { 93 + final String name = StringArgumentType.getString(context, "name"); 94 + ServerPlayer player = context.getSource().getPlayer(); 95 + 96 + if (player == null) { 97 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 98 + return 1; 99 + } 100 + 101 + try { 102 + player.displayClientMessage(Component.literal("Home Deleted"), true); 103 + DeleteHome(player, name); 104 + 105 + } catch (Exception e) { 106 + TeleportCommands.LOGGER.error(String.valueOf(e)); 107 + player.displayClientMessage(Component.literal("Error Deleting Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 108 + return 1; 109 + } 110 + return 0; 111 + }))); 112 + 113 + commandManager.getDispatcher().register(Commands.literal("renamehome") 114 + .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 115 + .then(argument("newName", StringArgumentType.string()) 116 + .executes(context -> { 117 + final String name = StringArgumentType.getString(context, "name"); 118 + final String newName = StringArgumentType.getString(context, "newName"); 119 + ServerPlayer player = context.getSource().getPlayer(); 120 + 121 + if (player == null) { 122 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 123 + return 1; 124 + } 125 + 126 + try { 127 + player.displayClientMessage(Component.literal("Home Renamed"), true); 128 + RenameHome(player, name, newName); 129 + } catch (Exception e) { 130 + TeleportCommands.LOGGER.error(String.valueOf(e)); 131 + player.displayClientMessage(Component.literal("Error Renaming Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 132 + return 1; 133 + } 134 + return 0; 135 + })))); 136 + 137 + 138 + commandManager.getDispatcher().register(Commands.literal("homes") 139 + .executes(context -> { 140 + ServerPlayer player = context.getSource().getPlayer(); 141 + 142 + if (player == null) { 143 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 144 + return 1; 145 + } 146 + 147 + try { 148 + PrintHomes(player); 149 + } catch (Exception e) { 150 + TeleportCommands.LOGGER.error(String.valueOf(e)); 151 + player.displayClientMessage(Component.literal("Error Getting Homes!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 152 + return 1; 153 + } 154 + return 0; 155 + })); 156 + 157 + commandManager.getDispatcher().register(Commands.literal("defaulthome") 158 + .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 159 + .executes(context -> { 160 + final String name = StringArgumentType.getString(context, "name"); 161 + ServerPlayer player = context.getSource().getPlayer(); 162 + 163 + if (player == null) { 164 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 165 + return 1; 166 + } 167 + 168 + try { 169 + SetDefaultHome(player, name); 170 + } catch (Exception e) { 171 + TeleportCommands.LOGGER.error(String.valueOf(e)); 172 + player.displayClientMessage(Component.literal("Error Changing Default Home!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); 173 + return 1; 174 + } 175 + return 0; 176 + }))); 177 + } 178 + 179 + 180 + 181 + private static void SetHome(ServerPlayer player, String homeName) throws Exception { 182 + homeName = homeName.toLowerCase(); 183 + Vec3 pos = player.position(); 184 + ServerLevel world = player.serverLevel(); 185 + 186 + StorageManager.PlayerStorageResult storages = GetPlayerStorage(player.getStringUUID()); 187 + StorageManager.StorageClass storage = storages.storage; 188 + StorageManager.StorageClass.Player playerStorage = storages.playerStorage; 189 + 190 + boolean homeNotFound = true; 191 + 192 + // check for duplicates 193 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 194 + if (Objects.equals(currentHome.name, homeName)) { 195 + homeNotFound = false; 196 + break; 197 + } 198 + } 199 + 200 + if (homeNotFound) { 201 + // Create a new Home 202 + StorageManager.StorageClass.Player.Home homeLocation = new StorageManager.StorageClass.Player.Home(); 203 + 204 + homeLocation.name = homeName; 205 + homeLocation.x = Double.parseDouble(String.format("%.1f", pos.x())); 206 + homeLocation.y = Double.parseDouble(String.format("%.1f", pos.y())); 207 + homeLocation.z = Double.parseDouble(String.format("%.1f", pos.z())); 208 + homeLocation.world = world.dimension().location().toString(); 209 + 210 + playerStorage.Homes.add(homeLocation); 211 + 212 + if (playerStorage.Homes.size() == 1) { 213 + playerStorage.DefaultHome = homeName; 214 + } 215 + 216 + StorageSaver(storage); 217 + } else { 218 + player.displayClientMessage(Component.literal("Home Already Exists!"), true); 219 + } 220 + } 221 + 222 + private static void GoHome(ServerPlayer player, String homeName) throws Exception { 223 + homeName = homeName.toLowerCase(); 224 + StorageManager.StorageClass.Player playerStorage = GetPlayerStorage(player.getStringUUID()).playerStorage; 225 + 226 + // check if there is a default exists 227 + if (homeName.isEmpty()) { 228 + if (playerStorage.DefaultHome.isEmpty()) { 229 + player.displayClientMessage(Component.literal("You Have No Homes!"), true); 230 + return; 231 + } else { 232 + homeName = playerStorage.DefaultHome; 233 + } 234 + } 235 + 236 + boolean foundHome = false; 237 + boolean foundWorld = false; 238 + 239 + // find correct home 240 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 241 + if (Objects.equals(currentHome.name, homeName)){ 242 + foundHome = true; 243 + 244 + // find correct world 245 + for (ServerLevel currentWorld : Objects.requireNonNull(player.getServer()).getAllLevels()) { 246 + if (Objects.equals(currentWorld.dimension().location().toString(), currentHome.world)) { 247 + Teleporter(player, currentWorld, new Vec3(currentHome.x, currentHome.y, currentHome.z)); 248 + foundWorld = true; 249 + break; 250 + } 251 + } 252 + } 253 + } 254 + 255 + if (!foundHome) { 256 + player.displayClientMessage(Component.literal("Home Not Found!"), true); 257 + } else if (!foundWorld) { 258 + player.displayClientMessage(Component.literal("World Not Found!"), true); 259 + } 260 + } 261 + 262 + private static void DeleteHome(ServerPlayer player, String homeName) throws Exception { 263 + homeName = homeName.toLowerCase(); 264 + StorageManager.PlayerStorageResult storages = GetPlayerStorage(player.getStringUUID()); 265 + StorageManager.StorageClass storage = storages.storage; 266 + StorageManager.StorageClass.Player playerStorage = storages.playerStorage; 267 + 268 + StorageManager.StorageClass.Player.Home homeToDelete = null; 269 + 270 + // get correct home 271 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 272 + if (Objects.equals(currentHome.name, homeName)){ 273 + homeToDelete = currentHome; 274 + break; 275 + } 276 + } 277 + 278 + if (Objects.nonNull(homeToDelete)) { 279 + playerStorage.Homes.remove(homeToDelete); 280 + StorageSaver(storage); 281 + } else { 282 + player.displayClientMessage(Component.literal("Home Not Found!"), true); 283 + } 284 + } 285 + 286 + private static void RenameHome(ServerPlayer player, String homeName, String newHomeName) throws Exception { 287 + homeName = homeName.toLowerCase(); 288 + newHomeName = newHomeName.toLowerCase(); 289 + 290 + StorageManager.PlayerStorageResult storages = GetPlayerStorage(player.getStringUUID()); 291 + StorageManager.StorageClass storage = storages.storage; 292 + StorageManager.StorageClass.Player playerStorage = storages.playerStorage; 293 + 294 + StorageManager.StorageClass.Player.Home homeToRename = null; 295 + boolean newNameNotFound = true; 296 + 297 + // check for duplicates 298 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 299 + if (Objects.equals(currentHome.name, newHomeName)) { 300 + newNameNotFound = false; 301 + break; 302 + } 303 + } 304 + 305 + if (newNameNotFound) { 306 + // get correct home 307 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 308 + if (Objects.equals(currentHome.name, homeName)){ 309 + homeToRename = currentHome; 310 + break; 311 + } 312 + } 313 + 314 + if (Objects.nonNull(homeToRename)) { 315 + if (Objects.equals(playerStorage.DefaultHome, homeToRename.name)) { 316 + playerStorage.DefaultHome = newHomeName; 317 + } 318 + 319 + homeToRename.name = newHomeName; 320 + StorageSaver(storage); 321 + } else { 322 + player.displayClientMessage(Component.literal("Home Not Found!"), true); 323 + } 324 + } else { 325 + player.displayClientMessage(Component.literal("Home Already Exists!"), true); 326 + } 327 + 328 + } 329 + 330 + private static void PrintHomes(ServerPlayer player) throws Exception { 331 + StorageManager.StorageClass.Player playerStorage = GetPlayerStorage(player.getStringUUID()).playerStorage; 332 + boolean anyHomes = false; 333 + 334 + for (StorageManager.StorageClass.Player.Home currenthome : playerStorage.Homes) { 335 + if (!anyHomes) { 336 + player.displayClientMessage(Component.literal("Homes: \n").withStyle(ChatFormatting.YELLOW, ChatFormatting.BOLD), false); 337 + anyHomes = true; 338 + } 339 + 340 + String name = String.format(" - %s", currenthome.name); 341 + String nameDefault = " (Default)"; 342 + 343 + 344 + String coords = String.format(" [X%.1f Y%.1f Z%.1f]", currenthome.x, currenthome.y, currenthome.z); 345 + String dimension = String.format(" [%s]", currenthome.world); 346 + 347 + if (Objects.equals(currenthome.name, playerStorage.DefaultHome)) { 348 + player.displayClientMessage(Component.literal(name).withStyle(ChatFormatting.AQUA) 349 + .append(Component.literal(nameDefault).withStyle(ChatFormatting.AQUA, ChatFormatting.BOLD)), 350 + false 351 + ); 352 + } else { 353 + player.displayClientMessage(Component.literal(name).withStyle(ChatFormatting.AQUA), false); 354 + } 355 + 356 + 357 + player.displayClientMessage(Component.literal(" |").withStyle(ChatFormatting.AQUA) 358 + .append(Component.literal(coords).withStyle(ChatFormatting.LIGHT_PURPLE).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, String.format("X%.2f Y%.2f Z%.2f", currenthome.x, currenthome.y, currenthome.z))))) 359 + .append(Component.literal(dimension).withStyle(ChatFormatting.DARK_PURPLE).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, currenthome.world)))), 360 + false 361 + ); 362 + 363 + player.displayClientMessage(Component.literal(" |").withStyle(ChatFormatting.AQUA) 364 + .append(Component.literal(" [Tp]").withStyle(ChatFormatting.GREEN).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/home %s", currenthome.name))))) 365 + .append(Component.literal(" [Rename]").withStyle(ChatFormatting.BLUE).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/renamehome %s ", currenthome.name))))) 366 + .append(Component.literal(" [Delete]\n").withStyle(ChatFormatting.RED).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/delhome %s", currenthome.name))))), 367 + false 368 + ); 369 + } 370 + 371 + if (!anyHomes) { 372 + player.displayClientMessage(Component.literal("No homes set"), true); 373 + } 374 + } 375 + 376 + private static void SetDefaultHome(ServerPlayer player, String homeName) throws Exception { 377 + homeName = homeName.toLowerCase(); 378 + StorageManager.PlayerStorageResult storages = GetPlayerStorage(player.getStringUUID()); 379 + StorageManager.StorageClass storage = storages.storage; 380 + StorageManager.StorageClass.Player playerStorage = storages.playerStorage; 381 + 382 + boolean homeExists = false; 383 + 384 + // check if home exists 385 + for (StorageManager.StorageClass.Player.Home currentHome : playerStorage.Homes) { 386 + if (Objects.equals(currentHome.name, homeName)){ 387 + homeExists = true; 388 + break; 389 + } 390 + } 391 + 392 + if (homeExists) { 393 + if (Objects.equals(playerStorage.DefaultHome, homeName)) { 394 + player.displayClientMessage(Component.literal("Home is already set as default!"), true); 395 + 396 + } else { 397 + playerStorage.DefaultHome = homeName; 398 + StorageSaver(storage); 399 + } 400 + } else { 401 + player.displayClientMessage(Component.literal("Home not found!"), true); 402 + } 403 + } 404 + }
+200
common/src/main/java/dev/mrsnowy/teleport_commands/commands/tpa.java
··· 1 + package dev.mrsnowy.teleport_commands.commands; 2 + 3 + import dev.mrsnowy.teleport_commands.TeleportCommands; 4 + import java.util.*; 5 + import net.minecraft.ChatFormatting; 6 + import net.minecraft.commands.Commands; 7 + import net.minecraft.commands.arguments.EntityArgument; 8 + import net.minecraft.network.chat.ClickEvent; 9 + import net.minecraft.network.chat.Component; 10 + import net.minecraft.server.level.ServerPlayer; 11 + 12 + import static dev.mrsnowy.teleport_commands.utils.tools.Teleporter; 13 + 14 + public class tpa { 15 + 16 + private static final ArrayList<tpaArrayClass> tpaList = new ArrayList<>(); 17 + 18 + private static class tpaArrayClass { 19 + private String InitPlayer; 20 + private String RecPlayer; 21 + private boolean here; 22 + } 23 + 24 + public static void register(Commands commandManager) { 25 + 26 + commandManager.getDispatcher().register(Commands.literal("tpa") 27 + .then(Commands.argument("player", EntityArgument.player()) 28 + .executes(context -> { 29 + final ServerPlayer TargetPlayer = EntityArgument.getPlayer(context, "player"); 30 + ServerPlayer player = context.getSource().getPlayer(); 31 + 32 + if (player == null) { 33 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 34 + return 1; 35 + } 36 + 37 + tpaCommandHandler(player, TargetPlayer, false); 38 + return 0; 39 + }))); 40 + 41 + commandManager.getDispatcher().register(Commands.literal("tpahere") 42 + .then(Commands.argument("player", EntityArgument.player()) 43 + .executes(context -> { 44 + final ServerPlayer TargetPlayer = EntityArgument.getPlayer(context, "player"); 45 + ServerPlayer player = context.getSource().getPlayer(); 46 + 47 + if (player == null) { 48 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 49 + return 1; 50 + } 51 + 52 + tpaCommandHandler(player, TargetPlayer, true); 53 + return 0; 54 + }))); 55 + 56 + commandManager.getDispatcher().register(Commands.literal("tpaaccept") 57 + .then(Commands.argument("player", EntityArgument.player()) 58 + .executes(context -> { 59 + final ServerPlayer TargetPlayer = EntityArgument.getPlayer(context, "player"); 60 + ServerPlayer player = context.getSource().getPlayer(); 61 + 62 + if (player == null) { 63 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 64 + return 1; 65 + } 66 + 67 + tpaAccept(player, TargetPlayer); 68 + return 0; 69 + }))); 70 + 71 + commandManager.getDispatcher().register(Commands.literal("tpadeny") 72 + .then(Commands.argument("player", EntityArgument.player()) 73 + .executes(context -> { 74 + final ServerPlayer TargetPlayer = EntityArgument.getPlayer(context, "player"); 75 + ServerPlayer player = context.getSource().getPlayer(); 76 + 77 + if (player == null) { 78 + TeleportCommands.LOGGER.error("Error while executing the command, No player found!"); 79 + return 1; 80 + } 81 + 82 + tpaDeny(player, TargetPlayer); 83 + return 0; 84 + }))); 85 + } 86 + 87 + 88 + 89 + private static void tpaCommandHandler(ServerPlayer FromPlayer, ServerPlayer ToPlayer, boolean here) { 90 + 91 + if (FromPlayer == ToPlayer) { 92 + FromPlayer.displayClientMessage(Component.literal("Well, that was easy").withStyle(ChatFormatting.AQUA),true); 93 + 94 + } else { 95 + String ToMessage; 96 + String FromMessage; 97 + 98 + // Store da request 99 + tpaArrayClass tpaRequest = new tpaArrayClass(); 100 + tpaRequest.InitPlayer = FromPlayer.getStringUUID(); 101 + tpaRequest.RecPlayer = ToPlayer.getStringUUID(); 102 + tpaRequest.here = here; 103 + tpaList.add(tpaRequest); 104 + 105 + if (here) { 106 + ToMessage = "TpaHere Request Received From "; 107 + FromMessage = "TpaHere Request Send to "; 108 + 109 + } else { 110 + ToMessage = "Tpa Request Received From "; 111 + FromMessage = "Tpa Request Send to "; 112 + } 113 + 114 + String ToPlayerString = Objects.requireNonNull(ToPlayer.getName().tryCollapseToString()); 115 + String FromPlayerString = Objects.requireNonNull(FromPlayer.getName().tryCollapseToString()); 116 + 117 + FromPlayer.displayClientMessage(Component.literal(FromMessage).withStyle(ChatFormatting.AQUA) 118 + .append(Component.literal(ToPlayerString).withStyle(ChatFormatting.AQUA, ChatFormatting.BOLD)) 119 + // .append(Text.literal("\n[Cancel]").formatted(Formatting.BLUE, Formatting.BOLD)) 120 + ,true 121 + ); 122 + 123 + ToPlayer.displayClientMessage(Component.literal(ToMessage).withStyle(ChatFormatting.AQUA) 124 + .append(Component.literal(FromPlayerString).withStyle(ChatFormatting.AQUA, ChatFormatting.BOLD)) 125 + .append(Component.literal("\n[Accept]").withStyle(ChatFormatting.GREEN, ChatFormatting.BOLD).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/tpaaccept %s", FromPlayerString))))) 126 + .append(Component.literal(" [Deny]").withStyle(ChatFormatting.RED, ChatFormatting.BOLD).withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/tpadeny %s", FromPlayerString))))), 127 + false 128 + ); 129 + 130 + Timer timer = new Timer(); 131 + timer.schedule( 132 + new TimerTask() { 133 + @Override 134 + public void run() { 135 + boolean successful = tpaList.remove(tpaRequest); 136 + if (successful) { 137 + if (here) { 138 + FromPlayer.displayClientMessage(Component.literal("TpaHere Request Expired").withStyle(ChatFormatting.AQUA),true); 139 + } else { 140 + FromPlayer.displayClientMessage(Component.literal("Tpa Request Expired").withStyle(ChatFormatting.AQUA),true); 141 + } 142 + } 143 + } 144 + }, 30 * 1000 145 + ); 146 + } 147 + } 148 + 149 + private static void tpaAccept(ServerPlayer FromPlayer, ServerPlayer ToPlayer) { 150 + if (FromPlayer == ToPlayer) { 151 + FromPlayer.displayClientMessage(Component.literal("Uhm.. no?").withStyle(ChatFormatting.AQUA),true); 152 + } else { 153 + Optional<tpaArrayClass> tpaStorage = tpaList.stream() 154 + .filter(tpa -> Objects.equals(ToPlayer.getStringUUID(), tpa.InitPlayer)) 155 + .filter(tpa -> Objects.equals(FromPlayer.getStringUUID(), tpa.RecPlayer)) 156 + .findFirst(); 157 + 158 + if (tpaStorage.isPresent()) { 159 + if (tpaStorage.get().here) { 160 + FromPlayer.displayClientMessage(Component.literal("Teleporting"),true); 161 + ToPlayer.displayClientMessage(Component.literal("Request Accepted"),true); 162 + 163 + Teleporter(FromPlayer, ToPlayer.serverLevel(), ToPlayer.position()); 164 + } else { 165 + ToPlayer.displayClientMessage(Component.literal("Teleporting"),true); 166 + FromPlayer.displayClientMessage(Component.literal("Request Accepted"),true); 167 + 168 + Teleporter(ToPlayer, FromPlayer.serverLevel(), FromPlayer.position()); 169 + } 170 + 171 + tpaList.remove(tpaStorage.get()); 172 + } else { 173 + FromPlayer.displayClientMessage(Component.literal("No Requests found!").withStyle(ChatFormatting.AQUA),true); 174 + } 175 + } 176 + } 177 + 178 + private static void tpaDeny(ServerPlayer FromPlayer, ServerPlayer ToPlayer) { 179 + if (FromPlayer == ToPlayer) { 180 + FromPlayer.displayClientMessage(Component.literal("Uhm.. no?").withStyle(ChatFormatting.AQUA),true); 181 + } else { 182 + Optional<tpaArrayClass> tpaStorage = tpaList.stream() 183 + .filter(tpa -> Objects.equals(ToPlayer.getStringUUID(), tpa.InitPlayer)) 184 + .filter(tpa -> Objects.equals(FromPlayer.getStringUUID(), tpa.RecPlayer)) 185 + .findFirst(); 186 + 187 + if (tpaStorage.isPresent()) { 188 + tpaList.remove(tpaStorage.get()); 189 + 190 + if (tpaStorage.get().here) { 191 + ToPlayer.displayClientMessage(Component.literal("Request Denied").withStyle(ChatFormatting.AQUA),true); 192 + } else { 193 + FromPlayer.displayClientMessage(Component.literal("Request Denied").withStyle(ChatFormatting.AQUA),true); 194 + } 195 + } else { 196 + FromPlayer.displayClientMessage(Component.literal("No Requests found!").withStyle(ChatFormatting.AQUA),true); 197 + } 198 + } 199 + } 200 + }
+6
common/src/main/java/dev/mrsnowy/teleport_commands/storage/configManager.java
··· 1 + package dev.mrsnowy.teleport_commands.storage; 2 + 3 + public class configManager { 4 + // Currently nothing to see here... yet 5 + 6 + }
+62
common/src/main/java/dev/mrsnowy/teleport_commands/utils/tools.java
··· 1 + package dev.mrsnowy.teleport_commands.utils; 2 + 3 + import dev.mrsnowy.teleport_commands.storage.StorageManager; 4 + import java.util.*; 5 + import net.minecraft.core.particles.ParticleTypes; 6 + import net.minecraft.server.level.ServerLevel; 7 + import net.minecraft.server.level.ServerPlayer; 8 + import net.minecraft.sounds.SoundEvent; 9 + import net.minecraft.sounds.SoundSource; 10 + import net.minecraft.world.phys.Vec3; 11 + 12 + import static dev.mrsnowy.teleport_commands.storage.StorageManager.GetPlayerStorage; 13 + import static dev.mrsnowy.teleport_commands.storage.StorageManager.StorageSaver; 14 + import static net.minecraft.sounds.SoundEvents.ENDERMAN_TELEPORT; 15 + 16 + public class tools { 17 + 18 + public static void Teleporter(ServerPlayer player, ServerLevel world, Vec3 coords) { 19 + world.sendParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() + 1, player.getZ(), 20, 0.0D, 0.0D, 0.0D, 0.01); 20 + world.sendParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 1.0D, 0.0D, 0.03); 21 + world.playSound(null, player.blockPosition(), SoundEvent.createVariableRangeEvent(ENDERMAN_TELEPORT.getLocation()), SoundSource.PLAYERS, 0.4f, 1.0f); 22 + 23 + var flying = player.getAbilities().flying; 24 + 25 + player.teleportTo(world, coords.x, coords.y, coords.z, player.getYRot(), player.getXRot()); 26 + 27 + // Restore flying when teleporting dimensions 28 + if (flying) { 29 + player.getAbilities().flying = true; 30 + player.onUpdateAbilities(); 31 + } 32 + 33 + world.playSound(null, player.blockPosition(), SoundEvent.createVariableRangeEvent(ENDERMAN_TELEPORT.getLocation()), SoundSource.PLAYERS, 0.4f, 1.0f); 34 + Timer timer = new Timer(); 35 + 36 + timer.schedule( 37 + new TimerTask() { 38 + @Override 39 + public void run() { 40 + world.sendParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() , player.getZ(), 20, 0.0D, 1.0D, 0.0D, 0.01); 41 + world.sendParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 0.0D, 0.0D, 0.03); 42 + } 43 + }, 100 // hopefully good, 2 ticks 44 + ); 45 + } 46 + 47 + 48 + 49 + public static void DeathLocationUpdater(Vec3 pos, ServerLevel world, String UUID) throws Exception { 50 + StorageManager.PlayerStorageResult storages = GetPlayerStorage(UUID); 51 + 52 + StorageManager.StorageClass storage = storages.storage; 53 + StorageManager.StorageClass.Player playerStorage = storages.playerStorage; 54 + 55 + playerStorage.deathLocation.x = Double.parseDouble(String.format("%.1f", pos.x())); 56 + playerStorage.deathLocation.y = Double.parseDouble(String.format("%.1f", pos.y())); 57 + playerStorage.deathLocation.z = Double.parseDouble(String.format("%.1f", pos.z())); 58 + playerStorage.deathLocation.world = world.dimension().location().toString(); 59 + 60 + StorageSaver(storage); 61 + } 62 + }
+6
common/src/main/resources/pack.mcmeta
··· 1 + { 2 + "pack": { 3 + "description": "${mod_name}", 4 + "pack_format": 8 5 + } 6 + }
+34
fabric/build.gradle
··· 1 + plugins { 2 + id 'multiloader-loader' 3 + id 'fabric-loom' version '1.6-SNAPSHOT' 4 + } 5 + dependencies { 6 + minecraft "com.mojang:minecraft:${minecraft_version}" 7 + mappings loom.officialMojangMappings() 8 + modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" 9 + modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" 10 + } 11 + 12 + loom { 13 + def aw = project(":common").file("src/main/resources/${mod_id}.accesswidener") 14 + if (aw.exists()) { 15 + accessWidenerPath.set(aw) 16 + } 17 + mixin { 18 + defaultRefmapName.set("${mod_id}.refmap.json") 19 + } 20 + runs { 21 + client { 22 + client() 23 + setConfigName("Fabric Client") 24 + ideConfigGenerated(true) 25 + runDir("runs/client") 26 + } 27 + server { 28 + server() 29 + setConfigName("Fabric Server") 30 + ideConfigGenerated(true) 31 + runDir("runs/server") 32 + } 33 + } 34 + }
+35
fabric/src/main/java/dev/mrsnowy/teleport_commands/fabricInit.java
··· 1 + package dev.mrsnowy.teleport_commands; 2 + 3 + import net.fabricmc.api.ModInitializer; 4 + import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; 5 + import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; 6 + import net.minecraft.server.level.ServerPlayer; 7 + 8 + import java.util.Objects; 9 + 10 + public class fabricInit implements ModInitializer { 11 + 12 + @Override 13 + public void onInitialize() { 14 + // This code runs as soon as Minecraft is in a mod-load-ready state. 15 + // However, some things (like resources) may still be uninitialized. 16 + // Proceed with mild caution. 17 + 18 + TeleportCommands.LOGGER.info("Teleport Commands loaded! Hello Fabric!"); 19 + 20 + // initialize the mod 21 + ServerLifecycleEvents.SERVER_STARTED.register((server) -> { 22 + TeleportCommands.initializeMod(server, "Fabric"); 23 + }); 24 + 25 + 26 + // check if it is a player and check if the player died 27 + ServerEntityEvents.ENTITY_UNLOAD.register((entity, world) -> { 28 + if (entity instanceof ServerPlayer player) { 29 + if (player.getRemovalReason() != null && (Objects.equals(player.getRemovalReason().toString(), "KILLED") || Objects.equals(player.getRemovalReason().toString(), "DISCARDED"))) { 30 + TeleportCommands.onPlayerDeath(player); 31 + } 32 + } 33 + }); 34 + } 35 + }
+41
fabric/src/main/resources/fabric.mod.json
··· 1 + { 2 + "schemaVersion": 1, 3 + "id": "${mod_id}", 4 + "version": "${version}", 5 + "name": "${mod_name}", 6 + "description": "${description}", 7 + "authors": [ 8 + "${mod_author}" 9 + ], 10 + "contact": { 11 + "homepage": "https://mrsnowy.dev/", 12 + "sources": "https://github.com/MrSn0wy/TeleportCommands", 13 + "issues": "https://github.com/MrSn0wy/TeleportCommands/issues" 14 + }, 15 + "license": "${license}", 16 + "icon": "${mod_id}.png", 17 + "environment": "*", 18 + "entrypoints": { 19 + "main": [ 20 + "dev.mrsnowy.teleport_commands.fabricInit" 21 + ] 22 + }, 23 + "custom": { 24 + "modmenu": { 25 + "links": { 26 + "modmenu.modrinth": "https://modrinth.com/mod/teleport-commands", 27 + "modmenu.kofi": "https://ko-fi.com/mr_snowy" 28 + } 29 + } 30 + }, 31 + "depends": { 32 + "fabricloader": ">=${fabric_loader_version}", 33 + "fabric-api": "*", 34 + "minecraft": "${minecraft_version}", 35 + "java": ">=${java_version}" 36 + }, 37 + "suggests": { 38 + "another-mod": "*" 39 + } 40 + } 41 +
+25 -13
gradle.properties
··· 1 - # Done to increase the memory available to gradle. 2 - org.gradle.jvmargs=-Xmx2G 3 - org.gradle.parallel=true 1 + # Important Notes: 2 + # Every field you add must be added to the root build.gradle expandProps map. 3 + 4 + # Project 5 + version=1.0.5 6 + group=dev.mrsnowy.teleport_commands 7 + java_version=17 4 8 5 - # Fabric Properties 6 - # check these on https://fabricmc.net/develop 9 + # Common 7 10 minecraft_version=1.20.4 8 - yarn_mappings=1.20.4+build.3 9 - loader_version=0.15.9 11 + mod_name=Teleport Commands 12 + mod_author=Mr. Snowy 13 + mod_id=teleport_commands 14 + license=MIT 15 + credits=Mr. Snowy 16 + description=A server-side mod that adds various teleportation related commands. 17 + minecraft_version_range=[1.20.4, 1.21) 10 18 11 - # Mod Properties 12 - mod_version=1.0.2 13 - maven_group=dev.mrsnowy.teleport_commands 14 - archives_base_name=teleport_commands 19 + # Fabric 20 + fabric_version=0.97.0+1.20.4 21 + fabric_loader_version=0.15.10 22 + 23 + # NeoForge 24 + neoforge_version=20.4.234 25 + neoforge_loader_version_range=[2,) 15 26 16 - # Dependencies 17 - fabric_version=0.97.0+1.20.4 27 + # Gradle 28 + org.gradle.jvmargs=-Xmx3G 29 + org.gradle.daemon=false
+38
neoforge/build.gradle
··· 1 + plugins { 2 + id 'multiloader-loader' 3 + id 'net.neoforged.gradle.userdev' version '7.0.107' 4 + } 5 + 6 + // Automatically enable neoforge AccessTransformers if the file exists 7 + // This location is hardcoded in FML and can not be changed. 8 + // https://github.com/neoforged/FancyModLoader/blob/a952595eaaddd571fbc53f43847680b00894e0c1/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFile.java#L118 9 + def at = file('src/main/resources/META-INF/accesstransformer.cfg') 10 + if (at.exists()) { 11 + minecraft.accessTransformers.file at 12 + } 13 + runs { 14 + configureEach { 15 + modSource project.sourceSets.main 16 + } 17 + client { 18 + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id 19 + } 20 + server { 21 + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id 22 + programArgument '--nogui' 23 + } 24 + 25 + gameTestServer { 26 + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id 27 + } 28 + 29 + data { 30 + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() 31 + } 32 + } 33 + 34 + sourceSets.main.resources { srcDir 'src/generated/resources' } 35 + 36 + dependencies { 37 + implementation "net.neoforged:neoforge:${neoforge_version}" 38 + }
+40
neoforge/src/main/java/dev/mrsnowy/teleport_commands/neoforgeInit.java
··· 1 + package dev.mrsnowy.teleport_commands; 2 + 3 + import net.neoforged.bus.api.EventPriority; 4 + import net.neoforged.bus.api.IEventBus; 5 + import net.neoforged.bus.api.SubscribeEvent; 6 + import net.neoforged.fml.common.Mod; 7 + import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; 8 + import net.neoforged.neoforge.event.server.ServerStartingEvent; 9 + import net.minecraft.server.level.ServerPlayer; 10 + 11 + @Mod(TeleportCommands.MOD_ID) 12 + public class neoforgeInit { 13 + 14 + public neoforgeInit(IEventBus eventBus) { 15 + // This method is invoked by the NeoForge mod loader when it is ready 16 + // to load your mod. You can access NeoForge and Common code in this 17 + // project. 18 + 19 + TeleportCommands.LOGGER.info("Teleport Commands loaded! Hello NeoForge!"); 20 + } 21 + 22 + @Mod.EventBusSubscriber(modid = TeleportCommands.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) 23 + private static class NeoForgeEventSubscriber { 24 + 25 + @SubscribeEvent(priority = EventPriority.HIGHEST) 26 + private static void onServerStarting(ServerStartingEvent event) { 27 + // initialize the mod 28 + TeleportCommands.initializeMod(event.getServer(), "NeoForge"); 29 + } 30 + 31 + @SubscribeEvent(priority = EventPriority.HIGHEST) 32 + private static void onEntityUnload(LivingDeathEvent event) { 33 + // check if it is a player 34 + if (event.getEntity() instanceof ServerPlayer player) { 35 + TeleportCommands.onPlayerDeath(player); 36 + } 37 + } 38 + } 39 + } 40 +
+32
neoforge/src/main/resources/META-INF/mods.toml
··· 1 + modLoader = "javafml" #mandatory 2 + loaderVersion = "${neoforge_loader_version_range}" #mandatory 3 + license = "${license}" # Review your options at https://choosealicense.com/. 4 + issueTrackerURL="https://github.com/MrSn0wy/TeleportCommands/issues" #optional 5 + [[mods]] #mandatory 6 + modId = "${mod_id}" #mandatory 7 + version = "${version}" #mandatory 8 + displayName = "${mod_name}" #mandatory 9 + #updateJSONURL="https://change.me.example.invalid/updates.json" #optional (see https://docs.neoforged.net/docs/misc/updatechecker/) 10 + displayURL="https://github.com/MrSn0wy/TeleportCommands" #optional (displayed in the mod UI) 11 + logoFile="${mod_id}.png" #optional 12 + credits="${credits}" #optional 13 + authors = "${mod_author}" #optional 14 + description = '''${description}''' #mandatory (Supports multiline text) 15 + [[dependencies.${mod_id}]] #optional 16 + modId = "neoforge" #mandatory 17 + type="required" #mandatory (Can be one of "required", "optional", "incompatible" or "discouraged") 18 + versionRange = "${neoforge_loader_version_range}" #mandatory 19 + ordering = "NONE" # The order that this dependency should load in relation to your mod, required to be either 'BEFORE' or 'AFTER' if the dependency is not mandatory 20 + side = "BOTH" # Side this dependency is applied on - 'BOTH', 'CLIENT' or 'SERVER' 21 + [[dependencies.${mod_id}]] 22 + modId = "minecraft" 23 + type="required" #mandatory (Can be one of "required", "optional", "incompatible" or "discouraged") 24 + versionRange = "${minecraft_version_range}" 25 + ordering = "NONE" 26 + side = "BOTH" 27 + 28 + # Features are specific properties of the game environment, that you may want to declare you require. This example declares 29 + # that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't 30 + # stop your mod loading on the server for example. 31 + #[features.${mod_id}] 32 + #openGLVersion="[3.2,)"
+32
neoforge/src/main/resources/META-INF/neoforge.mods.toml
··· 1 + modLoader = "javafml" #mandatory 2 + loaderVersion = "${neoforge_loader_version_range}" #mandatory 3 + license = "${license}" # Review your options at https://choosealicense.com/. 4 + #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional 5 + [[mods]] #mandatory 6 + modId = "${mod_id}" #mandatory 7 + version = "${version}" #mandatory 8 + displayName = "${mod_name}" #mandatory 9 + #updateJSONURL="https://change.me.example.invalid/updates.json" #optional (see https://docs.neoforged.net/docs/misc/updatechecker/) 10 + #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional (displayed in the mod UI) 11 + logoFile="${mod_id}.png" #optional 12 + credits="${credits}" #optional 13 + authors = "${mod_author}" #optional 14 + description = '''${description}''' #mandatory (Supports multiline text) 15 + [[dependencies.${mod_id}]] #optional 16 + modId = "neoforge" #mandatory 17 + type="required" #mandatory (Can be one of "required", "optional", "incompatible" or "discouraged") 18 + versionRange = "${neoforge_loader_version_range}" #mandatory 19 + ordering = "NONE" # The order that this dependency should load in relation to your mod, required to be either 'BEFORE' or 'AFTER' if the dependency is not mandatory 20 + side = "BOTH" # Side this dependency is applied on - 'BOTH', 'CLIENT' or 'SERVER' 21 + [[dependencies.${mod_id}]] 22 + modId = "minecraft" 23 + type="required" #mandatory (Can be one of "required", "optional", "incompatible" or "discouraged") 24 + versionRange = "${minecraft_version_range}" 25 + ordering = "NONE" 26 + side = "BOTH" 27 + 28 + # Features are specific properties of the game environment, that you may want to declare you require. This example declares 29 + # that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't 30 + # stop your mod loading on the server for example. 31 + #[features.${mod_id}] 32 + #openGLVersion="[3.2,)"
+52 -10
settings.gradle
··· 1 - pluginManagement { 2 - repositories { 3 - maven { 4 - name = 'Fabric' 5 - url = 'https://maven.fabricmc.net/' 6 - } 7 - mavenCentral() 8 - gradlePluginPortal() 9 - } 10 - } 1 + pluginManagement { 2 + repositories { 3 + gradlePluginPortal() 4 + mavenCentral() 5 + exclusiveContent { 6 + forRepository { 7 + maven { 8 + name = 'Fabric' 9 + url = uri("https://maven.fabricmc.net") 10 + } 11 + } 12 + filter { 13 + includeGroup("net.fabricmc") 14 + includeGroup("fabric-loom") 15 + } 16 + } 17 + exclusiveContent { 18 + forRepository { 19 + maven { 20 + name = 'NeoForge' 21 + url = uri("https://maven.neoforged.net/releases") 22 + } 23 + } 24 + filter { 25 + includeGroupAndSubgroups("net.neoforged") 26 + includeGroup("codechicken") 27 + } 28 + } 29 + exclusiveContent { 30 + forRepository { 31 + maven { 32 + name = 'Sponge Snapshots' 33 + url = uri("https://repo.spongepowered.org/repository/maven-public") 34 + } 35 + } 36 + filter { 37 + includeGroupAndSubgroups("org.spongepowered") 38 + includeGroup("net.minecraftforge") 39 + } 40 + } 41 + } 42 + } 43 + 44 + plugins { 45 + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' 46 + } 47 + 48 + // This should match the folder name of the project, or else IDEA may complain (see https://youtrack.jetbrains.com/issue/IDEA-317606) 49 + rootProject.name = 'MultiLoader-Template' 50 + include("common") 51 + include("fabric") 52 + include("neoforge")
-77
src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java
··· 1 - package dev.mrsnowy.teleport_commands; 2 - 3 - import dev.mrsnowy.teleport_commands.storage.StorageManager; 4 - import dev.mrsnowy.teleport_commands.utils.commands; 5 - import net.fabricmc.api.ModInitializer; 6 - 7 - import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; 8 - import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; 9 - import net.fabricmc.loader.api.FabricLoader; 10 - import net.minecraft.entity.Entity; 11 - import net.minecraft.server.MinecraftServer; 12 - import net.minecraft.server.network.ServerPlayerEntity; 13 - import net.minecraft.server.world.ServerWorld; 14 - import net.minecraft.util.WorldSavePath; 15 - import net.minecraft.world.World; 16 - import org.slf4j.Logger; 17 - import org.slf4j.LoggerFactory; 18 - 19 - import java.nio.file.Path; 20 - import java.util.Objects; 21 - 22 - import static dev.mrsnowy.teleport_commands.utils.tools.DeathLocationUpdater; 23 - 24 - public class TeleportCommands implements ModInitializer { 25 - // This logger is used to write text to the console and the log file. 26 - // It is considered best practice to use your mod id as the logger's name. 27 - // That way, it's clear which mod wrote info, warnings, and errors. 28 - public static final String MOD_ID = "teleport_commands"; 29 - public static final Logger LOGGER = LoggerFactory.getLogger("teleport_commands"); 30 - 31 - public static Path SAVE_DIR; 32 - public static Path CONFIG_DIR; 33 - public static StorageManager Storage; 34 - public static MinecraftServer Server; 35 - 36 - @Override 37 - public void onInitialize() { 38 - // This code runs as soon as Minecraft is in a mod-load-ready state. 39 - // However, some things (like resources) may still be uninitialized. 40 - // Proceed with mild caution. 41 - ServerWorldEvents.LOAD.register(this::onWorldLoad); 42 - 43 - ServerEntityEvents.ENTITY_UNLOAD.register(this::onPlayerUnload); 44 - 45 - // todo: /back /tpa /tpahere /home /homes /sethome /delhome /renamehome /defaulthome /spawn /worldspawn 46 - commands.registerCommands(); 47 - } 48 - 49 - 50 - 51 - private void onPlayerUnload(Entity entity, ServerWorld world) { 52 - if (entity instanceof ServerPlayerEntity player) { 53 - // LOGGER.info(String.valueOf(entity.getRemovalReason())); 54 - if (player.getRemovalReason() != null && (Objects.equals(player.getRemovalReason().toString(), "KILLED") || Objects.equals(player.getRemovalReason().toString(), "DISCARDED"))) { 55 - try { 56 - // /back command position 57 - LOGGER.info(player.getPos().toString()); 58 - DeathLocationUpdater(player.getPos(), player.getServerWorld(), player.getUuidAsString()); 59 - } catch (Exception e) { 60 - throw new RuntimeException(e); 61 - } 62 - } 63 - } 64 - } 65 - 66 - private void onWorldLoad(MinecraftServer minecraftServer, ServerWorld serverWorld) { 67 - // make it run only once 68 - if (serverWorld.getRegistryKey() == World.OVERWORLD) { 69 - // initialize da variables 70 - SAVE_DIR = Path.of(String.valueOf(minecraftServer.getSavePath(WorldSavePath.ROOT))); 71 - CONFIG_DIR = FabricLoader.getInstance().getConfigDir(); 72 - 73 - Server = minecraftServer; 74 - StorageManager.StorageInit(); 75 - } 76 - } 77 - }
-1
src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java
··· 14 14 import java.util.Optional; 15 15 16 16 public class StorageManager { 17 - 18 17 public static Path STORAGE_FOLDER; 19 18 public static Path STORAGE_FILE; 20 19
-8
src/main/java/dev/mrsnowy/teleport_commands/storage/configManager.java
··· 1 - package dev.mrsnowy.teleport_commands.storage; 2 - 3 - //import java.nio.file.Path; 4 - //import net.fabricmc.loader.api.FabricLoader; 5 - 6 - public class configManager { 7 - 8 - }
+6 -10
src/main/java/dev/mrsnowy/teleport_commands/suggestions/HomesuggestionProvider.java common/src/main/java/dev/mrsnowy/teleport_commands/suggestions/HomesuggestionProvider.java
··· 6 6 import com.mojang.brigadier.suggestion.SuggestionsBuilder; 7 7 import dev.mrsnowy.teleport_commands.TeleportCommands; 8 8 import dev.mrsnowy.teleport_commands.storage.StorageManager; 9 - import net.minecraft.server.command.ServerCommandSource; 10 - import net.minecraft.server.network.ServerPlayerEntity; 11 - import net.minecraft.server.world.ServerWorld; 12 - import net.minecraft.util.math.Vec3d; 13 - 14 9 import java.util.Objects; 15 10 import java.util.concurrent.CompletableFuture; 11 + import net.minecraft.commands.CommandSourceStack; 12 + import net.minecraft.server.level.ServerPlayer; 16 13 17 14 import static dev.mrsnowy.teleport_commands.storage.StorageManager.GetPlayerStorage; 18 15 19 - public class HomesuggestionProvider implements SuggestionProvider<ServerCommandSource> { 16 + public class HomesuggestionProvider implements SuggestionProvider<CommandSourceStack> { 20 17 @Override 21 - public CompletableFuture<Suggestions> getSuggestions(CommandContext<ServerCommandSource> context, SuggestionsBuilder builder) { 18 + public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) { 22 19 try { 23 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 24 - StorageManager.StorageClass.Player playerStorage = null; 25 - playerStorage = GetPlayerStorage(player.getUuidAsString()).playerStorage; 20 + ServerPlayer player = Objects.requireNonNull(context.getSource().getPlayer()); 21 + StorageManager.StorageClass.Player playerStorage = GetPlayerStorage(player.getStringUUID()).playerStorage; 26 22 27 23 for (StorageManager.StorageClass.Player.Home currenthome : playerStorage.Homes) { 28 24 builder.suggest(currenthome.name);
-192
src/main/java/dev/mrsnowy/teleport_commands/utils/commands.java
··· 1 - package dev.mrsnowy.teleport_commands.utils; 2 - 3 - import com.mojang.brigadier.arguments.StringArgumentType; 4 - import dev.mrsnowy.teleport_commands.TeleportCommands; 5 - import dev.mrsnowy.teleport_commands.suggestions.HomesuggestionProvider; 6 - import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; 7 - import net.minecraft.command.argument.EntityArgumentType; 8 - import net.minecraft.server.command.CommandManager; 9 - import net.minecraft.server.network.ServerPlayerEntity; 10 - import net.minecraft.text.Text; 11 - import net.minecraft.util.Formatting; 12 - 13 - import javax.swing.text.html.parser.Entity; 14 - import java.util.Objects; 15 - 16 - import static net.minecraft.server.command.CommandManager.argument; 17 - import static net.minecraft.server.command.CommandManager.literal; 18 - 19 - public class commands { 20 - public static void registerCommands() { 21 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("back") 22 - .executes(context -> { 23 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 24 - try { 25 - player.sendMessage(Text.literal("Teleporting"), true); 26 - tools.ToDeathLocation(player); 27 - } catch (Exception e) { 28 - TeleportCommands.LOGGER.error(String.valueOf(e)); 29 - player.sendMessage(Text.literal("Error Teleporting!").formatted(Formatting.RED, Formatting.BOLD), true); 30 - return 1; 31 - } 32 - return 0; 33 - }))); 34 - 35 - 36 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("sethome") 37 - .then(argument("name", StringArgumentType.string()) 38 - .executes(context -> { 39 - final String name = StringArgumentType.getString(context, "name"); 40 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 41 - 42 - try { 43 - player.sendMessage(Text.literal("Home Set"), true); 44 - tools.SetHome(player, name); 45 - 46 - } catch (Exception e) { 47 - TeleportCommands.LOGGER.error(String.valueOf(e)); 48 - player.sendMessage(Text.literal("Error Setting Home!").formatted(Formatting.RED, Formatting.BOLD), true); 49 - return 1; 50 - } 51 - return 0; 52 - })))); 53 - 54 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("home") 55 - .executes(context -> { 56 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 57 - 58 - try { 59 - player.sendMessage(Text.literal("Going Home"), true); 60 - tools.GoHome(player, ""); 61 - 62 - } catch (Exception e) { 63 - TeleportCommands.LOGGER.error(String.valueOf(e)); 64 - player.sendMessage(Text.literal("Error Going Home!").formatted(Formatting.RED, Formatting.BOLD), true); 65 - return 1; 66 - } 67 - return 0; 68 - }) 69 - .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 70 - .executes(context -> { 71 - final String name = StringArgumentType.getString(context, "name"); 72 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 73 - 74 - try { 75 - player.sendMessage(Text.literal("Going Home"), true); 76 - tools.GoHome(player, name); 77 - 78 - } catch (Exception e) { 79 - player.sendMessage(Text.literal("Error Going Home!").formatted(Formatting.RED, Formatting.BOLD), true); 80 - TeleportCommands.LOGGER.error(String.valueOf(e)); 81 - return 1; 82 - } 83 - return 0; 84 - })))); 85 - 86 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("delhome") 87 - .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 88 - .executes(context -> { 89 - final String name = StringArgumentType.getString(context, "name"); 90 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 91 - 92 - try { 93 - player.sendMessage(Text.literal("Home Deleted"), true); 94 - tools.DeleteHome(player, name); 95 - 96 - } catch (Exception e) { 97 - TeleportCommands.LOGGER.error(String.valueOf(e)); 98 - player.sendMessage(Text.literal("Error Deleting Home!").formatted(Formatting.RED, Formatting.BOLD), true); 99 - return 1; 100 - } 101 - return 0; 102 - })))); 103 - 104 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("renamehome") 105 - .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 106 - .then(argument("newName", StringArgumentType.string()) 107 - .executes(context -> { 108 - final String name = StringArgumentType.getString(context, "name"); 109 - final String newName = StringArgumentType.getString(context, "newName"); 110 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 111 - 112 - try { 113 - player.sendMessage(Text.literal("Home Renamed"), true); 114 - tools.RenameHome(player, name, newName); 115 - } catch (Exception e) { 116 - TeleportCommands.LOGGER.error(String.valueOf(e)); 117 - player.sendMessage(Text.literal("Error Renaming Home!").formatted(Formatting.RED, Formatting.BOLD), true); 118 - return 1; 119 - } 120 - return 0; 121 - }))))); 122 - 123 - 124 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("homes") 125 - .executes(context -> { 126 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 127 - try { 128 - tools.PrintHomes(player); 129 - } catch (Exception e) { 130 - TeleportCommands.LOGGER.error(String.valueOf(e)); 131 - player.sendMessage(Text.literal("Error Getting Homes!").formatted(Formatting.RED, Formatting.BOLD), true); 132 - return 1; 133 - } 134 - return 0; 135 - }))); 136 - 137 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("defaulthome") 138 - .then(argument("name", StringArgumentType.string()).suggests(new HomesuggestionProvider()) 139 - .executes(context -> { 140 - final String name = StringArgumentType.getString(context, "name"); 141 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 142 - try { 143 - tools.SetDefaultHome(player, name); 144 - } catch (Exception e) { 145 - TeleportCommands.LOGGER.error(String.valueOf(e)); 146 - player.sendMessage(Text.literal("Error Changing Default Home!").formatted(Formatting.RED, Formatting.BOLD), true); 147 - return 1; 148 - } 149 - return 0; 150 - })))); 151 - 152 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("tpa") 153 - .then(CommandManager.argument("player", EntityArgumentType.player()) 154 - .executes(context -> { 155 - final ServerPlayerEntity TargetPlayer = EntityArgumentType.getPlayer(context, "player"); 156 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 157 - 158 - tools.tpaCommandHandler(player, TargetPlayer, false); 159 - return 0; 160 - })))); 161 - 162 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("tpahere") 163 - .then(CommandManager.argument("player", EntityArgumentType.player()) 164 - .executes(context -> { 165 - final ServerPlayerEntity TargetPlayer = EntityArgumentType.getPlayer(context, "player"); 166 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 167 - 168 - tools.tpaCommandHandler(player, TargetPlayer, true); 169 - return 0; 170 - })))); 171 - 172 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("tpaaccept") 173 - .then(CommandManager.argument("player", EntityArgumentType.player()) 174 - .executes(context -> { 175 - final ServerPlayerEntity TargetPlayer = EntityArgumentType.getPlayer(context, "player"); 176 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 177 - 178 - tools.tpaAccept(player, TargetPlayer); 179 - return 0; 180 - })))); 181 - 182 - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("tpadeny") 183 - .then(CommandManager.argument("player", EntityArgumentType.player()) 184 - .executes(context -> { 185 - final ServerPlayerEntity TargetPlayer = EntityArgumentType.getPlayer(context, "player"); 186 - ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); 187 - 188 - tools.tpaDeny(player, TargetPlayer); 189 - return 0; 190 - })))); 191 - } 192 - }
-421
src/main/java/dev/mrsnowy/teleport_commands/utils/tools.java
··· 1 - package dev.mrsnowy.teleport_commands.utils; 2 - 3 - import net.fabricmc.fabric.api.dimension.v1.FabricDimensions; 4 - import net.minecraft.particle.ParticleTypes; 5 - import net.minecraft.server.network.ServerPlayerEntity; 6 - import net.minecraft.server.world.ServerWorld; 7 - import net.minecraft.sound.SoundCategory; 8 - import net.minecraft.sound.SoundEvent; 9 - import net.minecraft.text.ClickEvent; 10 - import net.minecraft.text.Text; 11 - import net.minecraft.util.Formatting; 12 - import net.minecraft.util.math.Vec3d; 13 - import net.minecraft.world.TeleportTarget; 14 - 15 - import java.util.*; 16 - 17 - import static dev.mrsnowy.teleport_commands.storage.StorageManager.*; 18 - import static net.minecraft.sound.SoundEvents.ENTITY_ENDERMAN_TELEPORT; 19 - 20 - public class tools { 21 - private static ArrayList<tpaArrayClass> tpaList = new ArrayList<>(); 22 - 23 - private static class tpaArrayClass { 24 - private String InitPlayer; 25 - private String RecPlayer; 26 - private boolean here; 27 - } 28 - 29 - private static void Teleporter(ServerPlayerEntity player, ServerWorld world, Vec3d coords) { 30 - world.spawnParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() + 1, player.getZ(), 20, 0.0D, 0.0D, 0.0D, 0.01); 31 - world.spawnParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 1.0D, 0.0D, 0.03); 32 - world.playSound(null, player.getBlockPos(), SoundEvent.of(ENTITY_ENDERMAN_TELEPORT.getId()), SoundCategory.PLAYERS, 0.4f, 1.0f); 33 - 34 - FabricDimensions.teleport(player, world, new TeleportTarget(coords, Vec3d.ZERO, player.getYaw(), player.getPitch())); 35 - 36 - world.playSound(null, player.getBlockPos(), SoundEvent.of(ENTITY_ENDERMAN_TELEPORT.getId()), SoundCategory.PLAYERS, 0.4f, 1.0f); 37 - Timer timer = new Timer(); 38 - 39 - timer.schedule( 40 - new TimerTask() { 41 - @Override 42 - public void run() { 43 - world.spawnParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() , player.getZ(), 20, 0.0D, 1.0D, 0.0D, 0.01); 44 - world.spawnParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 0.0D, 0.0D, 0.03); 45 - } 46 - }, 100 // hopefully good, 2 ticks 47 - ); 48 - } 49 - 50 - 51 - public static void SetHome(ServerPlayerEntity player, String homeName) throws Exception { 52 - homeName = homeName.toLowerCase(); 53 - Vec3d pos = player.getPos(); 54 - ServerWorld world = player.getServerWorld(); 55 - 56 - PlayerStorageResult storages = GetPlayerStorage(player.getUuidAsString()); 57 - StorageClass storage = storages.storage; 58 - StorageClass.Player playerStorage = storages.playerStorage; 59 - 60 - boolean homeNotFound = true; 61 - 62 - // check for duplicates 63 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 64 - if (Objects.equals(currentHome.name, homeName)) { 65 - homeNotFound = false; 66 - break; 67 - } 68 - } 69 - 70 - if (homeNotFound) { 71 - // Create a new Home 72 - StorageClass.Player.Home homeLocation = new StorageClass.Player.Home(); 73 - 74 - homeLocation.name = homeName; 75 - homeLocation.x = Double.parseDouble(String.format("%.1f", pos.getX())); 76 - homeLocation.y = Double.parseDouble(String.format("%.1f", pos.getY()));; 77 - homeLocation.z = Double.parseDouble(String.format("%.1f", pos.getZ()));; 78 - homeLocation.world = world.getRegistryKey().getValue().toString(); 79 - 80 - playerStorage.Homes.add(homeLocation); 81 - 82 - if (playerStorage.Homes.size() == 1) { 83 - playerStorage.DefaultHome = homeName; 84 - } 85 - 86 - StorageSaver(storage); 87 - } else { 88 - player.sendMessage(Text.literal("Home Already Exists!"), true); 89 - } 90 - } 91 - 92 - public static void GoHome(ServerPlayerEntity player, String homeName) throws Exception { 93 - homeName = homeName.toLowerCase(); 94 - StorageClass.Player playerStorage = GetPlayerStorage(player.getUuidAsString()).playerStorage; 95 - 96 - // check if there is a default exists 97 - if (homeName.isEmpty()) { 98 - if (playerStorage.DefaultHome.isEmpty()) { 99 - player.sendMessage(Text.literal("You Have No Homes!"), true); 100 - return; 101 - } else { 102 - homeName = playerStorage.DefaultHome; 103 - } 104 - } 105 - 106 - boolean foundHome = false; 107 - boolean foundWorld = false; 108 - 109 - // find correct home 110 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 111 - if (Objects.equals(currentHome.name, homeName)){ 112 - foundHome = true; 113 - 114 - // find correct world 115 - for (ServerWorld currentWorld : Objects.requireNonNull(player.getServer()).getWorlds()) { 116 - if (Objects.equals(currentWorld.getRegistryKey().getValue().toString(), currentHome.world)) { 117 - Teleporter(player, currentWorld, new Vec3d(currentHome.x, currentHome.y, currentHome.z)); 118 - foundWorld = true; 119 - break; 120 - } 121 - } 122 - } 123 - } 124 - 125 - if (!foundHome) { 126 - player.sendMessage(Text.literal("Home Not Found!"), true); 127 - } else if (!foundWorld) { 128 - player.sendMessage(Text.literal("World Not Found!"), true); 129 - } 130 - } 131 - 132 - public static void DeleteHome(ServerPlayerEntity player, String homeName) throws Exception { 133 - homeName = homeName.toLowerCase(); 134 - PlayerStorageResult storages = GetPlayerStorage(player.getUuidAsString()); 135 - StorageClass storage = storages.storage; 136 - StorageClass.Player playerStorage = storages.playerStorage; 137 - 138 - StorageClass.Player.Home homeToDelete = null; 139 - 140 - // get correct home 141 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 142 - if (Objects.equals(currentHome.name, homeName)){ 143 - homeToDelete = currentHome; 144 - break; 145 - } 146 - } 147 - 148 - if (Objects.nonNull(homeToDelete)) { 149 - playerStorage.Homes.remove(homeToDelete); 150 - StorageSaver(storage); 151 - } else { 152 - player.sendMessage(Text.literal("Home Not Found!"), true); 153 - } 154 - } 155 - 156 - public static void RenameHome(ServerPlayerEntity player, String homeName, String newHomeName) throws Exception { 157 - homeName = homeName.toLowerCase(); 158 - newHomeName = newHomeName.toLowerCase(); 159 - 160 - PlayerStorageResult storages = GetPlayerStorage(player.getUuidAsString()); 161 - StorageClass storage = storages.storage; 162 - StorageClass.Player playerStorage = storages.playerStorage; 163 - 164 - StorageClass.Player.Home homeToRename = null; 165 - boolean newNameNotFound = true; 166 - 167 - // check for duplicates 168 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 169 - if (Objects.equals(currentHome.name, newHomeName)) { 170 - newNameNotFound = false; 171 - break; 172 - } 173 - } 174 - 175 - if (newNameNotFound) { 176 - // get correct home 177 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 178 - if (Objects.equals(currentHome.name, homeName)){ 179 - homeToRename = currentHome; 180 - break; 181 - } 182 - } 183 - 184 - if (Objects.nonNull(homeToRename)) { 185 - if (Objects.equals(playerStorage.DefaultHome, homeToRename.name)) { 186 - playerStorage.DefaultHome = newHomeName; 187 - } 188 - 189 - homeToRename.name = newHomeName; 190 - StorageSaver(storage); 191 - } else { 192 - player.sendMessage(Text.literal("Home Not Found!"), true); 193 - } 194 - } else { 195 - player.sendMessage(Text.literal("Home Already Exists!"), true); 196 - } 197 - 198 - } 199 - 200 - public static void PrintHomes(ServerPlayerEntity player) throws Exception { 201 - StorageClass.Player playerStorage = GetPlayerStorage(player.getUuidAsString()).playerStorage; 202 - boolean anyHomes = false; 203 - 204 - for (StorageClass.Player.Home currenthome : playerStorage.Homes) { 205 - if (!anyHomes) { 206 - player.sendMessage(Text.literal("Homes: \n").formatted(Formatting.YELLOW, Formatting.BOLD), false); 207 - anyHomes = true; 208 - } 209 - 210 - String name = String.format(" - %s", currenthome.name); 211 - String nameDefault = " (Default)"; 212 - 213 - 214 - String coords = String.format(" [X%.1f Y%.1f Z%.1f]", currenthome.x, currenthome.y, currenthome.z); 215 - String dimension = String.format(" [%s]", currenthome.world); 216 - 217 - if (Objects.equals(currenthome.name, playerStorage.DefaultHome)) { 218 - player.sendMessage(Text.literal(name).formatted(Formatting.AQUA) 219 - .append(Text.literal(nameDefault).formatted(Formatting.AQUA, Formatting.BOLD)), 220 - false 221 - ); 222 - } else { 223 - player.sendMessage(Text.literal(name).formatted(Formatting.AQUA), false); 224 - } 225 - 226 - 227 - player.sendMessage(Text.literal(" |").formatted(Formatting.AQUA) 228 - .append(Text.literal(coords).formatted(Formatting.LIGHT_PURPLE).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, String.format("X%.2f Y%.2f Z%.2f", currenthome.x, currenthome.y, currenthome.z))))) 229 - .append(Text.literal(dimension).formatted(Formatting.DARK_PURPLE).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, currenthome.world)))), 230 - false 231 - ); 232 - 233 - player.sendMessage(Text.literal(" |").formatted(Formatting.AQUA) 234 - .append(Text.literal(" [Tp]").formatted(Formatting.GREEN).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/home %s", currenthome.name))))) 235 - .append(Text.literal(" [Rename]").formatted(Formatting.BLUE).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/renamehome %s ", currenthome.name))))) 236 - .append(Text.literal(" [Delete]\n").formatted(Formatting.RED).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/delhome %s", currenthome.name))))), 237 - false 238 - ); 239 - } 240 - 241 - if (!anyHomes) { 242 - player.sendMessage(Text.literal("No homes set"), true); 243 - } 244 - } 245 - 246 - public static void SetDefaultHome(ServerPlayerEntity player, String homeName) throws Exception { 247 - homeName = homeName.toLowerCase(); 248 - PlayerStorageResult storages = GetPlayerStorage(player.getUuidAsString()); 249 - StorageClass storage = storages.storage; 250 - StorageClass.Player playerStorage = storages.playerStorage; 251 - 252 - boolean homeExists = false; 253 - 254 - // check if home exists 255 - for (StorageClass.Player.Home currentHome : playerStorage.Homes) { 256 - if (Objects.equals(currentHome.name, homeName)){ 257 - homeExists = true; 258 - break; 259 - } 260 - } 261 - 262 - if (homeExists) { 263 - if (Objects.equals(playerStorage.DefaultHome, homeName)) { 264 - player.sendMessage(Text.literal("Home is already set as default!"), true); 265 - 266 - } else { 267 - playerStorage.DefaultHome = homeName; 268 - StorageSaver(storage); 269 - } 270 - } else { 271 - player.sendMessage(Text.literal("Home not found!"), true); 272 - } 273 - } 274 - 275 - 276 - public static void ToDeathLocation(ServerPlayerEntity player) throws Exception { 277 - StorageClass.Player playerStorage = GetPlayerStorage(player.getUuidAsString()).playerStorage; 278 - 279 - Vec3d pos = new Vec3d(playerStorage.deathLocation.x, playerStorage.deathLocation.y, playerStorage.deathLocation.z); 280 - 281 - boolean found = false; 282 - for (ServerWorld currentWorld : Objects.requireNonNull(player.getServer()).getWorlds()) { 283 - if (Objects.equals(currentWorld.getRegistryKey().getValue().toString(), playerStorage.deathLocation.world)) { 284 - Teleporter(player, currentWorld, pos); 285 - found = true; 286 - break; 287 - } 288 - } 289 - 290 - if (!found) { 291 - player.sendMessage(Text.literal("No Location Found!"), true); 292 - } 293 - } 294 - 295 - public static void tpaCommandHandler(ServerPlayerEntity FromPlayer, ServerPlayerEntity ToPlayer, boolean here) { 296 - 297 - if (FromPlayer == ToPlayer) { 298 - FromPlayer.sendMessage(Text.literal("Well, that was easy").formatted(Formatting.AQUA),true); 299 - 300 - } else { 301 - String ToMessage; 302 - String FromMessage; 303 - 304 - // Store da request 305 - tpaArrayClass tpaRequest = new tpaArrayClass(); 306 - tpaRequest.InitPlayer = FromPlayer.getUuidAsString(); 307 - tpaRequest.RecPlayer = ToPlayer.getUuidAsString(); 308 - tpaRequest.here = here; 309 - tpaList.add(tpaRequest); 310 - 311 - if (here) { 312 - ToMessage = "TpaHere Request Received From "; 313 - FromMessage = "TpaHere Request Send to "; 314 - 315 - } else { 316 - ToMessage = "Tpa Request Received From "; 317 - FromMessage = "Tpa Request Send to "; 318 - } 319 - 320 - String ToPlayerString = Objects.requireNonNull(ToPlayer.getName().getLiteralString()); 321 - String FromPlayerString = Objects.requireNonNull(FromPlayer.getName().getLiteralString()); 322 - 323 - FromPlayer.sendMessage(Text.literal(FromMessage).formatted(Formatting.AQUA) 324 - .append(Text.literal(ToPlayerString).formatted(Formatting.AQUA, Formatting.BOLD)) 325 - // .append(Text.literal("\n[Cancel]").formatted(Formatting.BLUE, Formatting.BOLD)) 326 - ,true 327 - ); 328 - 329 - ToPlayer.sendMessage(Text.literal(ToMessage).formatted(Formatting.AQUA) 330 - .append(Text.literal(FromPlayerString).formatted(Formatting.AQUA, Formatting.BOLD)) 331 - .append(Text.literal("\n[Accept]").formatted(Formatting.GREEN, Formatting.BOLD).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/tpaaccept %s", FromPlayerString))))) 332 - .append(Text.literal(" [Deny]").formatted(Formatting.RED, Formatting.BOLD).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/tpadeny %s", FromPlayerString))))), 333 - false 334 - ); 335 - 336 - Timer timer = new Timer(); 337 - timer.schedule( 338 - new TimerTask() { 339 - @Override 340 - public void run() { 341 - boolean successful = tpaList.remove(tpaRequest); 342 - if (successful) { 343 - if (here) { 344 - FromPlayer.sendMessage(Text.literal("TpaHere Request Expired").formatted(Formatting.AQUA),true); 345 - } else { 346 - FromPlayer.sendMessage(Text.literal("Tpa Request Expired").formatted(Formatting.AQUA),true); 347 - } 348 - } 349 - } 350 - }, 30 * 1000 351 - ); 352 - } 353 - } 354 - 355 - public static void tpaAccept(ServerPlayerEntity FromPlayer, ServerPlayerEntity ToPlayer) { 356 - if (FromPlayer == ToPlayer) { 357 - FromPlayer.sendMessage(Text.literal("No").formatted(Formatting.AQUA),true); 358 - } else { 359 - Optional<tpaArrayClass> tpaStorage = tpaList.stream() 360 - .filter(tpa -> Objects.equals(ToPlayer.getUuidAsString(), tpa.InitPlayer)) 361 - .filter(tpa -> Objects.equals(FromPlayer.getUuidAsString(), tpa.RecPlayer)) 362 - .findFirst(); 363 - 364 - if (tpaStorage.isPresent()) { 365 - if (tpaStorage.get().here) { 366 - FromPlayer.sendMessage(Text.literal("Teleporting"),true); 367 - ToPlayer.sendMessage(Text.literal("Request Accepted"),true); 368 - 369 - Teleporter(FromPlayer, ToPlayer.getServerWorld(), ToPlayer.getPos()); 370 - } else { 371 - ToPlayer.sendMessage(Text.literal("Teleporting"),true); 372 - FromPlayer.sendMessage(Text.literal("Request Accepted"),true); 373 - 374 - Teleporter(ToPlayer, FromPlayer.getServerWorld(), FromPlayer.getPos()); 375 - } 376 - 377 - tpaList.remove(tpaStorage.get()); 378 - } else { 379 - FromPlayer.sendMessage(Text.literal("No Requests found!").formatted(Formatting.AQUA),true); 380 - } 381 - } 382 - } 383 - 384 - public static void tpaDeny(ServerPlayerEntity FromPlayer, ServerPlayerEntity ToPlayer) { 385 - if (FromPlayer == ToPlayer) { 386 - FromPlayer.sendMessage(Text.literal("No").formatted(Formatting.AQUA),true); 387 - } else { 388 - Optional<tpaArrayClass> tpaStorage = tpaList.stream() 389 - .filter(tpa -> Objects.equals(ToPlayer.getUuidAsString(), tpa.InitPlayer)) 390 - .filter(tpa -> Objects.equals(FromPlayer.getUuidAsString(), tpa.RecPlayer)) 391 - .findFirst(); 392 - 393 - if (tpaStorage.isPresent()) { 394 - tpaList.remove(tpaStorage.get()); 395 - 396 - if (tpaStorage.get().here) { 397 - ToPlayer.sendMessage(Text.literal("Request Denied").formatted(Formatting.AQUA),true); 398 - } else { 399 - FromPlayer.sendMessage(Text.literal("Request Denied").formatted(Formatting.AQUA),true); 400 - } 401 - } else { 402 - FromPlayer.sendMessage(Text.literal("No Requests found!").formatted(Formatting.AQUA),true); 403 - } 404 - } 405 - } 406 - 407 - 408 - public static void DeathLocationUpdater(Vec3d pos, ServerWorld world, String UUID) throws Exception { 409 - PlayerStorageResult storages = GetPlayerStorage(UUID); 410 - 411 - StorageClass storage = storages.storage; 412 - StorageClass.Player playerStorage = storages.playerStorage; 413 - 414 - playerStorage.deathLocation.x = Double.parseDouble(String.format("%.1f", pos.getX()));; 415 - playerStorage.deathLocation.y = Double.parseDouble(String.format("%.1f", pos.getY()));; 416 - playerStorage.deathLocation.z = Double.parseDouble(String.format("%.1f", pos.getZ()));; 417 - playerStorage.deathLocation.world = world.getRegistryKey().getValue().toString(); 418 - 419 - StorageSaver(storage); 420 - } 421 - }
src/main/resources/assets/teleport_commands/icon.png common/src/main/resources/teleport_commands.png
-37
src/main/resources/fabric.mod.json
··· 1 - { 2 - "schemaVersion": 1, 3 - "id": "teleport_commands", 4 - "version": "${version}", 5 - "name": "Teleport Commands", 6 - "description": "A fabric server-side mod that adds various teleportation related commands", 7 - "authors": [ 8 - "Mr. Snowy" 9 - ], 10 - "contact": { 11 - "homepage": "https://mrsnowy.dev/", 12 - "sources": "https://github.com/MrSn0wy/TeleportCommands", 13 - "issues": "https://github.com/MrSn0wy/TeleportCommands/issues" 14 - }, 15 - "license": "MIT", 16 - "icon": "assets/teleport_commands/icon.png", 17 - "environment": "*", 18 - "entrypoints": { 19 - "main": [ 20 - "dev.mrsnowy.teleport_commands.TeleportCommands" 21 - ] 22 - }, 23 - "custom": { 24 - "modmenu": { 25 - "links": { 26 - "modmenu.modrinth": "https://modrinth.com/mod/teleport-commands", 27 - "modmenu.kofi": "https://ko-fi.com/mr_snowy" 28 - } 29 - } 30 - }, 31 - "depends": { 32 - "fabricloader": ">=0.15.9", 33 - "minecraft": "~1.20.4", 34 - "java": ">=17", 35 - "fabric-api": ">=0.97.0" 36 - } 37 - }