├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ ├── CopyFile.kt │ ├── SquareMarkerPlatformExtension.kt │ ├── squaremarker.base.gradle.kts │ ├── squaremarker.platform.gradle.kts │ └── squaremarker.platform.loom.gradle.kts ├── common ├── build.gradle.kts └── src │ └── main │ └── kotlin │ ├── Components.kt │ ├── Configuration.kt │ ├── IO.kt │ ├── Lang.kt │ ├── SquareMarker.kt │ ├── WorldIdentifierSerializer.kt │ ├── command │ ├── Commander.kt │ ├── Commands.kt │ ├── PlayerCommander.kt │ ├── SquaremarkerCommand.kt │ └── commands │ │ ├── HelpCommand.kt │ │ ├── ListMarkerCommand.kt │ │ ├── RemoveMarkerCommand.kt │ │ ├── SetMarkerCommand.kt │ │ ├── ShowMarkerCommand.kt │ │ └── UpdateMarkerCommand.kt │ └── marker │ ├── API.kt │ ├── Marker.kt │ ├── MarkerService.kt │ └── MarkerTask.kt ├── fabric ├── build.gradle.kts └── src │ └── main │ ├── kotlin │ ├── SquareMarkerInitializer.kt │ └── command │ │ └── FabricCommander.kt │ └── resources │ └── fabric.mod.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── neoforge ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ ├── kotlin │ ├── SquareMarkerInitializer.kt │ └── command │ │ └── ForgeCommander.kt │ └── resources │ ├── META-INF │ └── neoforge.mods.toml │ └── pack.mcmeta ├── paper ├── build.gradle.kts └── src │ └── main │ ├── kotlin │ ├── Folia.kt │ ├── PaperWorldIdentifierSerializer.kt │ ├── SquareMarkerPlugin.kt │ └── command │ │ └── PaperCommander.kt │ └── resources │ └── plugin.yml ├── resources └── default_icon.png └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "build" 2 | 3 | on: 4 | push: 5 | branches: [ "**" ] 6 | tags-ignore: [ "**" ] 7 | pull_request: 8 | 9 | jobs: 10 | call-build: 11 | uses: "jpenilla/actions/.github/workflows/shared-ci.yml@master" 12 | with: 13 | artifacts-path: "build/libs/*.jar" 14 | loom: true 15 | jdk-version: 21 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | 5 | **/run/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # squaremarker 2 | 3 | A simple marker extension for squaremap (https://github.com/jpenilla/squaremap) 4 |
5 | This plugin is an extension and only works in combination with squaremap. 6 |
7 | It offers the possibility to easily create markers yourself, which are then displayed on the map.
8 | This project is still under development and will be improved and expanded in the future.
9 | Feel free to report any bugs you find via [GitHub Issues](https://github.com/SentixDev/squaremarker/issues). 10 | 11 | # Download 12 | Downloads are available via [GitHub Releases](https://github.com/SentixDev/squaremarker/releases). 13 | 14 | # Usage 15 | 16 | ## Commands 17 | | Command | Description | Permission | 18 | |--------------------------------------------------|------------------------------------------|-----------------------| 19 | | `/squaremarker help [query]` | Query help for squaremarker commands | `squaremarker.help` | 20 | | `/squaremarker list` | Shows a list with all existing markers | `squaremarker.list` | 21 | | `/squaremarker show ` | Shows details to a specific marker | `squaremarker.show` | 22 | | `/squaremarker set [content] [icon-url]` | Set a marker at your current location | `squaremarker.set` | 23 | | `/squaremarker update [content] [icon-url]` | Update a marker to your current location | `squaremarker.update` | 24 | | `/squaremarker remove ` | Remove a marker with ID | `squaremarker.remove` | 25 | 26 | ## Configuration 27 | ```yaml 28 | # Define the main command label 29 | command-label: squaremarker 30 | 31 | # Define the main command aliases 32 | command-aliases: 33 | - marker 34 | - squaremapmarker 35 | - smarker 36 | 37 | # Define the name of the layer 38 | layer-name: Marker 39 | 40 | # Define the link to the marker-icon-image 41 | icon-url: https://github.com/SentixDev/squaremarker/raw/master/resources/default_icon.png 42 | 43 | # Define the icon size 44 | icon-size: 16 45 | 46 | # Whether people can show/hide the markers on their map 47 | show-controls: true 48 | 49 | # Whether the markers are hidden by default 50 | default-hidden: false 51 | 52 | # The rate at which markers will update in milliseconds, defaults to 5000ms or 5 seconds 53 | update-rate-milliseconds: 5000 54 | ``` 55 | 56 | ## Additional 57 | ***Of course, you can also use HTML tags in the content to customize the marker tooltips.*** 58 | 59 | **Old marker files of the "Pl3xMap-Marker" addon are not compatible with this plugin.** 60 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") 3 | id("org.jlleitschuh.gradle.ktlint") 4 | } 5 | 6 | tasks.jar { 7 | enabled = false 8 | } 9 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | id("org.jlleitschuh.gradle.ktlint") version "11.0.0" 4 | } 5 | 6 | repositories { 7 | gradlePluginPortal() 8 | mavenCentral() 9 | maven("https://repo.papermc.io/repository/maven-public/") 10 | maven("https://maven.fabricmc.net/") 11 | maven("https://maven.architectury.dev/") 12 | maven("https://repo.jpenilla.xyz/snapshots/") 13 | } 14 | 15 | dependencies { 16 | implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20") 17 | implementation("org.jlleitschuh.gradle:ktlint-gradle:12.0.2") 18 | implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.0") 19 | implementation("xyz.jpenilla:quiet-architectury-loom:1.7-SNAPSHOT") 20 | } 21 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/CopyFile.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.DefaultTask 2 | import org.gradle.api.file.RegularFileProperty 3 | import org.gradle.api.tasks.InputFile 4 | import org.gradle.api.tasks.OutputFile 5 | import org.gradle.api.tasks.TaskAction 6 | 7 | abstract class CopyFile : DefaultTask() { 8 | @get:InputFile 9 | abstract val fileToCopy: RegularFileProperty 10 | 11 | @get:OutputFile 12 | abstract val destination: RegularFileProperty 13 | 14 | @TaskAction 15 | private fun copyFile() { 16 | destination.get().asFile.parentFile.mkdirs() 17 | fileToCopy.get().asFile.copyTo(destination.get().asFile, overwrite = true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/SquareMarkerPlatformExtension.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.file.RegularFileProperty 2 | import org.gradle.api.model.ObjectFactory 3 | import org.gradle.api.provider.Property 4 | import javax.inject.Inject 5 | 6 | abstract class SquareMarkerPlatformExtension { 7 | abstract val productionJar: RegularFileProperty 8 | 9 | abstract val modInfoFilePath: Property 10 | } 11 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/squaremarker.base.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | import org.gradle.jvm.toolchain.JavaLanguageVersion 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | plugins { 6 | base 7 | id("org.jetbrains.kotlin.jvm") 8 | id("java-library") 9 | id("org.jlleitschuh.gradle.ktlint") 10 | } 11 | 12 | kotlin { 13 | compilerOptions { 14 | jvmTarget = JvmTarget.JVM_21 15 | } 16 | } 17 | 18 | tasks { 19 | withType { 20 | listOf( 21 | "kotlin", 22 | "org.bstats", 23 | "io.leangen.geantyref", 24 | "org.spongepowered.configurate", 25 | "org.yaml.snakeyaml", 26 | ).forEach { relocate(it, "${rootProject.group}.lib.$it") } 27 | dependencies { 28 | exclude(dependency("org.jetbrains:annotations")) 29 | } 30 | } 31 | } 32 | 33 | kotlin { 34 | jvmToolchain { 35 | languageVersion = JavaLanguageVersion.of(21) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/squaremarker.platform.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("squaremarker.base") 3 | id("com.gradleup.shadow") 4 | } 5 | 6 | val platform = extensions.create("squareMarker", SquareMarkerPlatformExtension::class) 7 | 8 | tasks { 9 | val copyJar = register("copyJar") { 10 | fileToCopy.set(platform.productionJar) 11 | destination.set( 12 | platform.productionJar.flatMap { 13 | rootProject.layout.buildDirectory.file("libs/${it.asFile.name}") 14 | } 15 | ) 16 | } 17 | shadowJar { 18 | dependencies { 19 | exclude { 20 | it.moduleGroup == "org.checkerframework" 21 | || it.moduleGroup == "com.google.errorprone" 22 | || it.moduleGroup == "org.apiguardian" 23 | } 24 | } 25 | } 26 | assemble { 27 | dependsOn(copyJar) 28 | } 29 | } 30 | 31 | afterEvaluate { 32 | tasks.processResources { 33 | inputs.property("version", project.version) 34 | 35 | filesMatching(platform.modInfoFilePath.get()) { 36 | expand("version" to project.version) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/squaremarker.platform.loom.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("squaremarker.platform") 3 | id("xyz.jpenilla.quiet-architectury-loom") 4 | id("com.gradleup.shadow") 5 | } 6 | 7 | val minecraftVersion: String by rootProject 8 | 9 | val projectImpl: Configuration by configurations.creating 10 | configurations.implementation { 11 | extendsFrom(projectImpl) 12 | } 13 | 14 | dependencies { 15 | minecraft("com.mojang:minecraft:$minecraftVersion") 16 | mappings(loom.officialMojangMappings()) 17 | projectImpl(project(":squaremarker-common")) 18 | } 19 | 20 | val markerExt = extensions.getByType() 21 | markerExt.productionJar = tasks.remapJar.flatMap { it.archiveFile } 22 | 23 | tasks { 24 | shadowJar { 25 | configurations = listOf(projectImpl) 26 | dependencies { 27 | exclude { 28 | it.moduleGroup == "org.incendo" 29 | } 30 | } 31 | } 32 | remapJar { 33 | inputFile.set(shadowJar.flatMap { it.archiveFile }) 34 | archiveFileName.set("${project.name}-mc$minecraftVersion-${project.version}.jar") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("squaremarker.base") 3 | } 4 | 5 | val squaremapVersion: String by rootProject 6 | val cloudVersion: String by rootProject 7 | val cloudMinecraftVersion: String by rootProject 8 | val adventureVersion: String by rootProject 9 | val gsonVersion: String by rootProject 10 | val configurateVersion: String by rootProject 11 | 12 | dependencies { 13 | compileOnlyApi("xyz.jpenilla", "squaremap-api", squaremapVersion) 14 | api(platform("org.incendo:cloud-bom:$cloudVersion")) 15 | api(platform("org.incendo:cloud-minecraft-bom:$cloudMinecraftVersion")) 16 | api("org.incendo", "cloud-core") 17 | api("org.incendo", "cloud-brigadier") 18 | api("org.incendo", "cloud-annotations") 19 | api("org.incendo", "cloud-minecraft-extras") { 20 | isTransitive = false 21 | } 22 | api("org.incendo", "cloud-kotlin-extensions") 23 | compileOnly("com.google.code.gson", "gson", gsonVersion) 24 | compileOnly("net.kyori", "adventure-text-minimessage", adventureVersion) 25 | compileOnly("net.kyori", "adventure-text-logger-slf4j", adventureVersion) 26 | api(platform("org.spongepowered:configurate-bom:$configurateVersion")) 27 | api("org.spongepowered:configurate-yaml") 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/kotlin/Components.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | import net.kyori.adventure.audience.Audience 4 | import net.kyori.adventure.text.Component 5 | import net.kyori.adventure.text.minimessage.MiniMessage 6 | 7 | object Components { 8 | fun parse(input: String): Component { 9 | return MiniMessage.miniMessage().deserialize(input) 10 | } 11 | 12 | fun send( 13 | audience: Audience, 14 | input: String, 15 | ) { 16 | audience.sendMessage(parse("$input")) 17 | } 18 | 19 | fun sendPrefixed( 20 | audience: Audience, 21 | input: String, 22 | ) { 23 | audience.sendMessage(parse("${Lang.PREFIX} $input")) 24 | } 25 | 26 | fun url( 27 | content: String, 28 | hoverText: String, 29 | openUrl: String, 30 | ): String { 31 | return "${hoverable(hoverText)}$content" 32 | } 33 | 34 | fun clickable( 35 | content: String, 36 | hoverText: String, 37 | clickExecution: String, 38 | ): String { 39 | return "${hoverable(hoverText)}$content" 40 | } 41 | 42 | /* 43 | run_command 44 | suggest_command 45 | copy_to_clipboard 46 | open_file 47 | open_url 48 | */ 49 | fun clickable( 50 | content: String, 51 | hoverText: String, 52 | clickAction: String, 53 | clickExecution: String, 54 | ): String { 55 | return "${hoverable(hoverText)}$content" 56 | } 57 | 58 | fun hoverable(hoverText: String): String { 59 | return "" 60 | } 61 | 62 | fun gradient(input: String): String { 63 | return "$input" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /common/src/main/kotlin/Configuration.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | import org.spongepowered.configurate.objectmapping.ConfigSerializable 4 | 5 | @ConfigSerializable 6 | class Configuration { 7 | val commandLabel = "squaremarker" 8 | val commandAliases = mutableListOf("marker", "squaremapmarker", "smarker") 9 | val layerName = "Marker" 10 | val iconUrl = "https://github.com/SentixDev/squaremarker/raw/master/resources/default_icon.png" 11 | val iconSize = 16 12 | val showControls = true 13 | val defaultHidden = false 14 | val updateRateMilliseconds = 5L * 1000L // 5 seconds 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/kotlin/IO.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import dev.sentix.squaremarker.marker.Marker 6 | import xyz.jpenilla.squaremap.api.WorldIdentifier 7 | import kotlin.io.path.bufferedReader 8 | import kotlin.io.path.bufferedWriter 9 | import kotlin.io.path.createDirectories 10 | import kotlin.io.path.exists 11 | 12 | object IO { 13 | val gson: Gson = 14 | GsonBuilder() 15 | .registerTypeAdapter(WorldIdentifier::class.java, SquareMarker.instance.worldIdentifierSerializer) 16 | .create() 17 | 18 | private val gsonPrettier: Gson = 19 | gson.newBuilder() 20 | .setPrettyPrinting() 21 | .create() 22 | 23 | private val markerFile = SquareMarker.instance.markerFile 24 | 25 | fun init() { 26 | val emptyMarkerList = emptyList() 27 | if (!markerFile.exists()) { 28 | write(emptyMarkerList) 29 | } 30 | } 31 | 32 | fun write(input: List) { 33 | if (!markerFile.parent.exists()) { 34 | markerFile.parent.createDirectories() 35 | } 36 | markerFile.bufferedWriter().use { it.write(gsonPrettier.toJson(input)) } 37 | } 38 | 39 | fun read(): String { 40 | return markerFile.bufferedReader().use { it.readText() } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/kotlin/Lang.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | object Lang { 4 | const val PLAIN_PREFIX = "[squaremarker]" 5 | const val PREFIX = "[squaremarker]" 6 | 7 | const val NO_PERMISSION = "Not authorized." 8 | 9 | const val EMPTY = "$PREFIX No markers set." 10 | 11 | val HELP = 12 | Components.clickable( 13 | "$PREFIX ", 14 | Components.gradient("Click for SquareMarker command help"), 15 | "/${SquareMarker.instance.config.commandLabel} help", 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/kotlin/SquareMarker.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | import dev.sentix.squaremarker.command.Commander 4 | import dev.sentix.squaremarker.command.Commands 5 | import dev.sentix.squaremarker.marker.API 6 | import org.incendo.cloud.CommandManager 7 | import org.slf4j.Logger 8 | import org.slf4j.LoggerFactory 9 | import org.spongepowered.configurate.yaml.NodeStyle 10 | import org.spongepowered.configurate.yaml.YamlConfigurationLoader 11 | import java.nio.file.Path 12 | 13 | class SquareMarker( 14 | commandManager: CommandManager, 15 | private val configFile: Path, 16 | dataDir: Path, 17 | val worldIdentifierSerializer: Any = WorldIdentifierSerializer, 18 | ) { 19 | companion object { 20 | val logger: Logger = LoggerFactory.getLogger(SquareMarker::class.java) 21 | lateinit var instance: SquareMarker 22 | } 23 | 24 | val markerFile: Path = dataDir.resolve("marker.json") 25 | val config: Configuration = loadConfiguration() 26 | 27 | init { 28 | instance = this 29 | 30 | Commands(this, commandManager).registerCommands() 31 | } 32 | 33 | fun init() { 34 | IO.init() 35 | 36 | API.init() 37 | } 38 | 39 | fun shutdown() { 40 | API.unregister() 41 | } 42 | 43 | private fun loadConfiguration(): Configuration { 44 | val loader = 45 | YamlConfigurationLoader.builder() 46 | .path(configFile) 47 | .nodeStyle(NodeStyle.BLOCK) 48 | .build() 49 | val node = loader.load() 50 | val configInst = node.get(Configuration::class.java) ?: error("Error reading config") 51 | val save = loader.createNode() 52 | save.set(configInst) 53 | loader.save(save) 54 | return configInst 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /common/src/main/kotlin/WorldIdentifierSerializer.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker 2 | 3 | import com.google.gson.JsonDeserializationContext 4 | import com.google.gson.JsonDeserializer 5 | import com.google.gson.JsonElement 6 | import com.google.gson.JsonNull 7 | import com.google.gson.JsonPrimitive 8 | import com.google.gson.JsonSerializationContext 9 | import com.google.gson.JsonSerializer 10 | import xyz.jpenilla.squaremap.api.WorldIdentifier 11 | import java.lang.reflect.Type 12 | 13 | object WorldIdentifierSerializer : 14 | JsonSerializer, 15 | JsonDeserializer { 16 | override fun serialize( 17 | src: WorldIdentifier?, 18 | typeOfSrc: Type, 19 | context: JsonSerializationContext, 20 | ): JsonElement { 21 | if (src == null) return JsonNull.INSTANCE 22 | return JsonPrimitive(src.asString()) 23 | } 24 | 25 | override fun deserialize( 26 | json: JsonElement?, 27 | typeOfT: Type, 28 | context: JsonDeserializationContext, 29 | ): WorldIdentifier? { 30 | if (json == null || json is JsonNull) return null 31 | return WorldIdentifier.parse(json.asString) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/Commander.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command 2 | 3 | import net.kyori.adventure.audience.Audience 4 | 5 | interface Commander : Audience 6 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/Commands.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.Lang 5 | import dev.sentix.squaremarker.SquareMarker 6 | import dev.sentix.squaremarker.command.commands.HelpCommand 7 | import dev.sentix.squaremarker.command.commands.ListMarkerCommand 8 | import dev.sentix.squaremarker.command.commands.RemoveMarkerCommand 9 | import dev.sentix.squaremarker.command.commands.SetMarkerCommand 10 | import dev.sentix.squaremarker.command.commands.ShowMarkerCommand 11 | import dev.sentix.squaremarker.command.commands.UpdateMarkerCommand 12 | import net.kyori.adventure.text.Component.text 13 | import net.kyori.adventure.text.format.NamedTextColor 14 | import org.incendo.cloud.Command 15 | import org.incendo.cloud.CommandManager 16 | import org.incendo.cloud.description.Description.description 17 | import org.incendo.cloud.exception.InvalidCommandSenderException 18 | import org.incendo.cloud.exception.NoPermissionException 19 | import org.incendo.cloud.minecraft.extras.MinecraftExceptionHandler 20 | import org.incendo.cloud.util.TypeUtils 21 | 22 | class Commands( 23 | private val squareMarker: SquareMarker, 24 | val commandManager: CommandManager, 25 | ) { 26 | init { 27 | registerExceptionHandlers() 28 | } 29 | 30 | fun registerCommands() { 31 | listOf( 32 | HelpCommand(squareMarker, this), 33 | ListMarkerCommand(squareMarker, this), 34 | RemoveMarkerCommand(squareMarker, this), 35 | SetMarkerCommand(squareMarker, this), 36 | ShowMarkerCommand(squareMarker, this), 37 | UpdateMarkerCommand(squareMarker, this), 38 | ).forEach(SquaremarkerCommand::register) 39 | } 40 | 41 | private fun registerExceptionHandlers() { 42 | MinecraftExceptionHandler.createNative() 43 | .defaultArgumentParsingHandler() 44 | .defaultInvalidSenderHandler() 45 | .defaultCommandExecutionHandler() 46 | .handler(InvalidCommandSenderException::class.java) { _, ctx -> 47 | val requiredTypeDisplayName = 48 | when (ctx.exception().requiredSenderTypes().single()) { 49 | PlayerCommander::class.java -> "Players" 50 | else -> TypeUtils.simpleName(ctx.exception().requiredSenderTypes().single()) 51 | } 52 | text() 53 | .content("This command can only be executed by ") 54 | .color(NamedTextColor.RED) 55 | .append(text(requiredTypeDisplayName, NamedTextColor.GRAY)) 56 | .append(text('!')) 57 | .build() 58 | } 59 | .handler(NoPermissionException::class.java) { _, _ -> Components.parse(Lang.NO_PERMISSION) } 60 | .decorator { c -> Components.parse(Lang.HELP).append(c) } 61 | .registerTo(commandManager) 62 | } 63 | 64 | fun registerSubcommand(builderModifier: (Command.Builder) -> Command.Builder) { 65 | commandManager.command(builderModifier(rootBuilder())) 66 | } 67 | 68 | private fun rootBuilder(): Command.Builder = 69 | commandManager.commandBuilder( 70 | squareMarker.config.commandLabel, 71 | description("Squaremarker command. '/${squareMarker.config.commandLabel} help'"), 72 | *squareMarker.config.commandAliases.toTypedArray(), 73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/PlayerCommander.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command 2 | 3 | import xyz.jpenilla.squaremap.api.WorldIdentifier 4 | 5 | interface PlayerCommander : Commander { 6 | val world: WorldIdentifier 7 | val x: Double 8 | val y: Double 9 | val z: Double 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/SquaremarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command 2 | 3 | import dev.sentix.squaremarker.SquareMarker 4 | 5 | abstract class SquaremarkerCommand protected constructor( 6 | protected val squareMarker: SquareMarker, 7 | protected val commands: Commands, 8 | ) { 9 | abstract fun register() 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/HelpCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.SquareMarker 5 | import dev.sentix.squaremarker.command.Commander 6 | import dev.sentix.squaremarker.command.Commands 7 | import dev.sentix.squaremarker.command.SquaremarkerCommand 8 | import net.kyori.adventure.text.format.NamedTextColor 9 | import net.kyori.adventure.text.format.TextColor 10 | import org.incendo.cloud.component.CommandComponent 11 | import org.incendo.cloud.context.CommandContext 12 | import org.incendo.cloud.minecraft.extras.AudienceProvider 13 | import org.incendo.cloud.minecraft.extras.MinecraftHelp 14 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 15 | import org.incendo.cloud.parser.standard.StringParser.greedyStringParser 16 | import org.incendo.cloud.suggestion.Suggestion.suggestion 17 | import org.incendo.cloud.suggestion.SuggestionProvider 18 | 19 | class HelpCommand(plugin: SquareMarker, commands: Commands) : 20 | SquaremarkerCommand( 21 | plugin, 22 | commands, 23 | ) { 24 | private val help = createHelp() 25 | 26 | override fun register() { 27 | val helpQueryArgument = 28 | CommandComponent.builder("query", greedyStringParser()) 29 | .suggestionProvider( 30 | SuggestionProvider.blocking { context, _ -> 31 | commands.commandManager.createHelpHandler().queryRootIndex(context.sender()) 32 | .entries() 33 | .map { it.syntax() } 34 | .map { suggestion(it) } 35 | .toList() 36 | }, 37 | ) 38 | .optional() 39 | .build() 40 | 41 | commands.registerSubcommand { builder -> 42 | builder.literal("help") 43 | .argument(helpQueryArgument) 44 | .commandDescription(richDescription(Components.parse("Show marker help."))) 45 | .permission("squaremarker.help") 46 | .handler(::execute) 47 | } 48 | } 49 | 50 | private fun execute(context: CommandContext) { 51 | help.queryCommands(context.getOrDefault("query", ""), context.sender()) 52 | } 53 | 54 | private fun createHelp(): MinecraftHelp { 55 | return MinecraftHelp.builder() 56 | .commandManager(commands.commandManager) 57 | .audienceProvider(AudienceProvider.nativeAudience()) 58 | .commandPrefix("/${squareMarker.config.commandLabel} help") 59 | .colors( 60 | MinecraftHelp.helpColors( 61 | TextColor.color(0x5B00FF), 62 | NamedTextColor.WHITE, 63 | TextColor.color(0xC028FF), 64 | NamedTextColor.GRAY, 65 | NamedTextColor.DARK_GRAY, 66 | ), 67 | ) 68 | .messages(MinecraftHelp.MESSAGE_HELP_TITLE, "squaremarker command help") 69 | .build() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/ListMarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.Lang 5 | import dev.sentix.squaremarker.SquareMarker 6 | import dev.sentix.squaremarker.command.Commander 7 | import dev.sentix.squaremarker.command.Commands 8 | import dev.sentix.squaremarker.command.SquaremarkerCommand 9 | import dev.sentix.squaremarker.marker.Marker 10 | import dev.sentix.squaremarker.marker.MarkerService 11 | import org.incendo.cloud.context.CommandContext 12 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 13 | 14 | class ListMarkerCommand(plugin: SquareMarker, commands: Commands) : 15 | SquaremarkerCommand( 16 | plugin, 17 | commands, 18 | ) { 19 | override fun register() { 20 | commands.registerSubcommand { builder -> 21 | builder.literal("list") 22 | .commandDescription(richDescription(Components.parse("List all markers."))) 23 | .permission("squaremarker.list") 24 | .handler(::execute) 25 | } 26 | } 27 | 28 | private fun execute(context: CommandContext) { 29 | val sender = context.sender() 30 | 31 | val markerList = MarkerService.getMarkerList() 32 | 33 | if (markerList.isNotEmpty()) { 34 | sendMarkerList(sender, markerList) 35 | } else { 36 | Components.send(sender, Lang.EMPTY) 37 | } 38 | } 39 | 40 | private fun sendMarkerList( 41 | sender: Commander, 42 | markerList: MutableList, 43 | ) { 44 | val gradient = Components.gradient("Marker") 45 | 46 | Components.send(sender, "") 47 | Components.send( 48 | sender, 49 | "» ------------- × $gradient × ------------- «", 50 | ) 51 | Components.send(sender, "") 52 | 53 | Components.send(sender, " × Markers [" + markerList.size + "]") 54 | Components.send(sender, "") 55 | for (marker in markerList) { 56 | Components.send( 57 | sender, 58 | " × ${marker.id} ${ 59 | Components.clickable( 60 | "[SHOW]", 61 | "SHOW", 62 | "/squaremarker show ${marker.id}", 63 | ) 64 | }", 65 | ) 66 | } 67 | 68 | Components.send(sender, "") 69 | Components.send( 70 | sender, 71 | "» ------------- × $gradient × ------------- «", 72 | ) 73 | Components.send(sender, "") 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/RemoveMarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.SquareMarker 5 | import dev.sentix.squaremarker.command.Commander 6 | import dev.sentix.squaremarker.command.Commands 7 | import dev.sentix.squaremarker.command.SquaremarkerCommand 8 | import dev.sentix.squaremarker.marker.MarkerService 9 | import org.incendo.cloud.context.CommandContext 10 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 11 | import org.incendo.cloud.parser.standard.IntegerParser.integerParser 12 | 13 | class RemoveMarkerCommand(plugin: SquareMarker, commands: Commands) : 14 | SquaremarkerCommand( 15 | plugin, 16 | commands, 17 | ) { 18 | override fun register() { 19 | commands.registerSubcommand { builder -> 20 | builder.literal("remove") 21 | .required("id", integerParser()) 22 | .commandDescription(richDescription(Components.parse("Remove a marker by id."))) 23 | .permission("squaremarker.remove") 24 | .handler(::execute) 25 | } 26 | } 27 | 28 | private fun execute(context: CommandContext) { 29 | val sender = context.sender() 30 | 31 | val id: Int = context.get("id") 32 | 33 | if (MarkerService.markerExist(id)) { 34 | MarkerService.removeMarker(id) 35 | Components.sendPrefixed(sender, "Removed marker with ID $id.") 36 | } else { 37 | Components.sendPrefixed(sender, "No marker with ID $id found.") 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/SetMarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.SquareMarker 5 | import dev.sentix.squaremarker.command.Commands 6 | import dev.sentix.squaremarker.command.PlayerCommander 7 | import dev.sentix.squaremarker.command.SquaremarkerCommand 8 | import dev.sentix.squaremarker.marker.Marker 9 | import dev.sentix.squaremarker.marker.MarkerService 10 | import org.incendo.cloud.component.DefaultValue 11 | import org.incendo.cloud.context.CommandContext 12 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 13 | import org.incendo.cloud.parser.standard.StringParser.greedyStringParser 14 | import xyz.jpenilla.squaremap.api.Key 15 | import xyz.jpenilla.squaremap.api.SquaremapProvider 16 | import java.net.URI 17 | import javax.imageio.ImageIO 18 | import kotlin.random.Random.Default.nextInt 19 | 20 | class SetMarkerCommand(plugin: SquareMarker, commands: Commands) : 21 | SquaremarkerCommand( 22 | plugin, 23 | commands, 24 | ) { 25 | override fun register() { 26 | commands.registerSubcommand { builder -> 27 | builder.literal("set") 28 | .optional("input", greedyStringParser(), DefaultValue.constant(" ")) 29 | .commandDescription(richDescription(Components.parse("Set a marker at your position."))) 30 | .permission("squaremarker.set") 31 | .senderType(PlayerCommander::class.java) 32 | .handler(::execute) 33 | } 34 | } 35 | 36 | private fun execute(context: CommandContext) { 37 | val sender = context.sender() 38 | 39 | val id: Int = nextInt(9, 100000) 40 | 41 | val iconKey = "squaremarker_marker_icon_$id" 42 | 43 | val input: String = context.get("input") 44 | 45 | var content = input 46 | 47 | var url = "" 48 | 49 | if (input.contains("http")) { 50 | val split = input.split("http") 51 | 52 | content = split[0] 53 | 54 | url = "http${split[1]}" 55 | } 56 | 57 | val marker = 58 | Marker( 59 | id, 60 | content.trim(), 61 | url.trim(), 62 | iconKey, 63 | sender.world, 64 | sender.x, 65 | sender.y, 66 | sender.z, 67 | ) 68 | 69 | if (!MarkerService.markerExist(id)) { 70 | MarkerService.addMarker(marker) 71 | Components.sendPrefixed(sender, "Created marker with ID $id.") 72 | 73 | try { 74 | SquaremapProvider.get().iconRegistry().register( 75 | Key.key(marker.iconKey), 76 | ImageIO.read( 77 | URI.create(marker.iconUrl).toURL(), 78 | ), 79 | ) 80 | } catch (ex: Exception) { 81 | Components.sendPrefixed(sender, "Marker icon set to default.") 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/ShowMarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.SquareMarker 5 | import dev.sentix.squaremarker.command.Commander 6 | import dev.sentix.squaremarker.command.Commands 7 | import dev.sentix.squaremarker.command.SquaremarkerCommand 8 | import dev.sentix.squaremarker.marker.Marker 9 | import dev.sentix.squaremarker.marker.MarkerService 10 | import org.incendo.cloud.context.CommandContext 11 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 12 | import org.incendo.cloud.parser.standard.IntegerParser.integerParser 13 | 14 | class ShowMarkerCommand(plugin: SquareMarker, commands: Commands) : 15 | SquaremarkerCommand( 16 | plugin, 17 | commands, 18 | ) { 19 | override fun register() { 20 | commands.registerSubcommand { builder -> 21 | builder.literal("show") 22 | .required("id", integerParser()) 23 | .commandDescription(richDescription(Components.parse("Show a marker by id."))) 24 | .permission("squaremarker.show") 25 | .handler(::execute) 26 | } 27 | } 28 | 29 | private fun execute(context: CommandContext) { 30 | val sender = context.sender() 31 | 32 | val id: Int = context.get("id") 33 | 34 | if (MarkerService.markerExist(id)) { 35 | sendMarkerOverview(sender, MarkerService.getMarker(id)) 36 | } else { 37 | Components.sendPrefixed(sender, "No marker with ID $id found.") 38 | } 39 | } 40 | 41 | private fun sendMarkerOverview( 42 | sender: Commander, 43 | marker: Marker, 44 | ) { 45 | val gradient = Components.gradient("Marker") 46 | val div = 47 | "» ------------- × $gradient × ------------- «" 48 | 49 | Components.send(sender, "") 50 | Components.send( 51 | sender, 52 | div, 53 | ) 54 | Components.send(sender, "") 55 | 56 | Components.send(sender, " × ID | ${marker.id}") 57 | if (marker.content.isNotBlank()) { 58 | Components.send( 59 | sender, 60 | " × TEXT | ${marker.content}", 61 | ) 62 | } 63 | if (marker.iconUrl.isNotBlank()) { 64 | Components.send( 65 | sender, 66 | " × URL | ${ 67 | Components.url( 68 | "${marker.iconUrl}", 69 | "SHOW", 70 | marker.iconUrl, 71 | ) 72 | }", 73 | ) 74 | } 75 | 76 | Components.send(sender, "") 77 | Components.send( 78 | sender, 79 | " × ${ 80 | Components.clickable( 81 | "[UPDATE]", 82 | "UPDATE MARKER", 83 | "suggest_command", 84 | "/squaremarker update ${marker.id} ", 85 | ) 86 | } ${ 87 | Components.clickable( 88 | "[REMOVE]", 89 | "REMOVE MARKER", 90 | "/squaremarker remove ${marker.id}", 91 | ) 92 | }", 93 | ) 94 | Components.send(sender, "") 95 | Components.send( 96 | sender, 97 | " × ${ 98 | Components.clickable( 99 | "[LIST]", 100 | "SHOW LIST", 101 | "/squaremarker list", 102 | ) 103 | }", 104 | ) 105 | Components.send(sender, "") 106 | Components.send( 107 | sender, 108 | div, 109 | ) 110 | Components.send(sender, "") 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /common/src/main/kotlin/command/commands/UpdateMarkerCommand.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.command.commands 2 | 3 | import dev.sentix.squaremarker.Components 4 | import dev.sentix.squaremarker.SquareMarker 5 | import dev.sentix.squaremarker.command.Commands 6 | import dev.sentix.squaremarker.command.PlayerCommander 7 | import dev.sentix.squaremarker.command.SquaremarkerCommand 8 | import dev.sentix.squaremarker.marker.Marker 9 | import dev.sentix.squaremarker.marker.MarkerService 10 | import org.incendo.cloud.component.DefaultValue 11 | import org.incendo.cloud.context.CommandContext 12 | import org.incendo.cloud.minecraft.extras.RichDescription.richDescription 13 | import org.incendo.cloud.parser.standard.IntegerParser.integerParser 14 | import org.incendo.cloud.parser.standard.StringParser.greedyStringParser 15 | import xyz.jpenilla.squaremap.api.Key 16 | import xyz.jpenilla.squaremap.api.SquaremapProvider 17 | import java.io.File 18 | import java.net.URI 19 | import javax.imageio.ImageIO 20 | 21 | class UpdateMarkerCommand(plugin: SquareMarker, commands: Commands) : 22 | SquaremarkerCommand( 23 | plugin, 24 | commands, 25 | ) { 26 | override fun register() { 27 | commands.registerSubcommand { builder -> 28 | builder.literal("update") 29 | .required("id", integerParser()) 30 | .optional("input", greedyStringParser(), DefaultValue.constant(" ")) 31 | .commandDescription(richDescription(Components.parse("Update a marker to your position."))) 32 | .permission("squaremarker.set") 33 | .senderType(PlayerCommander::class.java) 34 | .handler(::execute) 35 | } 36 | } 37 | 38 | private fun execute(context: CommandContext) { 39 | val sender = context.sender() 40 | 41 | val id: Int = context.get("id") 42 | 43 | val iconKey = "squaremarker_marker_icon_$id" 44 | 45 | val input: String = context.get("input") 46 | 47 | var content = input 48 | 49 | var url = "" 50 | 51 | if (input.contains("http")) { 52 | val split = input.split("http") 53 | 54 | content = split[0] 55 | 56 | url = "http${split[1]}" 57 | } 58 | 59 | val marker = 60 | Marker( 61 | id, 62 | content.trim(), 63 | url.trim(), 64 | iconKey, 65 | sender.world, 66 | sender.x, 67 | sender.y, 68 | sender.z, 69 | ) 70 | 71 | if (MarkerService.markerExist(id)) { 72 | if (MarkerService.getMarker(id).iconUrl.isNotBlank()) { 73 | SquaremapProvider.get().iconRegistry().unregister(Key.key(marker.iconKey)) 74 | File("${SquaremapProvider.get().webDir()}/images/icon/registered/${marker.iconKey}.png").delete() 75 | } 76 | 77 | try { 78 | SquaremapProvider.get().iconRegistry().register( 79 | Key.key(marker.iconKey), 80 | ImageIO.read( 81 | URI(marker.iconUrl).toURL(), 82 | ), 83 | ) 84 | } catch (ex: Exception) { 85 | Components.sendPrefixed(sender, "Marker icon set to default.") 86 | } 87 | 88 | MarkerService.updateMarker(marker) 89 | Components.sendPrefixed(sender, "Updated existing marker with ID $id.") 90 | } else { 91 | Components.sendPrefixed(sender, "No marker with ID $id found.") 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /common/src/main/kotlin/marker/API.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.marker 2 | 3 | import dev.sentix.squaremarker.Lang 4 | import dev.sentix.squaremarker.SquareMarker 5 | import xyz.jpenilla.squaremap.api.Key 6 | import xyz.jpenilla.squaremap.api.MapWorld 7 | import xyz.jpenilla.squaremap.api.SimpleLayerProvider 8 | import xyz.jpenilla.squaremap.api.SquaremapProvider 9 | import xyz.jpenilla.squaremap.api.WorldIdentifier 10 | import java.net.URI 11 | import java.util.concurrent.Executors 12 | import java.util.concurrent.ScheduledExecutorService 13 | import java.util.concurrent.ScheduledFuture 14 | import java.util.concurrent.TimeUnit 15 | import javax.imageio.ImageIO 16 | 17 | object API { 18 | val markerIconKey: Key = Key.of("squaremarker_marker_icon_") 19 | 20 | private val executor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor() 21 | private val providerMap: MutableMap, MarkerTask>> = HashMap() 22 | 23 | fun init() { 24 | registerIcons() 25 | 26 | SquaremapProvider.get().mapWorlds().forEach(::initWorld) 27 | } 28 | 29 | fun unloadWorld(mapWorld: MapWorld) { 30 | providerMap.remove(mapWorld.identifier())?.apply { 31 | second.disable() 32 | first.cancel(true) 33 | } 34 | } 35 | 36 | fun initWorld(mapWorld: MapWorld) { 37 | if (mapWorld.identifier() in providerMap) { 38 | return 39 | } 40 | 41 | val provider: SimpleLayerProvider = 42 | SimpleLayerProvider.builder(SquareMarker.instance.config.layerName).apply { 43 | defaultHidden(SquareMarker.instance.config.defaultHidden) 44 | showControls(SquareMarker.instance.config.showControls) 45 | }.build() 46 | val key = Key.of("squaremarker_marker") 47 | if (mapWorld.layerRegistry().hasEntry(key)) { 48 | mapWorld.layerRegistry().unregister(key) 49 | } 50 | mapWorld.layerRegistry().register(key, provider) 51 | val task = MarkerTask(mapWorld, provider) 52 | val scheduled = 53 | executor.scheduleAtFixedRate( 54 | task, 55 | 0, 56 | SquareMarker.instance.config.updateRateMilliseconds, 57 | TimeUnit.MILLISECONDS, 58 | ) 59 | providerMap[mapWorld.identifier()] = Pair(scheduled, task) 60 | } 61 | 62 | private fun registerIcons() { 63 | SquaremapProvider.get().iconRegistry() 64 | .register(markerIconKey, ImageIO.read(URI.create(SquareMarker.instance.config.iconUrl).toURL())) 65 | for (marker in MarkerService.getMarkerList()) { 66 | if (marker.iconUrl.isNotBlank()) { 67 | try { 68 | SquaremapProvider.get().iconRegistry() 69 | .register(Key.of("squaremarker_marker_icon_${marker.id}"), ImageIO.read(URI.create(marker.iconUrl).toURL())) 70 | } catch (ex: Exception) { 71 | SquareMarker.logger.warn( 72 | "${Lang.PLAIN_PREFIX} There is an invalid url in your marker.json. Please fix \"${marker.iconUrl}\"!", 73 | ex, 74 | ) 75 | } 76 | } 77 | } 78 | } 79 | 80 | fun cancel(world: WorldIdentifier) { 81 | providerMap[world]?.first?.cancel(true) 82 | } 83 | 84 | fun unregister() { 85 | providerMap.values.forEach { (future, task) -> 86 | task.disable() 87 | future.cancel(true) 88 | } 89 | providerMap.clear() 90 | executor.shutdownNow() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /common/src/main/kotlin/marker/Marker.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.marker 2 | 3 | import xyz.jpenilla.squaremap.api.WorldIdentifier 4 | 5 | data class Marker( 6 | val id: Int, 7 | val content: String, 8 | val iconUrl: String, 9 | val iconKey: String, 10 | val world: WorldIdentifier, 11 | val posX: Double, 12 | val posY: Double, 13 | val posZ: Double, 14 | ) 15 | -------------------------------------------------------------------------------- /common/src/main/kotlin/marker/MarkerService.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.marker 2 | 3 | import com.google.gson.reflect.TypeToken 4 | import dev.sentix.squaremarker.IO 5 | 6 | object MarkerService { 7 | fun getMarkerList(): MutableList { 8 | val type = object : TypeToken>() {}.type 9 | return IO.gson.fromJson(IO.read(), type) 10 | } 11 | 12 | fun getMarker(id: Int): Marker { 13 | return getMarkerList().filter { it.id == id }[0] 14 | } 15 | 16 | fun markerExist(id: Int): Boolean { 17 | return try { 18 | getMarker(id) 19 | true 20 | } catch (_: IndexOutOfBoundsException) { 21 | false 22 | } 23 | } 24 | 25 | fun addMarker(marker: Marker) { 26 | val markerList = getMarkerList() 27 | markerList.add(marker) 28 | IO.write(markerList) 29 | } 30 | 31 | fun removeMarker(id: Int) { 32 | val markerList = getMarkerList() 33 | markerList.filter { it.id != id }.toMutableList().let { it1 -> IO.write(it1) } 34 | } 35 | 36 | fun updateMarker(marker: Marker) { 37 | removeMarker(marker.id) 38 | addMarker(marker) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/src/main/kotlin/marker/MarkerTask.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.marker 2 | 3 | import dev.sentix.squaremarker.SquareMarker 4 | import xyz.jpenilla.squaremap.api.Key 5 | import xyz.jpenilla.squaremap.api.MapWorld 6 | import xyz.jpenilla.squaremap.api.Point 7 | import xyz.jpenilla.squaremap.api.SimpleLayerProvider 8 | import xyz.jpenilla.squaremap.api.marker.Icon 9 | import xyz.jpenilla.squaremap.api.marker.Marker 10 | import xyz.jpenilla.squaremap.api.marker.MarkerOptions 11 | 12 | class MarkerTask(world: MapWorld, provider: SimpleLayerProvider) : Runnable { 13 | private val world: MapWorld 14 | private val provider: SimpleLayerProvider 15 | private var stop = false 16 | 17 | override fun run() { 18 | if (stop) { 19 | API.cancel(world.identifier()) 20 | } 21 | 22 | provider.clearMarkers() 23 | MarkerService.getMarkerList().forEach { marker -> 24 | if (marker.world == world.identifier()) { 25 | val iconKey: Key = 26 | if (marker.iconUrl != "") { 27 | Key.of(marker.iconKey) 28 | } else { 29 | API.markerIconKey 30 | } 31 | handle( 32 | marker.id, 33 | marker.content, 34 | iconKey, 35 | marker.posX, 36 | marker.posZ, 37 | ) 38 | } 39 | } 40 | } 41 | 42 | private fun handle( 43 | id: Int, 44 | name: String, 45 | iconKey: Key, 46 | x: Double, 47 | z: Double, 48 | ) { 49 | val icon: Icon = Marker.icon(Point.point(x, z), iconKey, SquareMarker.instance.config.iconSize) 50 | if (name.isNotBlank()) { 51 | icon.markerOptions( 52 | MarkerOptions.builder() 53 | .hoverTooltip( 54 | "
$name
", 55 | ), 56 | ) 57 | } 58 | val markerId = "squaremarker_marker_$id" 59 | provider.addMarker(Key.of(markerId), icon) 60 | } 61 | 62 | fun disable() { 63 | stop = true 64 | provider.clearMarkers() 65 | } 66 | 67 | init { 68 | this.world = world 69 | this.provider = provider 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /fabric/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("squaremarker.platform.loom") 3 | } 4 | 5 | val fabricApiVersion: String by rootProject 6 | val fabricLoaderVersion: String by rootProject 7 | val cloudMinecraftModdedVersion: String by rootProject 8 | val adventureFabricVersion: String by rootProject 9 | 10 | dependencies { 11 | modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") 12 | modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") 13 | 14 | // We don't include() these since squaremap already does and we depend on it 15 | modImplementation("org.incendo:cloud-fabric:$cloudMinecraftModdedVersion") 16 | modImplementation("net.kyori:adventure-platform-fabric:$adventureFabricVersion") 17 | } 18 | 19 | squareMarker { 20 | modInfoFilePath = "fabric.mod.json" 21 | } 22 | -------------------------------------------------------------------------------- /fabric/src/main/kotlin/SquareMarkerInitializer.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.fabric 2 | 3 | import dev.sentix.squaremarker.SquareMarker 4 | import dev.sentix.squaremarker.command.Commander 5 | import dev.sentix.squaremarker.fabric.command.FabricCommander 6 | import dev.sentix.squaremarker.marker.API 7 | import net.fabricmc.api.ModInitializer 8 | import net.fabricmc.fabric.api.event.Event 9 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents 10 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents 11 | import net.fabricmc.loader.api.FabricLoader 12 | import net.fabricmc.loader.api.ModContainer 13 | import net.minecraft.resources.ResourceLocation 14 | import org.incendo.cloud.CommandManager 15 | import org.incendo.cloud.SenderMapper 16 | import org.incendo.cloud.execution.ExecutionCoordinator 17 | import org.incendo.cloud.fabric.FabricServerCommandManager 18 | import xyz.jpenilla.squaremap.api.SquaremapProvider 19 | import xyz.jpenilla.squaremap.api.WorldIdentifier 20 | 21 | class SquareMarkerInitializer : ModInitializer { 22 | companion object { 23 | val modContainer: ModContainer = FabricLoader.getInstance().getModContainer("squaremarker").orElseThrow() 24 | } 25 | 26 | private val squareMarker: SquareMarker = 27 | SquareMarker( 28 | createCommandManager(), 29 | FabricLoader.getInstance().configDir.resolve("${modContainer.metadata.id}.yml"), 30 | FabricLoader.getInstance().gameDir.resolve(modContainer.metadata.id), 31 | ) 32 | 33 | override fun onInitialize() { 34 | // Ensure we initialize after squaremap regardless of load order (future squaremap versions should provide a better mechanism) 35 | ServerLifecycleEvents.SERVER_STARTING.register { squareMarker.init() } 36 | ServerLifecycleEvents.SERVER_STOPPED.register { squareMarker.shutdown() } 37 | 38 | // Use custom late phase as workaround for squaremap <1.1.7 39 | val late = ResourceLocation.parse("squaremarker:late") 40 | ServerWorldEvents.LOAD.register(late) { _, world -> 41 | SquaremapProvider.get().getWorldIfEnabled( 42 | WorldIdentifier.parse(world.dimension().location().toString()), 43 | ).ifPresent(API::initWorld) 44 | } 45 | ServerWorldEvents.LOAD.addPhaseOrdering(Event.DEFAULT_PHASE, late) 46 | 47 | ServerWorldEvents.UNLOAD.register { _, world -> 48 | SquaremapProvider.get().getWorldIfEnabled( 49 | WorldIdentifier.parse(world.dimension().location().toString()), 50 | ).ifPresent(API::unloadWorld) 51 | } 52 | } 53 | 54 | private fun createCommandManager(): CommandManager { 55 | val mgr = 56 | FabricServerCommandManager( 57 | ExecutionCoordinator.simpleCoordinator(), 58 | SenderMapper.create( 59 | { stack -> FabricCommander.create(stack) }, 60 | { commander -> (commander as FabricCommander).sender }, 61 | ), 62 | ) 63 | return mgr 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /fabric/src/main/kotlin/command/FabricCommander.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.fabric.command 2 | 3 | import dev.sentix.squaremarker.command.Commander 4 | import dev.sentix.squaremarker.command.PlayerCommander 5 | import net.kyori.adventure.audience.Audience 6 | import net.kyori.adventure.audience.ForwardingAudience 7 | import net.minecraft.commands.CommandSourceStack 8 | import net.minecraft.server.level.ServerPlayer 9 | import xyz.jpenilla.squaremap.api.WorldIdentifier 10 | 11 | open class FabricCommander(val sender: CommandSourceStack) : Commander, ForwardingAudience.Single { 12 | override fun audience(): Audience = sender 13 | 14 | class Player(sender: CommandSourceStack, private val player: ServerPlayer) : FabricCommander(sender), PlayerCommander { 15 | override val world: WorldIdentifier 16 | get() = WorldIdentifier.parse(player.level().dimension().location().toString()) 17 | override val x: Double 18 | get() = player.x 19 | override val y: Double 20 | get() = player.y 21 | override val z: Double 22 | get() = player.z 23 | } 24 | 25 | companion object { 26 | fun create(sender: CommandSourceStack): Commander { 27 | if (sender.player != null) { 28 | return Player(sender, sender.playerOrException) 29 | } 30 | return FabricCommander(sender) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "squaremarker", 4 | "version": "${version}", 5 | "name": "squaremarker", 6 | "description": "Marker addon for squaremap", 7 | "authors": [ 8 | "Sentix" 9 | ], 10 | "contact": { 11 | "homepage": "https://github.com/SentixDev/squaremarker", 12 | "sources": "https://github.com/SentixDev/squaremarker" 13 | }, 14 | "license": "Unknown (All Rights Reserved)", 15 | "icon": "assets/squaremarker/icon.png", 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "dev.sentix.squaremarker.fabric.SquareMarkerInitializer" 20 | ] 21 | }, 22 | "depends": { 23 | "fabricloader": ">=0.14.6", 24 | "fabric": "*", 25 | "minecraft": "~1.21", 26 | "java": ">=17", 27 | "squaremap": "*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=dev.sentix 2 | version=1.0.7-SNAPSHOT 3 | description=Marker addon for squaremap 4 | 5 | kotlin.code.style=official 6 | 7 | org.gradle.parallel=true 8 | org.gradle.caching=true 9 | org.gradle.jvmargs=-Xmx3G 10 | 11 | minecraftVersion=1.21.1 12 | cloudVersion=2.0.0 13 | cloudMinecraftVersion=2.0.0-beta.10 14 | cloudMinecraftModdedVersion=2.0.0-beta.9 15 | bstatsVersion=3.1.0 16 | squaremapVersion=1.2.7 17 | adventureVersion=4.14.0 18 | adventureFabricVersion=5.14.1 19 | gsonVersion=2.10.1 20 | configurateVersion=4.1.2 21 | fabricApiVersion=0.105.0+1.21.1 22 | fabricLoaderVersion=0.16.5 23 | forgeVersion=21.1.62 24 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SentixDev/squaremarker/f46fa55bbe14f19a54d879d51b93a7f818dfd0fc/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.10.2-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 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /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 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /neoforge/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("squaremarker.platform.loom") 3 | } 4 | 5 | val adventureVersion: String by rootProject 6 | val forgeVersion: String by rootProject 7 | val cloudMinecraftModdedVersion: String by rootProject 8 | 9 | dependencies { 10 | neoForge("net.neoforged:neoforge:$forgeVersion") 11 | 12 | // We don't include() these since squaremap already does and we depend on it 13 | modImplementation("org.incendo:cloud-neoforge:$cloudMinecraftModdedVersion") 14 | compileOnly("net.kyori:adventure-api:$adventureVersion") 15 | } 16 | 17 | squareMarker { 18 | modInfoFilePath = "META-INF/neoforge.mods.toml" 19 | } 20 | -------------------------------------------------------------------------------- /neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=neoforge 2 | -------------------------------------------------------------------------------- /neoforge/src/main/kotlin/SquareMarkerInitializer.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.forge 2 | 3 | import dev.sentix.squaremarker.SquareMarker 4 | import dev.sentix.squaremarker.command.Commander 5 | import dev.sentix.squaremarker.forge.command.ForgeCommander 6 | import dev.sentix.squaremarker.marker.API 7 | import net.minecraft.server.level.ServerLevel 8 | import net.neoforged.fml.ModContainer 9 | import net.neoforged.fml.common.Mod 10 | import net.neoforged.neoforge.common.NeoForge 11 | import net.neoforged.neoforge.event.level.LevelEvent 12 | import net.neoforged.neoforge.event.server.ServerStartingEvent 13 | import net.neoforged.neoforge.event.server.ServerStoppedEvent 14 | import org.incendo.cloud.CommandManager 15 | import org.incendo.cloud.SenderMapper 16 | import org.incendo.cloud.execution.ExecutionCoordinator 17 | import org.incendo.cloud.neoforge.NeoForgeServerCommandManager 18 | import xyz.jpenilla.squaremap.api.SquaremapProvider 19 | import xyz.jpenilla.squaremap.api.WorldIdentifier 20 | import java.io.File 21 | import java.nio.file.Path 22 | 23 | @Mod("squaremarker") 24 | class SquareMarkerInitializer( 25 | modContainer: ModContainer, 26 | ) { 27 | private val dir: Path = File(modContainer.modId).toPath() 28 | private val squareMarker: SquareMarker = 29 | SquareMarker( 30 | createCommandManager(), 31 | dir.resolve("config.yml"), 32 | dir, 33 | ) 34 | 35 | init { 36 | // Ensure we initialize after squaremap regardless of load order (future squaremap versions should provide a better mechanism) 37 | NeoForge.EVENT_BUS.addListener { squareMarker.init() } 38 | NeoForge.EVENT_BUS.addListener { squareMarker.shutdown() } 39 | 40 | NeoForge.EVENT_BUS.addListener { 41 | val level = it.level as? ServerLevel ?: return@addListener 42 | SquaremapProvider.get().getWorldIfEnabled( 43 | WorldIdentifier.parse(level.dimension().location().toString()), 44 | ).ifPresent(API::initWorld) 45 | } 46 | 47 | NeoForge.EVENT_BUS.addListener { 48 | val level = it.level as? ServerLevel ?: return@addListener 49 | SquaremapProvider.get().getWorldIfEnabled( 50 | WorldIdentifier.parse(level.dimension().location().toString()), 51 | ).ifPresent(API::unloadWorld) 52 | } 53 | } 54 | 55 | private fun createCommandManager(): CommandManager { 56 | val mgr = 57 | NeoForgeServerCommandManager( 58 | ExecutionCoordinator.simpleCoordinator(), 59 | SenderMapper.create( 60 | { stack -> ForgeCommander.create(stack) }, 61 | { commander -> (commander as ForgeCommander).sender }, 62 | ), 63 | ) 64 | return mgr 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /neoforge/src/main/kotlin/command/ForgeCommander.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.forge.command 2 | 3 | import dev.sentix.squaremarker.command.Commander 4 | import dev.sentix.squaremarker.command.PlayerCommander 5 | import net.kyori.adventure.audience.Audience 6 | import net.kyori.adventure.audience.ForwardingAudience 7 | import net.minecraft.commands.CommandSourceStack 8 | import net.minecraft.server.level.ServerPlayer 9 | import xyz.jpenilla.squaremap.api.WorldIdentifier 10 | import java.lang.reflect.Method 11 | 12 | open class ForgeCommander(val sender: CommandSourceStack) : Commander, ForwardingAudience.Single { 13 | override fun audience(): Audience = commandSourceAudienceMethod(null, sender) as Audience 14 | 15 | class Player(sender: CommandSourceStack, private val player: ServerPlayer) : ForgeCommander(sender), PlayerCommander { 16 | override val world: WorldIdentifier 17 | get() = WorldIdentifier.parse(player.level().dimension().location().toString()) 18 | override val x: Double 19 | get() = player.x 20 | override val y: Double 21 | get() = player.y 22 | override val z: Double 23 | get() = player.z 24 | } 25 | 26 | companion object { 27 | val commandSourceAudienceMethod: Method = 28 | Class.forName("xyz.jpenilla.squaremap.forge.ForgeAdventure") 29 | .getDeclaredMethod("commandSourceAudience", CommandSourceStack::class.java) 30 | 31 | fun create(sender: CommandSourceStack): Commander { 32 | if (sender.player != null) { 33 | return Player(sender, sender.playerOrException) 34 | } 35 | return ForgeCommander(sender) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "[1,)" 3 | license = "MIT" 4 | issueTrackerURL = "https://github.com/SentixDev/squaremarker/issues" 5 | showAsResourcePack = false 6 | 7 | [[mods]] 8 | modId = "squaremarker" 9 | version = "${version}" 10 | displayName = "squaremarker" 11 | displayURL = "https://github.com/SentixDev/squaremarker" 12 | authors = "Sentix" 13 | description = "Marker addon for squaremap" 14 | displayTest = "IGNORE_ALL_VERSION" 15 | 16 | [[dependencies.squaremarker]] 17 | modId = "neoforge" 18 | mandatory = true 19 | versionRange = "[21.0,)" 20 | ordering = "NONE" 21 | side = "BOTH" 22 | 23 | [[dependencies.squaremarker]] 24 | modId = "minecraft" 25 | mandatory = true 26 | versionRange = "[1.21,1.22)" 27 | ordering = "NONE" 28 | side = "BOTH" 29 | 30 | [[dependencies.squaremarker]] 31 | modId = "cloud" 32 | mandatory = true 33 | versionRange = "*" 34 | ordering = "AFTER" 35 | side = "BOTH" 36 | 37 | [[dependencies.squaremarker]] 38 | modId = "squaremap" 39 | mandatory = true 40 | versionRange = "*" 41 | ordering = "AFTER" 42 | side = "BOTH" 43 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "squaremarker resources", 4 | "pack_format": 9 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /paper/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | 3 | plugins { 4 | id("squaremarker.platform") 5 | } 6 | 7 | val minecraftVersion: String by rootProject 8 | val bstatsVersion: String by rootProject 9 | 10 | dependencies { 11 | implementation(project(":squaremarker-common")) 12 | 13 | compileOnly("io.papermc.paper:paper-api:$minecraftVersion-R0.1-SNAPSHOT") 14 | 15 | implementation("org.incendo", "cloud-paper") 16 | 17 | implementation("org.bstats", "bstats-bukkit", bstatsVersion) 18 | } 19 | 20 | java { 21 | toolchain.languageVersion = JavaLanguageVersion.of(21) 22 | } 23 | 24 | kotlin { 25 | compilerOptions { 26 | jvmTarget = JvmTarget.JVM_21 27 | } 28 | } 29 | 30 | tasks { 31 | compileJava { 32 | options.encoding = Charsets.UTF_8.name() 33 | options.release = 21 34 | } 35 | 36 | jar { 37 | archiveClassifier = "not-shadowed" 38 | } 39 | 40 | shadowJar { 41 | archiveClassifier = null as String? 42 | listOf( 43 | "org.incendo", 44 | ).forEach { relocate(it, "${rootProject.group}.lib.$it") } 45 | dependencies { 46 | exclude(dependency("org.jetbrains:annotations")) 47 | } 48 | } 49 | } 50 | 51 | squareMarker { 52 | productionJar = tasks.shadowJar.flatMap { it.archiveFile } 53 | modInfoFilePath = "plugin.yml" 54 | } 55 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/Folia.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.paper 2 | 3 | val folia: Boolean by lazy { 4 | val regionizedServerCls: Class<*>? = 5 | runCatching { 6 | Class.forName("io.papermc.paper.threadedregions.RegionizedServer") 7 | }.getOrNull() 8 | regionizedServerCls != null 9 | } 10 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/PaperWorldIdentifierSerializer.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.paper 2 | 3 | import com.google.gson.JsonDeserializationContext 4 | import com.google.gson.JsonDeserializer 5 | import com.google.gson.JsonElement 6 | import com.google.gson.JsonNull 7 | import com.google.gson.JsonParseException 8 | import com.google.gson.JsonPrimitive 9 | import com.google.gson.JsonSerializationContext 10 | import com.google.gson.JsonSerializer 11 | import org.bukkit.NamespacedKey 12 | import org.bukkit.Server 13 | import xyz.jpenilla.squaremap.api.BukkitAdapter 14 | import xyz.jpenilla.squaremap.api.WorldIdentifier 15 | import java.lang.reflect.Type 16 | 17 | class PaperWorldIdentifierSerializer(private val server: Server) : 18 | JsonSerializer, 19 | JsonDeserializer { 20 | override fun serialize( 21 | src: WorldIdentifier?, 22 | typeOfSrc: Type, 23 | context: JsonSerializationContext, 24 | ): JsonElement { 25 | if (src == null) return JsonNull.INSTANCE 26 | return JsonPrimitive(src.asString()) 27 | } 28 | 29 | override fun deserialize( 30 | json: JsonElement?, 31 | typeOfT: Type, 32 | context: JsonDeserializationContext, 33 | ): WorldIdentifier? { 34 | if (json == null || json is JsonNull) return null 35 | val tryDeserializeKey = NamespacedKey.fromString(json.asString) 36 | if (tryDeserializeKey != null) { 37 | val world = server.getWorld(tryDeserializeKey) 38 | if (world != null) return WorldIdentifier.parse(json.asString) 39 | } 40 | val world = server.getWorld(json.asString) 41 | if (world == null) { 42 | try { 43 | return WorldIdentifier.parse(json.asString) 44 | } catch (ex: Exception) { 45 | throw JsonParseException("'${json.asString}' is an invalid WorldIdentifier and no world exists with that name.", ex) 46 | } 47 | } 48 | return BukkitAdapter.worldIdentifier(world) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/SquareMarkerPlugin.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.paper 2 | 3 | import dev.sentix.squaremarker.SquareMarker 4 | import dev.sentix.squaremarker.command.Commander 5 | import dev.sentix.squaremarker.marker.API 6 | import dev.sentix.squaremarker.paper.command.PaperCommander 7 | import org.bstats.bukkit.Metrics 8 | import org.bukkit.event.EventHandler 9 | import org.bukkit.event.Listener 10 | import org.bukkit.event.world.WorldLoadEvent 11 | import org.bukkit.plugin.java.JavaPlugin 12 | import org.incendo.cloud.SenderMapper 13 | import org.incendo.cloud.execution.ExecutionCoordinator 14 | import org.incendo.cloud.paper.LegacyPaperCommandManager 15 | import xyz.jpenilla.squaremap.api.BukkitAdapter 16 | import xyz.jpenilla.squaremap.api.SquaremapProvider 17 | 18 | class SquareMarkerPlugin : JavaPlugin(), Listener { 19 | private lateinit var squareMarker: SquareMarker 20 | 21 | override fun onEnable() { 22 | squareMarker = 23 | SquareMarker( 24 | createCommandManager(), 25 | dataFolder.toPath().resolve("config.yml"), 26 | dataFolder.toPath(), 27 | PaperWorldIdentifierSerializer(server), 28 | ).also { it.init() } 29 | 30 | server.pluginManager.registerEvents(this, this) 31 | 32 | // https://bstats.org/plugin/bukkit/squaremarker/14117 33 | Metrics(this, 14117) 34 | } 35 | 36 | override fun onDisable() { 37 | squareMarker.shutdown() 38 | } 39 | 40 | private fun createCommandManager(): LegacyPaperCommandManager { 41 | val mgr = 42 | LegacyPaperCommandManager( 43 | this, 44 | ExecutionCoordinator.builder() 45 | .synchronizeExecution(folia) 46 | .build(), 47 | SenderMapper.create( 48 | { sender -> PaperCommander.create(sender) }, 49 | { commander -> (commander as PaperCommander).sender }, 50 | ), 51 | ) 52 | mgr.registerBrigadier() 53 | return mgr 54 | } 55 | 56 | @EventHandler 57 | fun handleLoad(event: WorldLoadEvent) { 58 | SquaremapProvider.get().getWorldIfEnabled(BukkitAdapter.worldIdentifier(event.world)).ifPresent(API::initWorld) 59 | } 60 | 61 | @EventHandler 62 | fun handleunLoad(event: WorldLoadEvent) { 63 | SquaremapProvider.get().getWorldIfEnabled(BukkitAdapter.worldIdentifier(event.world)).ifPresent(API::unloadWorld) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/command/PaperCommander.kt: -------------------------------------------------------------------------------- 1 | package dev.sentix.squaremarker.paper.command 2 | 3 | import dev.sentix.squaremarker.command.Commander 4 | import dev.sentix.squaremarker.command.PlayerCommander 5 | import net.kyori.adventure.audience.Audience 6 | import net.kyori.adventure.audience.ForwardingAudience 7 | import org.bukkit.command.CommandSender 8 | import xyz.jpenilla.squaremap.api.BukkitAdapter 9 | import xyz.jpenilla.squaremap.api.WorldIdentifier 10 | 11 | open class PaperCommander(val sender: CommandSender) : Commander, ForwardingAudience.Single { 12 | override fun audience(): Audience = sender 13 | 14 | class Player(private val player: org.bukkit.entity.Player) : PaperCommander(player), PlayerCommander { 15 | override val world: WorldIdentifier 16 | get() = BukkitAdapter.worldIdentifier(player.world) 17 | override val x: Double 18 | get() = player.location.x 19 | override val y: Double 20 | get() = player.location.y 21 | override val z: Double 22 | get() = player.location.z 23 | } 24 | 25 | companion object { 26 | fun create(sender: CommandSender): Commander { 27 | if (sender is org.bukkit.entity.Player) { 28 | return Player(sender) 29 | } 30 | return PaperCommander(sender) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /paper/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: squaremarker 2 | version: $version 3 | main: dev.sentix.squaremarker.paper.SquareMarkerPlugin 4 | description: Marker addon for squaremap 5 | load: POSTWORLD 6 | authors: 7 | - Sentix 8 | website: https://github.com/SentixDev/squaremarker 9 | depend: 10 | - squaremap 11 | prefix: squaremarker 12 | api-version: 1.19 13 | folia-supported: true 14 | -------------------------------------------------------------------------------- /resources/default_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SentixDev/squaremarker/f46fa55bbe14f19a54d879d51b93a7f818dfd0fc/resources/default_icon.png -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "squaremarker" 2 | 3 | pluginManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | mavenCentral() 7 | maven("https://repo.papermc.io/repository/maven-public/") 8 | maven("https://maven.fabricmc.net/") 9 | maven("https://maven.architectury.dev/") 10 | maven("https://repo.jpenilla.xyz/snapshots/") 11 | } 12 | } 13 | 14 | dependencyResolutionManagement { 15 | repositories { 16 | mavenCentral() 17 | maven("https://repo.papermc.io/repository/maven-public/") 18 | maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") { 19 | mavenContent { snapshotsOnly() } 20 | } 21 | } 22 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 23 | } 24 | 25 | plugins { 26 | id("xyz.jpenilla.quiet-architectury-loom") version "1.7-SNAPSHOT" 27 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" 28 | } 29 | 30 | include("common") 31 | project(":common").name = "squaremarker-common" 32 | 33 | include("fabric") 34 | project(":fabric").name = "squaremarker-fabric" 35 | 36 | include("neoforge") 37 | project(":neoforge").name = "squaremarker-neoforge" 38 | 39 | include("paper") 40 | project(":paper").name = "squaremarker-paper" 41 | --------------------------------------------------------------------------------