diff --git a/.forgejo/workflows/build-dev.yml b/.forgejo/workflows/build-dev.yml
new file mode 100644
index 0000000..e0449f4
--- /dev/null
+++ b/.forgejo/workflows/build-dev.yml
@@ -0,0 +1,42 @@
+on:
+ push:
+ branches-ignore:
+ - refs/tags/
+
+jobs:
+ dev:
+ runs-on: nodebullshit
+ steps:
+ - uses: actions/checkout@v3
+ name: Checkout
+
+ - name: Set short git commit reference
+ id: vars
+ run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+
+ - uses: https://github.com/actions/setup-java@v4
+ name: Setup Java
+ with:
+ distribution: temurin
+ java-version: 17
+
+ - uses: https://github.com/gradle/actions/setup-gradle@v3
+ name: Setup Gradle
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew runDatagen
+ name: Generate assets
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew build
+ name: Build project
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew publish
+ name: Upload
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+ PACKAGE_REPO_KEY: ${{ secrets.PACKAGE_REPO_KEY }}
diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml
new file mode 100644
index 0000000..01b60ea
--- /dev/null
+++ b/.forgejo/workflows/build-release.yml
@@ -0,0 +1,54 @@
+on:
+ release:
+ types:
+ - released
+ - prereleased
+ - created
+ - published
+
+jobs:
+ release:
+ runs-on: nodebullshit
+ steps:
+ - uses: actions/checkout@v3
+ name: Checkout
+
+ - name: Fetch the full git repository
+ run: git fetch --prune --unshallow
+
+ - name: Set short git commit reference
+ id: vars
+ run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+
+ - uses: https://github.com/actions/setup-java@v4
+ name: Setup Java
+ with:
+ distribution: temurin
+ java-version: 17
+
+ - uses: https://github.com/gradle/actions/setup-gradle@v3
+ name: Setup Gradle
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew runDatagen
+ name: Generate assets
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew build
+ name: Build project
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+
+ - run: ./gradlew publish
+ name: Upload
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+ PACKAGE_REPO_KEY: ${{ secrets.PACKAGE_REPO_KEY }}
+
+ - run: ./gradlew modrinth
+ name: Publish to Modrinth
+ env:
+ GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
+ MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
diff --git a/LICENSE b/LICENSE
index 782b415..353ae17 100644
--- a/LICENSE
+++ b/LICENSE
@@ -631,7 +631,7 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- Gimble
+ Gimbal
Copyright (C) 2024 moonleay
This program is free software: you can redistribute it and/or modify
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
- Gimble Copyright (C) 2024 moonleay
+ Gimbal Copyright (C) 2024 moonleay
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
diff --git a/README.md b/README.md
index 2d8dd06..71c794c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,21 @@
-# The Gimble project
+# The Gimbal project
This project aims to improve the experience of creating structures in Minecraft.
+# Links
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## Features
- **Modes** Use different modes to edit structures. Think Vim for Minecraft. [x]
- **Modifier** Use modifiers to change the behavior of the modes and your building experience. [x]
diff --git a/build.gradle.kts b/build.gradle.kts
index b121bc2..efb5c4d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,3 +1,21 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
import org.jetbrains.gradle.ext.ProjectSettings
import org.jetbrains.gradle.ext.TaskTriggersConfig
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -9,13 +27,23 @@ plugins {
`maven-publish`
eclipse
id("org.jetbrains.gradle.plugin.idea-ext")
+ id("com.modrinth.minotaur") version "2.+"
}
-val mavenVersion = System.getenv("CI_COMMIT_TAG") ?: System.getenv("CI_COMMIT_SHORT_SHA")?.let { "$it-dev" }
-?: "0.1.0-dev" //""0.0.0-SNAPSHOT"
+val ver = if ((System.getenv("GITHUB_REF") ?: "local").startsWith("refs/tags/"))
+ System.getenv("GITHUB_REF_NAME") ?: "err" else System.getenv("GIT_SHA_SHORT") ?: "0.0.0"
+
+val mavenVersion = ver
val modId: String by project
val modName: String by project
+/*
+* Gimbal version stuff
+* */
+
+val gimbalProtocolVersion = 3
+
+
val mavenGroup: String by project
val mavenArtifact: String by project
@@ -32,6 +60,9 @@ group = mavenGroup
project.base.archivesName.set(mavenArtifact)
repositories {
+ maven { // Dependency api
+ url = uri("https://oss.sonatype.org/content/repositories/snapshots")
+ }
}
fabricApi {
@@ -48,6 +79,10 @@ dependencies {
modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion")
modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
+ modApi("me.lucko:fabric-permissions-api:0.2-SNAPSHOT")
+ {
+ exclude(group = "net.fabricmc")
+ }
}
val targetJavaVersion = 17
@@ -58,6 +93,7 @@ val templateProps = mapOf(
"modVersion" to project.version as String,
"modId" to modId,
"modName" to modName,
+ "protocolVersion" to gimbalProtocolVersion,
"minecraftVersion" to minecraftVersion,
"fabricLoaderVersion" to fabricLoaderVersion,
"fabricKotlinVersion" to fabricKotlinVersion,
@@ -151,17 +187,18 @@ publishing {
}
repositories {
- if (System.getenv("CI_JOB_TOKEN") != null) {
+ if (System.getenv("CI") != null) {
maven {
- name = "GitLab"
- val projectId = System.getenv("CI_PROJECT_ID")
- val apiV4 = System.getenv("CI_API_V4_URL")
- url = uri("$apiV4/projects/$projectId/packages/maven")
+ name = "Codeberg"
+ val repoOwner = System.getenv("GITHUB_REPOSITORY_OWNER")
+ val serverUrl = System.getenv("GITHUB_SERVER_URL")
+ val accessToken = System.getenv("PACKAGE_REPO_KEY")
+ url = uri("$serverUrl/api/packages/$repoOwner/maven")
authentication {
- create("token", HttpHeaderAuthentication::class.java) {
- credentials(HttpHeaderCredentials::class.java) {
- name = "Job-Token"
- value = System.getenv("CI_JOB_TOKEN")
+ create("header", HttpHeaderAuthentication::class.java) {
+ credentials(HttpHeaderCredentials::class) {
+ name = "Authorization"
+ value = "token $accessToken"
}
}
}
@@ -170,6 +207,33 @@ publishing {
}
}
+// build.gradle.kts
+modrinth {
+ token.set(System.getenv("MODRINTH_TOKEN")) // Remember to have the MODRINTH_TOKEN environment variable set or else this will fail - just make sure it stays private!
+ projectId.set(modId) // This can be the project ID or the slug. Either will work!
+ versionNumber.set(mavenVersion) // You don't need to set this manually. Will fail if Modrinth has this version already
+ versionName.set("$modName $mavenVersion for $minecraftVersion")
+ versionType.set("alpha") // This is the default -- can also be `beta` or `alpha`
+ uploadFile.set(tasks.remapJar) // With Loom, this MUST be set to `remapJar` instead of `jar`!
+ gameVersions.addAll(listOf(project.ext["minecraft.version"] as String)) // Must be an array, even with only one version
+ loaders.add("fabric") // Must also be an array - no need to specify this if you're using Loom or ForgeGradle
+ changelog.set(
+ "Changelog v$mavenVersion\n\nCheckout the changelog [on codeberg](${System.getenv("GITHUB_SERVER_URL") ?: ""}/${
+ System.getenv(
+ "GITHUB_REPOSITORY"
+ ) ?: ""
+ }/releases/tag/${System.getenv("GITHUB_REF_NAME") ?: ""})"
+ )
+ dependencies { // A special DSL for creating dependencies
+ // scope.type
+ // The scope can be `required`, `optional`, `incompatible`, or `embedded`
+ // The type can either be `project` or `version`
+ required.project("fabric-api") // Creates a new required dependency on Fabric API
+ required.project("fabric-language-kotlin")
+ }
+}
+
+
rootProject.idea.project {
this as ExtensionAware
configure {
diff --git a/gradle.properties b/gradle.properties
index 1fae464..aa5c709 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,18 +1,36 @@
+#
+# Gimbal
+# Copyright (C) 2024 moonleay
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
#Generated by fabric-mod-template
#Sun Apr 21 19:29:15 CEST 2024
-fabric.loom.version=1.4.6
+fabric.loom.version=1.6-SNAPSHOT
kotlin.version=1.9.22
fabric.api.version=0.77.0+1.19.2
yarn.version=1.19.2+build.28
idea-ext.version=1.1.6
org.gradle.jvmargs=-Xmx2G
-modId=gimble
+modId=gimbal
kotlinx.serialization.version=1.6.2
fabric.kotlin.version=1.10.18+kotlin.1.9.22
mavenGroup=net.moonleay
kotlin.code.style=official
minecraft.version=1.19.2
-modName=Gimble
+modName=Gimbal
#fabric.loader.version=0.15.10
-mavenArtifact=gimble
+mavenArtifact=gimbal
fabric.loader.version=0.14.0
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1af9e09..ea3fa1d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,24 @@
+#
+# Gimbal
+# Copyright (C) 2024 moonleay
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a4..1e55349 100755
--- a/gradlew
+++ b/gradlew
@@ -1,19 +1,21 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Gimbal
+# Copyright (C) 2024 moonleay
#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
#
-# https://www.apache.org/licenses/LICENSE-2.0
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
#
##############################################################################
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 487fa1f..1a3e400 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,21 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
pluginManagement {
repositories {
maven {
diff --git a/src/main/java/net/moonleay/gimbal/Main.kt b/src/main/java/net/moonleay/gimbal/Main.kt
new file mode 100644
index 0000000..903d100
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/Main.kt
@@ -0,0 +1,43 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal
+
+import net.fabricmc.api.ModInitializer
+import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.networking.GimbalServer
+import org.apache.logging.log4j.LogManager
+
+internal object Main : ModInitializer {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ override fun onInitialize() {
+ LOGGER.info("Initializing Gimbal on the common side...")
+ LOGGER.info("Registering packets...")
+ GimbalServer.registerPacketHandler()
+ LOGGER.info("Packets have been registered.")
+ LOGGER.info("Registering events...")
+ ServerPlayConnectionEvents.INIT.register(ServerPlayConnectionEvents.Init { handler, server ->
+ GimbalServer.notifyPlayerOfPolicy(handler.player)
+ })
+ LOGGER.info("Events have been registered.")
+ LOGGER.info("Gimbal has been initialized on the common side.")
+ LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/ClientMain.kt b/src/main/java/net/moonleay/gimbal/client/ClientMain.kt
new file mode 100644
index 0000000..d3f1823
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/ClientMain.kt
@@ -0,0 +1,67 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client
+
+import net.fabricmc.api.ClientModInitializer
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
+import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents
+import net.fabricmc.loader.api.FabricLoader
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.client.config.ClientConfigHolder
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.KeybindingManager
+import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar
+import net.moonleay.gimbal.networking.GimbalClient
+import org.apache.logging.log4j.LogManager
+
+internal object ClientMain : ClientModInitializer {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+ lateinit var CONFIG: ClientConfigHolder
+
+
+ override fun onInitializeClient() {
+ LOGGER.info("Initializing Gimbal on the client side...")
+ KeybindingRegistrar.registerKeybindings()
+ this.registerEvents()
+ LOGGER.info("Registering packets...")
+ GimbalClient.registerPacketHandlers()
+ LOGGER.info("Packets have been registered.")
+ LOGGER.info("Loading client config.")
+ val gimbalConfigPath = FabricLoader.getInstance().configDir.resolve(BuildConstants.modId + "/client.json")
+ CONFIG = ClientConfigHolder(gimbalConfigPath)
+ LOGGER.info("Config has been loaded.")
+ LOGGER.info("Applying Config to client.")
+ ClientEditor.applyConfig(CONFIG.config)
+ LOGGER.info("Config has been applied.")
+ LOGGER.info("Gimbal has been initialized on the client side.")
+ }
+
+ private fun registerEvents() {
+ LOGGER.info("Registering client events...")
+ ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
+ KeybindingManager.onClientTick(client)
+ })
+
+ ClientLoginConnectionEvents.INIT.register(ClientLoginConnectionEvents.Init { _, _ ->
+ ClientEditor.onConnectedToNewWorld() // Client is connecting to a new server, reset the editor
+ })
+ LOGGER.info("Client events have been registered.")
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/ClientConfigHolder.kt b/src/main/java/net/moonleay/gimbal/client/config/ClientConfigHolder.kt
new file mode 100644
index 0000000..4ad504d
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/ClientConfigHolder.kt
@@ -0,0 +1,79 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.decodeFromStream
+import kotlinx.serialization.json.encodeToStream
+import net.moonleay.gimbal.client.editor.ClientEditor
+import java.nio.file.Path
+import kotlin.io.path.*
+
+class ClientConfigHolder(private val path: Path) {
+ var config: GimbalClientConfig
+ private set
+
+ init {
+ this.config = load()
+ }
+
+ fun updateConfig(new: GimbalClientConfig) {
+ this.config = new
+ this.save(config)
+ ClientEditor.applyConfig(config)
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ fun load(): GimbalClientConfig {
+ if (!path.isReadable())
+ save(GimbalClientConfig())
+ val iStream = path.inputStream()
+ val gimbalClientConfig: GimbalClientConfig = iStream.use {
+ Json {
+ ignoreUnknownKeys = true
+ }.decodeFromStream(it)
+ }
+ iStream.close()
+ return gimbalClientConfig
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ fun save(conf: GimbalClientConfig) {
+ if (!path.parent.exists()) {
+ path.parent.createDirectory()
+ }
+ if (!path.parent.isWritable()) {
+ throw Exception("Parent of path ${path.parent.pathString} is not writable.")
+ }
+ if (!path.exists())
+ path.createFile()
+ if (!path.isWritable()) {
+ throw Exception("Path (${path.pathString}) exists, but is not writable.")
+ }
+ val oStream = path.outputStream()
+ oStream.use {
+ Json {
+ ignoreUnknownKeys = true
+ }.encodeToStream(conf, it)
+ }
+ oStream.close()
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/GimbalClientConfig.kt b/src/main/java/net/moonleay/gimbal/client/config/GimbalClientConfig.kt
new file mode 100644
index 0000000..5fd641c
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/GimbalClientConfig.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config
+
+import kotlinx.serialization.Serializable
+import net.moonleay.gimbal.client.config.enums.ToastSettings
+import net.moonleay.gimbal.editor.state.mode.Mode
+
+@Serializable
+data class GimbalClientConfig(
+ val guiSettings: GimbalGuiSettings = GimbalGuiSettings(),
+ val toastSettings: ToastSettings = ToastSettings.ALL,
+ val playerFlySpeed: Int = 100,
+ val shouldEscResetMode: Boolean = true,
+ val defaultMode: Mode = Mode.NORMAL
+)
diff --git a/src/main/java/net/moonleay/gimbal/client/config/GimbalGuiSettings.kt b/src/main/java/net/moonleay/gimbal/client/config/GimbalGuiSettings.kt
new file mode 100644
index 0000000..06755a1
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/GimbalGuiSettings.kt
@@ -0,0 +1,33 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config
+
+import kotlinx.serialization.Serializable
+import net.moonleay.gimbal.client.config.enums.HorizontalAnchor
+import net.moonleay.gimbal.client.config.enums.HudOptions
+import net.moonleay.gimbal.client.config.enums.VerticalAnchor
+
+@Serializable
+data class GimbalGuiSettings(
+ val showHud: Boolean = true,
+ val offset: ScaledRes = ScaledRes(4.0, 4.0),
+ val horizontalAnchor: HorizontalAnchor = HorizontalAnchor.LEFT,
+ val verticalAnchor: VerticalAnchor = VerticalAnchor.TOP,
+ val hudOptions: HudOptions = HudOptions.ALL,
+)
diff --git a/src/main/java/net/moonleay/gimbal/client/config/ScaledRes.kt b/src/main/java/net/moonleay/gimbal/client/config/ScaledRes.kt
new file mode 100644
index 0000000..40d04aa
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/ScaledRes.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ScaledRes(
+ val scaledX: Double, // offsetX
+ val scaledY: Double, // offsetY
+)
diff --git a/src/main/java/net/moonleay/gimbal/client/config/enums/Centerpoint.kt b/src/main/java/net/moonleay/gimbal/client/config/enums/Centerpoint.kt
new file mode 100644
index 0000000..a9cecc4
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/enums/Centerpoint.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config.enums
+
+enum class Centerpoint {
+ TOP_LEFT,
+ TOP_RIGHT,
+ BOTTOM_RIGHT,
+ BOTTOM_LEFT,
+ CENTER
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/enums/HorizontalAnchor.kt b/src/main/java/net/moonleay/gimbal/client/config/enums/HorizontalAnchor.kt
new file mode 100644
index 0000000..439a56f
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/enums/HorizontalAnchor.kt
@@ -0,0 +1,28 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config.enums
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+enum class HorizontalAnchor {
+ LEFT,
+ CENTER,
+ RIGHT,
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/enums/HudOptions.kt b/src/main/java/net/moonleay/gimbal/client/config/enums/HudOptions.kt
new file mode 100644
index 0000000..e57f8c0
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/enums/HudOptions.kt
@@ -0,0 +1,31 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config.enums
+
+import kotlinx.serialization.Serializable
+import net.minecraft.text.Text
+import net.moonleay.gimbal.constants.TranslationKeys
+
+@Serializable
+enum class HudOptions(val translatableText: Text) {
+ ALL(Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_ALL)),
+ NUMBER(Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_NUMBER)),
+ INITIAL(Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_INITIALS)),
+ ONLY_MODE(Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_MODE_ONLY)),
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/enums/ToastSettings.kt b/src/main/java/net/moonleay/gimbal/client/config/enums/ToastSettings.kt
new file mode 100644
index 0000000..e581500
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/enums/ToastSettings.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config.enums
+
+import kotlinx.serialization.Serializable
+import net.minecraft.text.Text
+import net.moonleay.gimbal.client.util.ToastType
+import net.moonleay.gimbal.constants.TranslationKeys
+
+@Serializable
+enum class ToastSettings(val translatableText: Text, val allowedTypes: List) {
+ ALL(Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_ALL), listOf(ToastType.SYSTEM, ToastType.TOGGLE)),
+ ONLY_TOGGLE(Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_TOGGLE), listOf(ToastType.TOGGLE)),
+ ONLY_SYSTEM(Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_SYSTEM), listOf(ToastType.SYSTEM)),
+ NONE(Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_NONE), listOf())
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/config/enums/VerticalAnchor.kt b/src/main/java/net/moonleay/gimbal/client/config/enums/VerticalAnchor.kt
new file mode 100644
index 0000000..d3ae146
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/config/enums/VerticalAnchor.kt
@@ -0,0 +1,28 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.config.enums
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+enum class VerticalAnchor {
+ TOP,
+ CENTER,
+ BOTTOM,
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt b/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt
new file mode 100644
index 0000000..42d54c4
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt
@@ -0,0 +1,316 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.editor
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.text.Text
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.client.ClientMain
+import net.moonleay.gimbal.client.config.GimbalClientConfig
+import net.moonleay.gimbal.client.config.enums.HudOptions
+import net.moonleay.gimbal.client.util.ChatUtil
+import net.moonleay.gimbal.client.util.ToastType
+import net.moonleay.gimbal.editor.ServerEditorManager
+import net.moonleay.gimbal.editor.state.EditorState
+import net.moonleay.gimbal.editor.state.GimbalPolicyType
+import net.moonleay.gimbal.editor.state.GimbalServerState
+import net.moonleay.gimbal.editor.state.mode.Capability
+import net.moonleay.gimbal.editor.state.mode.Mode
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+import net.moonleay.gimbal.editor.util.EditorUtil
+import net.moonleay.gimbal.networking.GimbalClient
+import org.apache.logging.log4j.LogManager
+
+object ClientEditor {
+ private var POLICY = GimbalPolicyType.NOT_PRESENT
+
+ private lateinit var CURRENT_MODE: Mode
+ private var TEMP_DISABLED_MODE = Mode.UNKNOWN
+
+ private val CURRENT_MODE_MODIFIER = mutableListOf()
+ private val TEMP_DISABLED_MODIFIERS = mutableListOf()
+ private val DISABLED_MODIFIERS_STORAGE = mutableListOf()
+
+
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ fun applyConfig(config: GimbalClientConfig, isBoot: Boolean = true) {
+ if (isBoot) {
+ this.CURRENT_MODE = config.defaultMode
+ return
+ }
+ if (!config.shouldEscResetMode) return
+ this.CURRENT_MODE = config.defaultMode
+ onUpdated()
+ }
+
+ fun onConnectedToNewWorld() {
+ POLICY = GimbalPolicyType.NOT_PRESENT
+ if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
+ TEMP_DISABLED_MODE =
+ CURRENT_MODE
+ }
+ CURRENT_MODE = Mode.INSERT
+ DISABLED_MODIFIERS_STORAGE.addAll(
+ CURRENT_MODE_MODIFIER
+ )
+ CURRENT_MODE_MODIFIER.clear()
+ }
+
+ fun onPolicyReceived(data: GimbalServerState, shouldUpdateServer: Boolean = true) {
+ POLICY = data.policyType
+ if (data.policyType == GimbalPolicyType.ALLOWED) {
+ if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
+ CURRENT_MODE =
+ TEMP_DISABLED_MODE
+ TEMP_DISABLED_MODE = Mode.UNKNOWN
+ }
+ CURRENT_MODE_MODIFIER.addAll(
+ DISABLED_MODIFIERS_STORAGE
+ )
+ DISABLED_MODIFIERS_STORAGE.clear()
+ onUpdated(shouldUpdateServer)
+
+ if (!shouldUpdateServer) {
+ val player = MinecraftClient.getInstance().player
+ if (player == null) {
+ LOGGER.warn("Player is null!") //FIXME: Fix player is null at world join!
+ return
+ }
+ ServerEditorManager.updateEditorState(
+ MinecraftClient.getInstance().player!!.uuid,
+ this.getClientState()
+ )
+ }
+ }
+ }
+
+ fun isAllowed(): Boolean {
+ return POLICY == GimbalPolicyType.ALLOWED
+ }
+
+ fun shouldClient(capability: Capability): Boolean {
+ return EditorUtil.shouldPlayer(
+ capability, EditorState(
+ CURRENT_MODE,
+ CURRENT_MODE_MODIFIER
+ )
+ )
+ }
+
+ fun isInNonDefaultMode(): Boolean {
+ return CURRENT_MODE != ClientMain.CONFIG.config.defaultMode
+ }
+
+ /*
+ * Send an updated player state to the server
+ * */
+ private fun updateServerState() {
+ val state = this.getClientState()
+ GimbalClient.sendStatePacket(state)
+ ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
+ }
+
+
+ /*
+ * Set the current mode
+ * */
+ fun setMode(mode: Mode) {
+ if (!isAllowed()) {
+ ChatUtil.showToastToSelf(
+ "Gimbal is disabled",
+ "You cannot change modes",
+ ToastType.SYSTEM,
+ ClientMain.CONFIG.config,
+ MinecraftClient.getInstance()
+ )
+ return
+ }
+ if (!MinecraftClient.getInstance().player!!.isCreative)
+ return
+ CURRENT_MODE = mode
+
+ onUpdated()
+ }
+
+ /*
+ * Toggle a mode modifier
+ * */
+ fun toggleModifier(mod: ModeModifier) {
+ if (!isAllowed()) {
+ ChatUtil.showToastToSelf(
+ "Gimbal is disabled",
+ "You cannot change modifiers",
+ ToastType.SYSTEM,
+ ClientMain.CONFIG.config,
+ MinecraftClient.getInstance()
+ )
+ return
+ }
+ if (!MinecraftClient.getInstance().player!!.isCreative)
+ return
+
+ if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
+ if (TEMP_DISABLED_MODIFIERS.contains(mod)) {
+ TEMP_DISABLED_MODIFIERS.remove(mod)
+ } else {
+ TEMP_DISABLED_MODIFIERS.add(mod)
+ }
+ }
+ else {
+ if (CURRENT_MODE_MODIFIER.contains(mod)) {
+ CURRENT_MODE_MODIFIER.remove(mod)
+ ChatUtil.showToastToSelf(
+ "Disabled ${mod.displayName}",
+ "[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
+ ToastType.TOGGLE, ClientMain.CONFIG.config,
+ MinecraftClient.getInstance()
+ )
+
+ } else {
+ CURRENT_MODE_MODIFIER.add(mod)
+ ChatUtil.showToastToSelf(
+ "Enabled ${mod.displayName}",
+ "[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
+ ToastType.TOGGLE, ClientMain.CONFIG.config,
+ MinecraftClient.getInstance()
+ )
+ }
+ }
+
+ onUpdated()
+ }
+
+ private fun onUpdated(shouldUpdateServer: Boolean = true) {
+ CURRENT_MODE_MODIFIER.sortBy {
+ it.displayName
+ }
+ checkForIncompatibleModeModifiers(shouldUpdateServer)
+ }
+
+ /**
+ * This runs on Mode updated
+ */
+ private fun checkForIncompatibleModeModifiers(shouldUpdateServer: Boolean = true) {
+ if (TEMP_DISABLED_MODIFIERS.size > 0) {
+ CURRENT_MODE_MODIFIER.addAll(
+ TEMP_DISABLED_MODIFIERS
+ )
+ TEMP_DISABLED_MODIFIERS.clear()
+ }
+
+ val incompatibleModeModifiers = CURRENT_MODE.incompatibleModifiers
+ for (mod in CURRENT_MODE_MODIFIER) {
+ if (incompatibleModeModifiers.contains(mod)) {
+ TEMP_DISABLED_MODIFIERS.add(mod)
+ }
+ }
+ for (mod in TEMP_DISABLED_MODIFIERS) {
+ if (CURRENT_MODE_MODIFIER.contains(mod)) { // This check is probably useless.
+ CURRENT_MODE_MODIFIER.remove(mod)
+ }
+ }
+
+ CURRENT_MODE_MODIFIER.sortBy {
+ it.displayName
+ }
+
+ // Update State
+ if (shouldUpdateServer)
+ updateServerState()
+
+ if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
+ ChatUtil.showToastToSelf(
+ "${CURRENT_MODE.displayName} Mode disabled",
+ getDisplayNameListAsString(TEMP_DISABLED_MODIFIERS),
+ ToastType.SYSTEM,
+ ClientMain.CONFIG.config,
+ MinecraftClient.getInstance()
+ )
+ }
+ }
+
+ private fun getDisplayNameListAsString(list: List): String {
+ if(list.isEmpty())
+ return ""
+ val sb = StringBuilder()
+ for (mod in list) {
+ sb.append(mod.displayName)
+ sb.append(", ")
+ }
+ return sb.toString().dropLast(2)
+ }
+
+ private fun getShortNameListAsString(list: List): String {
+ if (list.isEmpty())
+ return ""
+ val sb = StringBuilder()
+ for (mod in list) {
+ sb.append(mod.shortName)
+ sb.append(", ")
+ }
+ return sb.toString().dropLast(2)
+ }
+
+ /*
+ * Get the display text to display in the HUD
+ * */
+ fun getModeDisplayText(config: GimbalClientConfig): Text {
+ val displayText = StringBuilder(CURRENT_MODE.displayName)
+ if (isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) {
+ when (config.guiSettings.hudOptions) {
+ HudOptions.ALL -> {
+ if (CURRENT_MODE_MODIFIER.size > 0) {
+ displayText.append(" [")
+ displayText.append(this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER))
+ displayText.append("]")
+ }
+ return Text.of(displayText.toString())
+ }
+
+ HudOptions.NUMBER -> {
+ displayText.append(" (")
+ displayText.append(CURRENT_MODE_MODIFIER.size)
+ displayText.append(")")
+ return Text.of(displayText.toString())
+ }
+
+ HudOptions.INITIAL -> {
+ if (CURRENT_MODE_MODIFIER.size > 0) {
+ displayText.append(" [")
+ displayText.append(this.getShortNameListAsString(CURRENT_MODE_MODIFIER))
+ displayText.append("]")
+ }
+ return Text.of(displayText.toString())
+ }
+
+ HudOptions.ONLY_MODE -> return Text.of(displayText.toString())
+ }
+ }
+ return Text.of("[GIMBAL DISABLED]")
+ }
+
+ fun getCurrentColor(): Int {
+ return CURRENT_MODE.color
+ }
+
+ fun getClientState(): EditorState {
+ return EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingManager.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingManager.kt
new file mode 100644
index 0000000..40e0f2f
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingManager.kt
@@ -0,0 +1,43 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings
+
+import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl
+import net.minecraft.client.MinecraftClient
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+
+object KeybindingManager {
+
+ private val shortcuts = mutableListOf()
+
+ /**
+ * Register a shortcut. This will also register the keybinding.
+ * */
+ fun registerShortcut(shortcut: GimbalShortcut) {
+ shortcuts.add(shortcut)
+ KeyBindingRegistryImpl.registerKeyBinding(shortcut.keyBinding)
+ }
+
+ fun onClientTick(client: MinecraftClient){
+ // Sadly, this cannot be done without iterating over all shortcuts :madge:
+ for (shortcut in shortcuts)
+ if (shortcut.keyBinding.wasPressed())
+ shortcut.onPressed(client)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/KeybindingRegistrar.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingRegistrar.kt
similarity index 54%
rename from src/main/java/net/moonleay/gimble/client/keybindings/KeybindingRegistrar.kt
rename to src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingRegistrar.kt
index 018e736..fd37f7d 100644
--- a/src/main/java/net/moonleay/gimble/client/keybindings/KeybindingRegistrar.kt
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/KeybindingRegistrar.kt
@@ -1,17 +1,36 @@
-package net.moonleay.gimble.client.keybindings
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings
import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil
-import net.moonleay.gimble.build.BuildConstants
-import net.moonleay.gimble.client.keybindings.impl.editormode.EnableInsertModeShortcut
-import net.moonleay.gimble.client.keybindings.impl.editormode.EnableReplaceModeShortcut
-import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut
-import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut
-import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut
-import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleNoUpdatesModifierShortcut
-import net.moonleay.gimble.client.keybindings.impl.gamemode.CreativeModeShortcut
-import net.moonleay.gimble.client.keybindings.impl.gamemode.SpectatorModeShortcut
-import net.moonleay.gimble.client.keybindings.impl.gamemode.SurvivalModeShortcut
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.client.keybindings.impl.editormode.EnableInsertModeShortcut
+import net.moonleay.gimbal.client.keybindings.impl.editormode.EnableReplaceModeShortcut
+import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut
+import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut
+import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut
+import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleNoUpdatesModifierShortcut
+import net.moonleay.gimbal.client.keybindings.impl.gamemode.CreativeModeShortcut
+import net.moonleay.gimbal.client.keybindings.impl.gamemode.SpectatorModeShortcut
+import net.moonleay.gimbal.client.keybindings.impl.gamemode.SurvivalModeShortcut
+import net.moonleay.gimbal.constants.TranslationKeys
import org.apache.logging.log4j.LogManager
import org.lwjgl.glfw.GLFW
@@ -29,28 +48,28 @@ object KeybindingRegistrar {
private fun registerSetEditorModeModifierKeybindings() {
val toggleBulldozerModifierShortcut = KeyBinding(
- "gimble.key.editor.modifier.bulldozer",
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.BULLDOZER,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.editormodifier"
+ TranslationKeys.Keybindings.Category.Editor.MODIFIER
)
val toggleForcePlaceModifierShortcut = KeyBinding(
- "gimble.key.editor.modifier.forceplace",
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.FORCE_PLACE,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.editormodifier"
+ TranslationKeys.Keybindings.Category.Editor.MODIFIER
)
val toggleNoUpdatesModifierShortcut = KeyBinding(
- "gimble.key.editor.modifier.noupdates",
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_UPDATES,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.editormodifier"
+ TranslationKeys.Keybindings.Category.Editor.MODIFIER
)
val toggleNoClipModifierShortcut = KeyBinding(
- "gimble.key.editor.modifier.noclip",
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_CLIP,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.editormodifier"
+ TranslationKeys.Keybindings.Category.Editor.MODIFIER
)
KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut))
@@ -61,22 +80,22 @@ object KeybindingRegistrar {
private fun registerSetEditorModeKeybindings() {
val insertKeyBinding = KeyBinding(
- "gimble.key.editor.mode.insert",
+ TranslationKeys.Keybindings.Binding.Editor.Mode.INSERT,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_I,
- "gimble.category.editormode"
+ TranslationKeys.Keybindings.Category.Editor.MODE
)
val replaceKeyBinding = KeyBinding(
- "gimble.key.editor.mode.replace",
+ TranslationKeys.Keybindings.Binding.Editor.Mode.REPLACE,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_R,
- "gimble.category.editormode"
+ TranslationKeys.Keybindings.Category.Editor.MODE
)
// val visualKeyBinding = KeyBinding(
-// "gimble.key.editor.mode.visual",
+// "gimbal.key.editor.mode.visual",
// InputUtil.Type.KEYSYM,
// GLFW.GLFW_KEY_V,
-// "gimble.category.editormode"
+// "gimbal.category.editormode"
// )
KeybindingManager.registerShortcut(EnableInsertModeShortcut(insertKeyBinding))
KeybindingManager.registerShortcut(EnableReplaceModeShortcut(replaceKeyBinding))
@@ -85,22 +104,22 @@ object KeybindingRegistrar {
private fun registerSetGameModeKeybindings() {
val survivalKeyBinding = KeyBinding(
- "gimble.key.game.mode.survival",
+ TranslationKeys.Keybindings.Binding.Game.Mode.SURVIVAL,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.gamemode"
+ TranslationKeys.Keybindings.Category.Game.GAMEMODE
)
val creativeKeyBinding = KeyBinding(
- "gimble.key.game.mode.creative",
+ TranslationKeys.Keybindings.Binding.Game.Mode.CREATIVE,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.gamemode"
+ TranslationKeys.Keybindings.Category.Game.GAMEMODE
)
val spectatorKeyBinding = KeyBinding(
- "gimble.key.game.mode.spectator",
+ TranslationKeys.Keybindings.Binding.Game.Mode.SPECTATOR,
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
- "gimble.category.gamemode"
+ TranslationKeys.Keybindings.Category.Game.GAMEMODE
)
KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding))
KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding))
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/GimbalShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/GimbalShortcut.kt
new file mode 100644
index 0000000..fd7f299
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/GimbalShortcut.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+
+abstract class GimbalShortcut(val keyBinding: KeyBinding) {
+
+ abstract fun onPressed(client: MinecraftClient)
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt
new file mode 100644
index 0000000..31208c9
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.Mode
+
+
+class EnableInsertModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.setMode(Mode.INSERT)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt
new file mode 100644
index 0000000..bfee8c7
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.Mode
+
+
+class EnableReplaceModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.setMode(Mode.REPLACE)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt
new file mode 100644
index 0000000..26136a0
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.Mode
+
+
+class EnableVisualModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.setMode(Mode.VISUAL)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt
new file mode 100644
index 0000000..6ca9306
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt
@@ -0,0 +1,31 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+
+class ToggleBulldozerModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.toggleModifier(ModeModifier.BULLDOZER)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt
new file mode 100644
index 0000000..18c7ce3
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt
@@ -0,0 +1,31 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+
+class ToggleForcePlaceModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.toggleModifier(ModeModifier.FORCE_PLACE)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt
new file mode 100644
index 0000000..0d23bab
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt
@@ -0,0 +1,31 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+
+class ToggleNoClipModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.toggleModifier(ModeModifier.NO_CLIP)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt
new file mode 100644
index 0000000..960e031
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt
@@ -0,0 +1,31 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+
+class ToggleNoUpdatesModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ClientEditor.toggleModifier(ModeModifier.NO_UPDATES)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/CreativeModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/CreativeModeShortcut.kt
new file mode 100644
index 0000000..11c9edf
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/CreativeModeShortcut.kt
@@ -0,0 +1,30 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.gamemode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.client.util.ChatUtil
+
+class CreativeModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ChatUtil.sendCommand("/gamemode creative", client, false)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt
new file mode 100644
index 0000000..599d163
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt
@@ -0,0 +1,30 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.gamemode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.client.util.ChatUtil
+
+class SpectatorModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+ override fun onPressed(client: MinecraftClient) {
+ ChatUtil.sendCommand("/gamemode spectator", client, false)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt
new file mode 100644
index 0000000..c14a4ae
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt
@@ -0,0 +1,32 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.keybindings.impl.gamemode
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.option.KeyBinding
+import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
+import net.moonleay.gimbal.client.util.ChatUtil
+
+
+class SurvivalModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
+
+ override fun onPressed(client: MinecraftClient) {
+ ChatUtil.sendCommand("/gamemode survival", client, false)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/screen/GimbalEditHudGui.kt b/src/main/java/net/moonleay/gimbal/client/screen/GimbalEditHudGui.kt
new file mode 100644
index 0000000..0155e35
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/screen/GimbalEditHudGui.kt
@@ -0,0 +1,151 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.screen
+
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.client.gui.widget.ButtonWidget
+import net.minecraft.client.util.math.MatrixStack
+import net.minecraft.screen.ScreenTexts
+import net.minecraft.text.Text
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.client.config.ClientConfigHolder
+import net.moonleay.gimbal.client.config.GimbalClientConfig
+import net.moonleay.gimbal.client.config.GimbalGuiSettings
+import net.moonleay.gimbal.client.config.ScaledRes
+import net.moonleay.gimbal.client.util.screen.ScreenUtil
+import net.moonleay.gimbal.constants.TranslationKeys
+import org.apache.logging.log4j.LogManager
+
+class GimbalEditHudGui(private val parent: Screen, private val cfg: ClientConfigHolder) :
+ Screen(Text.translatable(TranslationKeys.Gui.Config.Hud.EDIT_HUD)) {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ private var tempXOffset = 4.0
+ private var tempYOffset = 4.0
+ private var shouldFollow = false
+
+ init {
+ this.tempXOffset = cfg.config.guiSettings.offset.scaledX
+ this.tempYOffset = cfg.config.guiSettings.offset.scaledY
+ }
+
+ override fun init() {
+ super.init()
+ this.addDrawableChild(ButtonWidget(
+ this.width / 2 + 10, this.height - 27, 90, 20, Text.translatable(TranslationKeys.Gui.Config.Hud.RESET_HUD)
+ ) { _: ButtonWidget? ->
+ tempXOffset = 4.0
+ tempYOffset = 4.0
+ shouldFollow = false
+ })
+
+ this.addDrawableChild(ButtonWidget(
+ this.width / 2 - 100, this.height - 27, 90, 20, ScreenTexts.DONE
+ ) { _: ButtonWidget? ->
+ this.save()
+ this.client!!.setScreen(
+ this.parent
+ )
+ })
+ }
+
+ private fun save() {
+ val oldConf = cfg.config
+ if (ScreenUtil.isPositionOutOfBounds(this.tempXOffset, this.tempYOffset)) {
+ LOGGER.info("Text is not in bounds. This will not be saved in order to keep the user from making the hud inaccessible.")
+ return
+ }
+ LOGGER.info("Saving Pos...")
+
+ val anchor = ScreenUtil.getAnchor(this.tempXOffset, this.tempYOffset)
+
+ val newConf = GimbalClientConfig(
+ guiSettings = GimbalGuiSettings(
+ showHud = oldConf.guiSettings.showHud,
+ offset = ScaledRes(
+ scaledX = this.tempXOffset,
+ scaledY = this.tempYOffset,
+ ),
+ horizontalAnchor = anchor.first,
+ verticalAnchor = anchor.second,
+ hudOptions = oldConf.guiSettings.hudOptions
+ ),
+ toastSettings = oldConf.toastSettings,
+ playerFlySpeed = oldConf.playerFlySpeed,
+ shouldEscResetMode = oldConf.shouldEscResetMode,
+ defaultMode = oldConf.defaultMode
+ )
+
+ cfg.updateConfig(newConf)
+ }
+
+ override fun close() {
+ this.save()
+ this.client!!.setScreen(this.parent)
+ }
+
+ override fun tick() {
+ super.tick()
+ if (this.shouldFollow) {
+ val mouse = this.client?.mouse!!
+ val wantedX = ScreenUtil.getScaled(this.client!!.window.width, mouse.x.toFloat())
+ val wantedY = ScreenUtil.getScaled(this.client!!.window.height, mouse.y.toFloat())
+ if (!ScreenUtil.isPositionOutOfBounds(wantedX, wantedY)) {
+ this.tempXOffset = wantedX
+ this.tempYOffset = wantedY
+ }
+ }
+ }
+
+ override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ this.shouldFollow = true
+ return super.mouseClicked(mouseX, mouseY, button)
+ }
+
+ override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ this.shouldFollow = false
+ return super.mouseReleased(mouseX, mouseY, button)
+ }
+
+ override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) {
+ this.renderBackground(matrices)
+ drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 15, 16777215)
+ val scaleFactor = this.client!!.window.calculateScaleFactor(
+ this.client!!.options.guiScale.value,
+ this.client!!.forcesUnicodeFont()
+ )
+ val anchor = ScreenUtil.getAnchor(this.tempXOffset, this.tempYOffset)
+ this.textRenderer.drawWithShadow(
+ matrices,
+ Text.translatable(TranslationKeys.Gui.Config.Hud.EXAMPLE_HUD_TEXT),
+ ScreenUtil.getXForAnchor(
+ ScreenUtil.getReal(this.client!!.window.width, this.tempXOffset) / scaleFactor,
+ anchor.first,
+ this.textRenderer.getWidth(Text.translatable(TranslationKeys.Gui.Config.Hud.EXAMPLE_HUD_TEXT))
+ ),
+ ScreenUtil.getYForAnchor(
+ ScreenUtil.getReal(this.client!!.window.height, this.tempYOffset) / scaleFactor,
+ anchor.second,
+ this.textRenderer.fontHeight
+ ),
+ 0xFFFFFF
+ )
+ super.render(matrices, mouseX, mouseY, delta)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/screen/GimbalSettingsGui.kt b/src/main/java/net/moonleay/gimbal/client/screen/GimbalSettingsGui.kt
new file mode 100644
index 0000000..4e11df4
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/screen/GimbalSettingsGui.kt
@@ -0,0 +1,290 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.screen
+
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.client.gui.widget.ButtonWidget
+import net.minecraft.client.gui.widget.CyclingButtonWidget
+import net.minecraft.client.util.math.MatrixStack
+import net.minecraft.screen.ScreenTexts
+import net.minecraft.text.Text
+import net.moonleay.gimbal.client.config.ClientConfigHolder
+import net.moonleay.gimbal.client.config.GimbalClientConfig
+import net.moonleay.gimbal.client.config.GimbalGuiSettings
+import net.moonleay.gimbal.client.config.enums.HudOptions
+import net.moonleay.gimbal.client.config.enums.ToastSettings
+import net.moonleay.gimbal.client.screen.widgets.GimbalSliderWidget
+import net.moonleay.gimbal.client.util.NumberUtil
+import net.moonleay.gimbal.constants.TranslationKeys
+import net.moonleay.gimbal.editor.state.mode.Mode
+
+class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfigHolder) :
+ Screen(Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)) {
+
+ private var hudOptions: HudOptions
+ private var toastSettings: ToastSettings
+ private var playerFlySpeed: Int
+ private var defaultMode: Mode
+
+ init {
+ this.hudOptions = cfg.config.guiSettings.hudOptions
+ this.toastSettings = cfg.config.toastSettings
+ this.playerFlySpeed = cfg.config.playerFlySpeed
+ this.defaultMode = cfg.config.defaultMode
+ }
+
+ override fun init() {
+ this.addDrawableChild(CyclingButtonWidget.onOffBuilder(
+// Text.translatable("gimbal.gui.enabled"),
+// Text.translatable("gimbal.gui.disabled")
+ )
+ .initially(cfg.config.guiSettings.showHud)
+ .build(
+ this.width / 2 - 155,
+ this.height / 6 + 24 * 0,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.Hud.SHOW_HUD)
+ ) { _: CyclingButtonWidget?, isEnabled: Boolean? ->
+ val oldGui = cfg.config.guiSettings
+ val newGui = GimbalGuiSettings(
+ showHud = isEnabled ?: true,
+ offset = oldGui.offset,
+ horizontalAnchor = oldGui.horizontalAnchor,
+ verticalAnchor = oldGui.verticalAnchor,
+ hudOptions = oldGui.hudOptions
+ )
+ val newConf = GimbalClientConfig(
+ guiSettings = newGui,
+ toastSettings = cfg.config.toastSettings,
+ playerFlySpeed = cfg.config.playerFlySpeed,
+ shouldEscResetMode = cfg.config.shouldEscResetMode,
+ defaultMode = cfg.config.defaultMode
+ )
+ cfg.updateConfig(newConf)
+ })
+
+ this.addDrawableChild(ButtonWidget(
+ this.width / 2 - 155 + 160,
+ this.height / 6 + 24 * 0,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.Hud.EDIT_HUD)
+ ) { _: ButtonWidget? ->
+ this.client!!.setScreen(GimbalEditHudGui(this, cfg))
+ })
+
+ this.addDrawableChild>(
+ CyclingButtonWidget.builder { value: HudOptions? ->
+ when (value) {
+ HudOptions.ALL -> {
+ return@builder HudOptions.ALL.translatableText
+ }
+
+ HudOptions.NUMBER -> {
+ return@builder HudOptions.NUMBER.translatableText
+ }
+
+ HudOptions.INITIAL -> {
+ return@builder HudOptions.INITIAL.translatableText
+ }
+
+ HudOptions.ONLY_MODE -> {
+ return@builder HudOptions.ONLY_MODE.translatableText
+ }
+
+ else -> return@builder Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_ALL)
+ }
+ }
+ .values(HudOptions.entries)
+ .initially(this.hudOptions)
+ .build(
+ this.width / 2 - 155,
+ this.height / 6 + 24 * 1,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_MODIFIERS)
+ ) { _: CyclingButtonWidget?, hudDO: HudOptions ->
+ this.hudOptions = hudDO
+
+ val oldConfig = cfg.config
+ val oldGuiConfig = oldConfig.guiSettings
+ val newConfig = GimbalClientConfig(
+ guiSettings = GimbalGuiSettings(
+ horizontalAnchor = oldGuiConfig.horizontalAnchor,
+ verticalAnchor = oldGuiConfig.verticalAnchor,
+ showHud = oldGuiConfig.showHud,
+ offset = oldGuiConfig.offset,
+ hudOptions = this.hudOptions
+ ),
+ toastSettings = oldConfig.toastSettings,
+ playerFlySpeed = oldConfig.playerFlySpeed,
+ shouldEscResetMode = oldConfig.shouldEscResetMode,
+ defaultMode = oldConfig.defaultMode
+ )
+ cfg.updateConfig(newConfig)
+ }
+ )
+
+
+ this.addDrawableChild>(
+ CyclingButtonWidget.builder { value: ToastSettings? ->
+ when (value) {
+ ToastSettings.ALL -> {
+ return@builder ToastSettings.ALL.translatableText
+ }
+
+ ToastSettings.ONLY_TOGGLE -> {
+ return@builder ToastSettings.ONLY_TOGGLE.translatableText
+ }
+
+ ToastSettings.ONLY_SYSTEM -> {
+ return@builder ToastSettings.ONLY_SYSTEM.translatableText
+ }
+
+ ToastSettings.NONE -> {
+ return@builder ToastSettings.NONE.translatableText
+ }
+
+ else -> return@builder Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_ALL)
+ }
+ }
+ .values(ToastSettings.entries)
+ .initially(this.toastSettings)
+ .build(
+ this.width / 2 - 155 + 160,
+ this.height / 6 + 24 * 1,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.Toasts.SHOW_TOASTS)
+ ) { _: CyclingButtonWidget?, toastStng: ToastSettings ->
+ this.toastSettings = toastStng
+
+ val oldConfig = cfg.config
+ val newConfig = GimbalClientConfig(
+ guiSettings = oldConfig.guiSettings,
+ toastSettings = this.toastSettings,
+ playerFlySpeed = oldConfig.playerFlySpeed,
+ shouldEscResetMode = oldConfig.shouldEscResetMode,
+ defaultMode = oldConfig.defaultMode
+ )
+ cfg.updateConfig(newConfig)
+ }
+ )
+
+ this.addDrawableChild(GimbalSliderWidget(
+ this.width / 2 - 155,
+ this.height / 6 + 24 * 2,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.PLAYER_FLY_SPEED),
+ NumberUtil.linearInterpolate(this.playerFlySpeed.toDouble(), 100.0, 1000.0, 0.0, 1.0),
+ 100.0,
+ 1000.0,
+ ) { value ->
+ this.playerFlySpeed = NumberUtil.linearInterpolate(value, 0.0, 1.0, 100.0, 1000.0).toInt()
+
+ if (client!!.player != null && client!!.player!!.isCreative) {
+ client!!.player!!.abilities.flySpeed = (this.playerFlySpeed / 100) * 0.05f
+ }
+
+ val oldConfig = cfg.config
+ val newConfig = GimbalClientConfig(
+ guiSettings = oldConfig.guiSettings,
+ toastSettings = this.toastSettings,
+ playerFlySpeed = this.playerFlySpeed,
+ shouldEscResetMode = oldConfig.shouldEscResetMode,
+ defaultMode = oldConfig.defaultMode
+ )
+ cfg.updateConfig(newConfig)
+ })
+
+ this.addDrawableChild(CyclingButtonWidget.onOffBuilder()
+ .initially(cfg.config.shouldEscResetMode)
+ .build(
+ this.width / 2 - 155,
+ this.height / 6 + 24 * 3,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.SHOULD_ESC_RESET_MODE)
+ ) { _: CyclingButtonWidget?, isEnabled: Boolean? ->
+ val newConf = GimbalClientConfig(
+ guiSettings = cfg.config.guiSettings,
+ toastSettings = cfg.config.toastSettings,
+ playerFlySpeed = cfg.config.playerFlySpeed,
+ shouldEscResetMode = isEnabled?: true,
+ defaultMode = cfg.config.defaultMode
+ )
+ cfg.updateConfig(newConf)
+ })
+
+
+
+ this.addDrawableChild>(
+ CyclingButtonWidget.builder { value: Mode? ->
+ if (value == null) {
+ return@builder Text.literal(Mode.UNKNOWN.displayName)
+ }
+ return@builder Text.literal(value.displayName)
+ }
+ .values(Mode.entries)
+ .initially(this.defaultMode)
+ .build(
+ this.width / 2 - 155 + 160,
+ this.height / 6 + 24 * 3,
+ 150,
+ 20,
+ Text.translatable(TranslationKeys.Gui.Config.DEFAULT_MODE)
+ ) { b: CyclingButtonWidget?, requestedMode: Mode ->
+ if (requestedMode.hidden){
+ b!!.value = Mode.NORMAL
+ this.defaultMode = Mode.NORMAL
+ }
+ else {
+ this.defaultMode = requestedMode
+ }
+
+ val oldConfig = cfg.config
+ val newConfig = GimbalClientConfig(
+ guiSettings = oldConfig.guiSettings,
+ toastSettings = oldConfig.toastSettings,
+ playerFlySpeed = oldConfig.playerFlySpeed,
+ shouldEscResetMode = oldConfig.shouldEscResetMode,
+ defaultMode = this.defaultMode
+ )
+ cfg.updateConfig(newConfig)
+ }
+ )
+
+ // Done button
+ this.addDrawableChild(ButtonWidget(
+ this.width / 2 - 100, this.height / 6 + 168, 200, 20, ScreenTexts.DONE
+ ) { _: ButtonWidget? ->
+ this.client!!.setScreen(
+ this.parent
+ )
+ })
+ }
+
+ override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) {
+ this.renderBackground(matrices)
+ drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 15, 16777215)
+ super.render(matrices, mouseX, mouseY, delta)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/screen/widgets/GimbalSliderWidget.kt b/src/main/java/net/moonleay/gimbal/client/screen/widgets/GimbalSliderWidget.kt
new file mode 100644
index 0000000..c244615
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/screen/widgets/GimbalSliderWidget.kt
@@ -0,0 +1,50 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.screen.widgets
+
+import net.minecraft.client.gui.widget.SliderWidget
+import net.minecraft.text.Text
+import net.moonleay.gimbal.client.util.NumberUtil
+
+class GimbalSliderWidget(
+ x: Int,
+ y: Int,
+ width: Int,
+ height: Int,
+ private val text: Text,
+ value: Double,
+ private val lowerEnd: Double,
+ private val upperEnd: Double,
+ private val setValue: (Double) -> Unit,
+) :
+ SliderWidget(x, y, width, height, text, value) {
+ init {
+ this.message = this.text.copy()
+ .append(": " + (NumberUtil.linearInterpolate(this.value, 0.0, 1.0, this.lowerEnd, this.upperEnd).toInt()))
+ }
+
+ override fun updateMessage() {
+ this.message = this.text.copy()
+ .append(": " + (NumberUtil.linearInterpolate(this.value, 0.0, 1.0, this.lowerEnd, this.upperEnd).toInt()))
+ }
+
+ override fun applyValue() {
+ this.setValue(this.value)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/util/ChatUtil.kt b/src/main/java/net/moonleay/gimbal/client/util/ChatUtil.kt
new file mode 100644
index 0000000..b53d959
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/util/ChatUtil.kt
@@ -0,0 +1,54 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.util
+
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.toast.SystemToast
+import net.minecraft.text.Text
+import net.moonleay.gimbal.client.config.GimbalClientConfig
+
+object ChatUtil {
+ /**
+ * Note: command arg should contain "/" at the beginning.
+ * */
+ fun sendCommand(command: String, client: MinecraftClient, addToHistory: Boolean = true): Boolean {
+ if (addToHistory) {
+ client.inGameHud.chatHud.addToMessageHistory(command)
+ }
+ return client.player?.sendCommand(command.substring(1))?: false
+ }
+
+ fun addToChatHistory(message: String, client: MinecraftClient) {
+ client.inGameHud.chatHud.addMessage(Text.of(message))
+ }
+
+ fun showToastToSelf(
+ title: String,
+ description: String,
+ type: ToastType,
+ config: GimbalClientConfig,
+ client: MinecraftClient,
+ ) {
+ if (!config.toastSettings.allowedTypes.contains(type))
+ return
+
+ val toast = SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.of(title), Text.of(description))
+ client.toastManager.add(toast)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/util/NumberUtil.kt b/src/main/java/net/moonleay/gimbal/client/util/NumberUtil.kt
new file mode 100644
index 0000000..e335842
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/util/NumberUtil.kt
@@ -0,0 +1,44 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.util
+
+object NumberUtil {
+
+ /**
+ * Interpolate a number between two numbers in a linear way
+ */
+ fun linearInterpolate(number: Double, min: Double, max: Double, lowerEnd: Double, upperEnd: Double): Double {
+ val subtractFromNr = (0 - min) * -1
+ val minMaxDiff = max - min
+ val onePercent = minMaxDiff / 100.0
+ val percentOfNumber = (number - subtractFromNr) / onePercent
+
+ val toAddToLowerEnd = (0 - lowerEnd) * -1
+ val upperLowerDiff = upperEnd - lowerEnd
+ val onePercentOfEnd = upperLowerDiff / 100.0
+ return (percentOfNumber * onePercentOfEnd) + toAddToLowerEnd
+ }
+
+ /**
+ * Interpolate a number between two numbers in a logarithmic way
+ */
+ fun logarithmicInterpolate(number: Double, min: Double, max: Double, lowerEnd: Double, upperEnd: Double): Double {
+ TODO("Not impl.")
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/util/ToastType.kt b/src/main/java/net/moonleay/gimbal/client/util/ToastType.kt
new file mode 100644
index 0000000..4dc9312
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/util/ToastType.kt
@@ -0,0 +1,24 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.util
+
+enum class ToastType {
+ TOGGLE,
+ SYSTEM,
+}
diff --git a/src/main/java/net/moonleay/gimbal/client/util/screen/ScreenUtil.kt b/src/main/java/net/moonleay/gimbal/client/util/screen/ScreenUtil.kt
new file mode 100644
index 0000000..5a5d4f7
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/client/util/screen/ScreenUtil.kt
@@ -0,0 +1,71 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.client.util.screen
+
+import net.moonleay.gimbal.client.config.enums.HorizontalAnchor
+import net.moonleay.gimbal.client.config.enums.VerticalAnchor
+
+object ScreenUtil {
+
+ fun getAnchor(x: Double, y: Double): Pair {
+ return when (x) {
+ in 0.0..<34.0 -> HorizontalAnchor.LEFT
+ in 34.0..<67.0 -> HorizontalAnchor.CENTER
+ else -> HorizontalAnchor.RIGHT
+ } to when (y) {
+ in 0.0..<34.0 -> VerticalAnchor.TOP
+ in 34.0..<67.0 -> VerticalAnchor.CENTER
+ else -> VerticalAnchor.BOTTOM
+ }
+ }
+
+ fun getXForAnchor(x: Float, anchor: HorizontalAnchor, textWidth: Int): Float {
+ return when (anchor) {
+ HorizontalAnchor.LEFT -> x
+ HorizontalAnchor.CENTER -> x - (textWidth / 2)
+ HorizontalAnchor.RIGHT -> x - textWidth
+ }
+ }
+
+
+ fun getYForAnchor(y: Float, anchor: VerticalAnchor, textHeight: Int): Float {
+ return when (anchor) {
+ VerticalAnchor.TOP -> y
+ VerticalAnchor.CENTER -> y - (textHeight / 2)
+ VerticalAnchor.BOTTOM -> y - textHeight
+ }
+ }
+
+ fun getScaled(length: Int, real: Float): Double {
+ val scale = length / 100.0
+ return real / scale
+ }
+
+ fun getReal(length: Int, scaled: Double): Float {
+ val scale = length / 100.0
+ return (scaled * scale).toFloat()
+ }
+
+ fun isPositionOutOfBounds(x: Double, y: Double): Boolean {
+ val tooBig = 100 < x || 100 < y
+ val tooSmall = 0 > x || 0 > y
+ return tooBig || tooSmall
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt b/src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt
new file mode 100644
index 0000000..da664c0
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt
@@ -0,0 +1,28 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.constants
+
+import net.minecraft.util.Identifier
+import net.moonleay.gimbal.build.BuildConstants
+
+object PacketIDs {
+ val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
+ val GIMBAL_POLICY_PACKET_ID = Identifier(BuildConstants.modId, "gimbal_policy")
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt b/src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt
new file mode 100644
index 0000000..7263609
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt
@@ -0,0 +1,23 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.constants
+
+object PermissionIDs {
+ const val GIMBAL_USAGE_PERMISSION = "gimbal.use"
+}
diff --git a/src/main/java/net/moonleay/gimbal/constants/TranslationKeys.kt b/src/main/java/net/moonleay/gimbal/constants/TranslationKeys.kt
new file mode 100644
index 0000000..0db8509
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/constants/TranslationKeys.kt
@@ -0,0 +1,127 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.constants
+
+import net.moonleay.gimbal.build.BuildConstants
+
+object TranslationKeys {
+ object Gui {
+ const val BASE = "gui.${BuildConstants.modId}."
+
+ object Config {
+ const val BASE = "${TranslationKeys.Gui.BASE}conf."
+
+ const val SCREEN_NAME = "${BASE}settings"
+ const val GENERIC_ENABLED = "${BASE}enabled"
+ const val GENERIC_DISABLED = "${BASE}disabled"
+
+ const val PLAYER_FLY_SPEED = "${BASE}flySpeed"
+ const val SHOULD_ESC_RESET_MODE = "${BASE}shouldESCResetMode"
+ const val DEFAULT_MODE = "${BASE}defaultMode"
+
+ object Hud {
+ const val BASE = "${TranslationKeys.Gui.Config.BASE}hud."
+
+ const val SHOW_HUD = "${BASE}show"
+ const val EDIT_HUD = "${BASE}edit"
+ const val RESET_HUD = "${BASE}reset"
+ const val EXAMPLE_HUD_TEXT = "${BASE}example"
+
+ object Modifiers {
+ const val BASE = "${TranslationKeys.Gui.Config.Hud.BASE}modifiers."
+
+ const val SHOW_MODIFIERS = "${BASE}show"
+ const val SHOW_ALL = "${BASE}all"
+ const val SHOW_NUMBER = "${BASE}number"
+ const val SHOW_INITIALS = "${BASE}initials"
+ const val SHOW_MODE_ONLY = "${BASE}modeOnly"
+ }
+ }
+
+ object Toasts {
+ const val BASE = "${TranslationKeys.Gui.Config.BASE}toasts."
+
+ const val SHOW_TOASTS = "${BASE}show"
+ const val SHOW_ALL = "${BASE}all"
+ const val SHOW_TOGGLE = "${BASE}toggle"
+ const val SHOW_SYSTEM = "${BASE}system"
+ const val SHOW_NONE = "${BASE}none"
+ }
+ }
+ }
+
+ object Keybindings {
+ // No base here, Categories and Bindings have separate BASEs
+ object Category {
+ const val BASE = "category.${BuildConstants.modId}."
+
+ object Editor {
+ const val BASE = "${TranslationKeys.Keybindings.Category.BASE}editor."
+
+ const val MODE = "${BASE}mode"
+ const val MODIFIER = "${BASE}modifier"
+ }
+
+ object Game {
+ const val BASE = "${TranslationKeys.Keybindings.Category.BASE}game."
+
+ const val GAMEMODE = "${BASE}mode"
+ }
+ }
+
+ object Binding {
+ const val BASE = "key.${BuildConstants.modId}."
+
+ object Editor {
+ const val BASE = "${TranslationKeys.Keybindings.Binding.BASE}editor."
+
+ object Mode {
+ const val BASE = "${TranslationKeys.Keybindings.Binding.Editor.BASE}mode."
+
+ const val INSERT = "${BASE}insert"
+ const val REPLACE = "${BASE}replace"
+ const val VISUAL = "${BASE}visual"
+ }
+
+ object Modifier {
+ const val BASE = "${TranslationKeys.Keybindings.Binding.Editor.BASE}modifier."
+
+ const val BULLDOZER = "${BASE}autoClicker"
+ const val FORCE_PLACE = "${BASE}forcePlace"
+ const val NO_UPDATES = "${BASE}noUpdates"
+ const val NO_CLIP = "${BASE}noClip"
+ }
+ }
+
+ object Game {
+ const val BASE = "${TranslationKeys.Keybindings.Binding.BASE}game."
+
+ object Mode {
+ const val BASE = "${TranslationKeys.Keybindings.Binding.Game.BASE}mode."
+
+ const val SURVIVAL = "${BASE}survival"
+ const val CREATIVE = "${BASE}creative"
+ const val SPECTATOR = "${BASE}spectator"
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/datagen/DataGenerator.kt b/src/main/java/net/moonleay/gimbal/datagen/DataGenerator.kt
new file mode 100644
index 0000000..bd2452e
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/datagen/DataGenerator.kt
@@ -0,0 +1,33 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.datagen
+
+import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint
+import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
+import net.moonleay.gimbal.build.BuildConstants
+import org.apache.logging.log4j.LogManager
+
+internal class DataGenerator : DataGeneratorEntrypoint {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
+ LOGGER.info("Starting Data Generation")
+ fabricDataGenerator.addProvider(EnUsLanguageProvider(fabricDataGenerator))
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/datagen/EnUsLanguageProvider.kt b/src/main/java/net/moonleay/gimbal/datagen/EnUsLanguageProvider.kt
new file mode 100644
index 0000000..00279a1
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/datagen/EnUsLanguageProvider.kt
@@ -0,0 +1,96 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.datagen
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
+import net.moonleay.gimbal.constants.TranslationKeys
+
+class EnUsLanguageProvider(dataGenerator: FabricDataGenerator?) :
+ FabricLanguageProvider(dataGenerator, "en_us") {
+
+ override fun generateTranslations(translationBuilder: TranslationBuilder?) {
+ if (translationBuilder == null) return
+ /// Screens
+ // Gimbal settings screen
+ translationBuilder.add(TranslationKeys.Gui.Config.SCREEN_NAME, "Gimbal Settings")
+
+ // Hud
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.SHOW_HUD, "Show HUD")
+
+
+ //Gimbal HUD pos edit
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.EDIT_HUD, "Edit HUD Layout...")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.RESET_HUD, "Reset Layout")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.EXAMPLE_HUD_TEXT, "EXAMPLE [No Clip, Force]")
+
+ //Gimbal HUD Content
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_MODIFIERS, "Show Modifiers")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_ALL, "All")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_NUMBER, "Number")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_INITIALS, "Short")
+ translationBuilder.add(TranslationKeys.Gui.Config.Hud.Modifiers.SHOW_MODE_ONLY, "None")
+
+ //Gimbal Toasts
+ translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_TOASTS, "Show Toasts")
+ translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_ALL, "All")
+ translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_TOGGLE, "Only Toggle")
+ translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_SYSTEM, "Only System")
+ translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_NONE, "None")
+
+ // Gimbal Generic Settings
+ translationBuilder.add(TranslationKeys.Gui.Config.PLAYER_FLY_SPEED, "Fly Speed")
+ translationBuilder.add(TranslationKeys.Gui.Config.SHOULD_ESC_RESET_MODE, "ESC Resets Mode")
+ translationBuilder.add(TranslationKeys.Gui.Config.DEFAULT_MODE, "Default Mode")
+
+ // Gimbal Generic Gui
+ translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_ENABLED, "Enabled")
+ translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_DISABLED, "Disabled")
+
+ /// Options
+ // Editor modes
+ translationBuilder.add(TranslationKeys.Keybindings.Category.Editor.MODE, "Editor Modes")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Editor.Mode.INSERT, "Enter Insert Mode")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Editor.Mode.REPLACE, "Enter Replace Mode")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Editor.Mode.VISUAL, "Enter Visual Mode")
+
+ // Editor mode modifiers
+ translationBuilder.add(TranslationKeys.Keybindings.Category.Editor.MODIFIER, "Editor Mode Modifiers")
+ translationBuilder.add(
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.BULLDOZER,
+ "Toggle Bulldozer Modifier"
+ )
+ translationBuilder.add(
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.FORCE_PLACE,
+ "Toggle Force Place Modifier"
+ )
+ translationBuilder.add(
+ TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_UPDATES,
+ "Toggle No Updates Modifier"
+ )
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_CLIP, "Toggle No Clip Modifier")
+
+ // Game mode
+ translationBuilder.add(TranslationKeys.Keybindings.Category.Game.GAMEMODE, "Game Mode")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Game.Mode.SURVIVAL, "Enable Survival Mode")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Game.Mode.CREATIVE, "Enable Creative Mode")
+ translationBuilder.add(TranslationKeys.Keybindings.Binding.Game.Mode.SPECTATOR, "Enable Spectator Mode")
+
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/editor/ServerEditorManager.kt b/src/main/java/net/moonleay/gimbal/editor/ServerEditorManager.kt
new file mode 100644
index 0000000..c0a1801
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/ServerEditorManager.kt
@@ -0,0 +1,55 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor
+
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.editor.state.EditorState
+import net.moonleay.gimbal.editor.state.mode.Capability
+import net.moonleay.gimbal.editor.util.EditorUtil
+import org.apache.logging.log4j.LogManager
+import java.util.*
+
+object ServerEditorManager {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ private val STATEMAP = mutableMapOf()
+
+ fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
+ STATEMAP[playerUUID] = editorState
+ LOGGER.debug("{}: {} with {}", playerUUID, editorState.editorMode, editorState.editorModifier)
+ }
+
+
+ /*
+ * Check if a player should be able to perform an action
+ * */
+ fun shouldPlayer(playerUUID: UUID, capability: Capability): Boolean {
+ if (!STATEMAP.containsKey(playerUUID))
+ return false
+ val state = STATEMAP[playerUUID]!!
+ return EditorUtil.shouldPlayer(capability, state)
+ }
+
+
+// fun playerHasModifier(playerUUID: UUID, modifier: ModeModifier): Boolean {
+// if (!STATEMAP.containsKey(playerUUID))
+// return false
+// return STATEMAP[playerUUID]!!.editorModifier.contains(modifier) ?: false
+// }
+}
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/EditorState.kt b/src/main/java/net/moonleay/gimbal/editor/state/EditorState.kt
new file mode 100644
index 0000000..bda6a97
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/EditorState.kt
@@ -0,0 +1,29 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state
+
+import kotlinx.serialization.Serializable
+import net.moonleay.gimbal.editor.state.mode.Mode
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
+
+@Serializable
+data class EditorState(
+ var editorMode: Mode,
+ var editorModifier: MutableList,
+)
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt b/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt
new file mode 100644
index 0000000..37c7341
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt
@@ -0,0 +1,28 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+enum class GimbalPolicyType {
+ ALLOWED,
+ DENIED,
+ NOT_PRESENT,
+}
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt b/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt
new file mode 100644
index 0000000..7dffedc
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class GimbalServerState(
+ val protocolVersion: Int,
+ val policyType: GimbalPolicyType,
+)
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/mode/Capability.kt b/src/main/java/net/moonleay/gimbal/editor/state/mode/Capability.kt
new file mode 100644
index 0000000..bc8a055
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/mode/Capability.kt
@@ -0,0 +1,29 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state.mode
+
+enum class Capability {
+ INSERT,
+ REPLACE,
+ CAN_INTERACT,
+ NO_CLIP,
+ FORCE_PLACE,
+ NO_UPDATES,
+ BULLDOZER,
+}
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/mode/Mode.kt b/src/main/java/net/moonleay/gimbal/editor/state/mode/Mode.kt
new file mode 100644
index 0000000..5481b22
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/mode/Mode.kt
@@ -0,0 +1,28 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state.mode
+
+enum class Mode(val displayName: String, val color: Int, val hidden: Boolean, val incompatibleModifiers: List){
+ UNKNOWN("UNKNOWN", 0x000000, true, listOf()), // Unknown mode. This mode cannot be entered
+ NORMAL("NORMAL", 0x90a959, false, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
+ INSERT("INSERT", 0xf4bf75, false, listOf()), // Place and break blocks
+ REPLACE("REPLACE", 0xac4242, false, listOf(ModeModifier.NO_UPDATES)), // Replace blocks
+ // Add hidden modes after this comment
+ VISUAL("VISUAL", 0x6a9fb5, true, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
+}
diff --git a/src/main/java/net/moonleay/gimbal/editor/state/mode/ModeModifier.kt b/src/main/java/net/moonleay/gimbal/editor/state/mode/ModeModifier.kt
new file mode 100644
index 0000000..da99041
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/state/mode/ModeModifier.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.state.mode
+
+enum class ModeModifier(val displayName: String, val shortName: String) {
+// NONE("None"), // No Modifiers - default behavior
+NO_UPDATES("NO UPDATES", "NU"), // Do not update blocks when placing
+ BULLDOZER("BULLDOZER", "BLR"), // Break blocks fast
+ FORCE_PLACE("FORCE", "FP"), // Ignore block placement restrictions
+ NO_CLIP("NO CLIP", "NC"), // Do not collide with blocks
+}
diff --git a/src/main/java/net/moonleay/gimble/editor/util/EditorUtil.kt b/src/main/java/net/moonleay/gimbal/editor/util/EditorUtil.kt
similarity index 53%
rename from src/main/java/net/moonleay/gimble/editor/util/EditorUtil.kt
rename to src/main/java/net/moonleay/gimbal/editor/util/EditorUtil.kt
index 6c37255..55b3c52 100644
--- a/src/main/java/net/moonleay/gimble/editor/util/EditorUtil.kt
+++ b/src/main/java/net/moonleay/gimbal/editor/util/EditorUtil.kt
@@ -1,9 +1,28 @@
-package net.moonleay.gimble.editor.util
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.util
+
+import net.moonleay.gimbal.editor.state.EditorState
+import net.moonleay.gimbal.editor.state.mode.Capability
+import net.moonleay.gimbal.editor.state.mode.Mode
+import net.moonleay.gimbal.editor.state.mode.ModeModifier
-import net.moonleay.gimble.editor.state.EditorState
-import net.moonleay.gimble.editor.state.mode.Capability
-import net.moonleay.gimble.editor.state.mode.Mode
-import net.moonleay.gimble.editor.state.mode.ModeModifier
object EditorUtil {
diff --git a/src/main/java/net/moonleay/gimbal/editor/util/GimbalPolicy.kt b/src/main/java/net/moonleay/gimbal/editor/util/GimbalPolicy.kt
new file mode 100644
index 0000000..1d4e5ce
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/editor/util/GimbalPolicy.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.editor.util
+
+import kotlinx.serialization.Serializable
+import net.moonleay.gimbal.editor.state.GimbalPolicyType
+
+@Serializable
+data class GimbalPolicy(
+ val policy: GimbalPolicyType,
+)
diff --git a/src/main/java/net/moonleay/gimbal/mixin/BulldozerMixin.java b/src/main/java/net/moonleay/gimbal/mixin/BulldozerMixin.java
new file mode 100644
index 0000000..df682c2
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/BulldozerMixin.java
@@ -0,0 +1,84 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.network.ClientPlayerEntity;
+import net.minecraft.client.network.ClientPlayerInteractionManager;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.moonleay.gimbal.client.editor.ClientEditor;
+import net.moonleay.gimbal.editor.state.mode.Capability;
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import java.util.Objects;
+
+public abstract class BulldozerMixin {
+
+ @Mixin(MinecraftClient.class)
+ public static abstract class MinecraftClientMixin {
+ @Shadow
+ @Nullable
+ public ClientPlayerEntity player;
+ @Shadow
+ protected int attackCooldown;
+
+ @Inject(method = "doAttack", at = @At(value = "HEAD"))
+ private void func(CallbackInfoReturnable cir) {
+ if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
+ return;
+ }
+ this.attackCooldown = 0;
+ }
+
+ @Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
+ private void func2(boolean breaking, CallbackInfo ci) {
+ if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
+ return;
+ }
+ this.attackCooldown = 0;
+ }
+ }
+
+ @Mixin(ClientPlayerInteractionManager.class)
+ public static abstract class ClientPlayerInteractionManagerMixin {
+
+ @Shadow
+ private int blockBreakingCooldown;
+
+ @Shadow
+ @Final
+ private MinecraftClient client;
+
+ @Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
+ private void func(BlockPos pos, Direction direction, CallbackInfoReturnable cir) {
+ if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
+ return;
+ }
+ this.blockBreakingCooldown = 0;
+ }
+ }
+}
diff --git a/src/main/java/net/moonleay/gimble/mixin/ForcePlaceMixin.java b/src/main/java/net/moonleay/gimbal/mixin/ForcePlaceMixin.java
similarity index 53%
rename from src/main/java/net/moonleay/gimble/mixin/ForcePlaceMixin.java
rename to src/main/java/net/moonleay/gimbal/mixin/ForcePlaceMixin.java
index 4a861fd..042d704 100644
--- a/src/main/java/net/moonleay/gimble/mixin/ForcePlaceMixin.java
+++ b/src/main/java/net/moonleay/gimbal/mixin/ForcePlaceMixin.java
@@ -1,10 +1,28 @@
-package net.moonleay.gimble.mixin;
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
-import net.moonleay.gimble.editor.ServerEditorManager;
-import net.moonleay.gimble.editor.state.mode.Capability;
+import net.moonleay.gimbal.editor.ServerEditorManager;
+import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
diff --git a/src/main/java/net/moonleay/gimbal/mixin/HudMixin.java b/src/main/java/net/moonleay/gimbal/mixin/HudMixin.java
new file mode 100644
index 0000000..5c0f58f
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/HudMixin.java
@@ -0,0 +1,74 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.font.TextRenderer;
+import net.minecraft.client.gui.hud.InGameHud;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.text.Text;
+import net.moonleay.gimbal.client.ClientMain;
+import net.moonleay.gimbal.client.config.GimbalGuiSettings;
+import net.moonleay.gimbal.client.editor.ClientEditor;
+import net.moonleay.gimbal.client.util.screen.ScreenUtil;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(InGameHud.class)
+public abstract class HudMixin {
+
+ @Shadow @Final private MinecraftClient client;
+
+ @Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
+ private void render(MatrixStack matrices, CallbackInfo ci) {
+ TextRenderer tr = this.client.textRenderer;
+ GimbalGuiSettings conf = ClientMain.CONFIG.getConfig().getGuiSettings();
+ if (!conf.getShowHud())
+ return;
+ int scaleFactor = this.client.getWindow()
+ .calculateScaleFactor(
+ this.client.options.getGuiScale().getValue(),
+ this.client.forcesUnicodeFont()
+ );
+ Text displayText = ClientEditor.INSTANCE.getModeDisplayText(ClientMain.CONFIG.getConfig());
+ tr.drawWithShadow(
+ matrices,
+ displayText,
+ ScreenUtil.INSTANCE.getXForAnchor(
+ ScreenUtil.INSTANCE.getReal(
+ this.client.getWindow().getWidth(),
+ conf.getOffset().getScaledX() / scaleFactor),
+ conf.getHorizontalAnchor(),
+ this.client.textRenderer.getWidth(displayText)
+ ),
+ ScreenUtil.INSTANCE.getYForAnchor(
+ ScreenUtil.INSTANCE.getReal(
+ this.client.getWindow().getHeight(),
+ conf.getOffset().getScaledY() / scaleFactor),
+ conf.getVerticalAnchor(),
+ this.client.textRenderer.fontHeight
+ ),
+ ClientEditor.INSTANCE.getCurrentColor()
+ );
+ }
+}
diff --git a/src/main/java/net/moonleay/gimble/mixin/NoBlockUpdatesMixin.java b/src/main/java/net/moonleay/gimbal/mixin/NoBlockUpdatesMixin.java
similarity index 58%
rename from src/main/java/net/moonleay/gimble/mixin/NoBlockUpdatesMixin.java
rename to src/main/java/net/moonleay/gimbal/mixin/NoBlockUpdatesMixin.java
index 4055ad1..9fec1e5 100644
--- a/src/main/java/net/moonleay/gimble/mixin/NoBlockUpdatesMixin.java
+++ b/src/main/java/net/moonleay/gimbal/mixin/NoBlockUpdatesMixin.java
@@ -1,11 +1,29 @@
-package net.moonleay.gimble.mixin;
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
-import net.moonleay.gimble.editor.ServerEditorManager;
-import net.moonleay.gimble.editor.state.mode.Capability;
+import net.moonleay.gimbal.editor.ServerEditorManager;
+import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
diff --git a/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java b/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java
new file mode 100644
index 0000000..8e9a80a
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java
@@ -0,0 +1,106 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import com.mojang.authlib.GameProfile;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.Camera;
+import net.minecraft.entity.EntityPose;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.player.PlayerAbilities;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.world.World;
+import net.moonleay.gimbal.client.editor.ClientEditor;
+import net.moonleay.gimbal.editor.ServerEditorManager;
+import net.moonleay.gimbal.editor.state.mode.Capability;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import java.util.UUID;
+
+public abstract class NoClipMixin {
+
+ @Mixin(PlayerEntity.class) // Serverside, allows clipping
+ public static abstract class PlayerEntityMixin extends LivingEntity {
+ protected PlayerEntityMixin(EntityType extends LivingEntity> entityType, World world) {
+ super(entityType, world);
+ }
+
+ @Shadow
+ public abstract GameProfile getGameProfile();
+
+ @Shadow
+ public abstract PlayerAbilities getAbilities();
+
+ @Shadow
+ public abstract boolean isCreative();
+
+ @Inject(method = "tick", at = @At(value = "FIELD",
+ target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER)
+ )
+ private void enoClip(CallbackInfo ci) {
+ if (!this.isCreative())
+ return;
+ UUID uuid = this.getGameProfile().getId();
+
+ if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) {
+ return; // NoClip is not enabled
+ }
+ if (!this.getAbilities().flying) {
+ return;
+ }
+ // Enable NoClip
+ this.noClip = true;
+ }
+
+ @Inject(method = "updatePose", at = @At("HEAD"))
+ private void onUpdatePose(CallbackInfo ci) {
+ UUID uuid = this.getGameProfile().getId();
+
+ if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
+ return; // NoClip is not enabled
+ if (!this.getAbilities().flying)
+ return;
+
+ // Force standing pose in NoClip mode
+
+ this.setPose(EntityPose.STANDING);
+ }
+ }
+
+
+ @Mixin(Camera.class) // Clientside, fixes camera
+ public static abstract class CameraMixin {
+
+ @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
+ private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable cir) {
+ if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
+ return;
+ }
+ cir.setReturnValue(desiredCameraDistance);
+ cir.cancel();
+ }
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimble/mixin/NormalModeMixin.java b/src/main/java/net/moonleay/gimbal/mixin/NormalModeMixin.java
similarity index 58%
rename from src/main/java/net/moonleay/gimble/mixin/NormalModeMixin.java
rename to src/main/java/net/moonleay/gimbal/mixin/NormalModeMixin.java
index 372a400..d8f769a 100644
--- a/src/main/java/net/moonleay/gimble/mixin/NormalModeMixin.java
+++ b/src/main/java/net/moonleay/gimbal/mixin/NormalModeMixin.java
@@ -1,11 +1,29 @@
-package net.moonleay.gimble.mixin;
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.option.GameOptions;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import net.moonleay.gimble.editor.state.mode.Mode;
+import net.moonleay.gimbal.client.ClientMain;
+import net.moonleay.gimbal.client.editor.ClientEditor;
+import net.moonleay.gimbal.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -25,12 +43,12 @@ public class NormalModeMixin {
public ClientPlayerEntity player;
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
- private void setNormalMode(boolean pause, CallbackInfo ci) {
- if (ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
+ private void setDefaultMode(boolean pause, CallbackInfo ci) {
+ if (ClientMain.CONFIG.getConfig().getShouldEscResetMode() && ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
assert this.player != null;
if (this.player.isCreative()) {
// Set the editor mode to normal
- ClientEditor.INSTANCE.setMode(Mode.NORMAL);
+ ClientEditor.INSTANCE.setMode(ClientMain.CONFIG.getConfig().getDefaultMode());
ci.cancel();
}
}
diff --git a/src/main/java/net/moonleay/gimbal/mixin/PlayerFlySpeedMixin.java b/src/main/java/net/moonleay/gimbal/mixin/PlayerFlySpeedMixin.java
new file mode 100644
index 0000000..e846c91
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/PlayerFlySpeedMixin.java
@@ -0,0 +1,45 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.network.ClientPlayNetworkHandler;
+import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket;
+import net.moonleay.gimbal.client.ClientMain;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ClientPlayNetworkHandler.class)
+public abstract class PlayerFlySpeedMixin {
+
+ @Shadow
+ @Final
+ private MinecraftClient client;
+
+ @Inject(method = "onPlayerAbilities", at = @At(value = "RETURN"))
+ private void func(PlayerAbilitiesS2CPacket packet, CallbackInfo ci) {
+ this.client.player.getAbilities().setFlySpeed((ClientMain.CONFIG.getConfig().getPlayerFlySpeed() / 100) * 0.05f);
+ //client!!.player!!.abilities.flySpeed = (this.playerFlySpeed / 100) * 0.05f
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java b/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java
new file mode 100644
index 0000000..8a28216
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java
@@ -0,0 +1,104 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import net.minecraft.block.BlockState;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.*;
+import net.minecraft.state.property.Property;
+import net.minecraft.util.Hand;
+import net.minecraft.util.hit.BlockHitResult;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+import net.moonleay.gimbal.editor.ServerEditorManager;
+import net.moonleay.gimbal.editor.state.mode.Capability;
+import org.spongepowered.asm.mixin.*;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.UUID;
+
+public abstract class ReplaceModeMixin {
+
+ @Mixin(ItemPlacementContext.class)
+ public static abstract class ItemPlacementContextMixin extends ItemUsageContext {
+ @Shadow
+ protected boolean canReplaceExisting;
+
+ @Mutable
+ @Shadow
+ @Final
+ private BlockPos placementPos;
+
+ public ItemPlacementContextMixin(PlayerEntity player, Hand hand, BlockHitResult hit) {
+ super(player, hand, hit);
+ }
+
+ @Inject(method = "(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/hit/BlockHitResult;)V", at = @At(value = "RETURN"))
+ private void func(World world, PlayerEntity playerEntity, Hand hand, ItemStack itemStack, BlockHitResult blockHitResult, CallbackInfo ci) {
+ if (playerEntity == null)
+ return;
+ UUID id = playerEntity.getGameProfile().getId();
+ if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE))
+ return;
+
+ this.canReplaceExisting = true;
+ this.placementPos = blockHitResult.getBlockPos();
+ }
+ }
+
+ @Mixin(BlockItem.class)
+ public static abstract class BlockItemMixin extends Item {
+
+ public BlockItemMixin(Settings settings) {
+ super(settings);
+ }
+
+ @Shadow
+ protected abstract boolean place(ItemPlacementContext context, BlockState state);
+
+ @Redirect(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z"))
+ private boolean func(BlockItem instance, ItemPlacementContext context, BlockState state) {
+ if (context.getPlayer() == null)
+ return this.place(context, state);
+ UUID id = context.getPlayer().getGameProfile().getId();
+ if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE))
+ return this.place(context, state);
+ BlockState oldState = context.getWorld().getBlockState(context.getBlockPos());
+ return this.place(context, getTargetBlockState(oldState, instance.getBlock().getDefaultState()));
+ }
+
+ @Unique
+ public BlockState getTargetBlockState(BlockState oldState, BlockState newBlock) {
+ var oldManager = oldState.getBlock().getStateManager();
+ var newManager = newBlock.getBlock().getStateManager();
+ for (var prop : oldManager.getProperties()) {
+ var matchingProp = newManager.getProperty(prop.getName());
+ if (matchingProp != null) {
+ //noinspection rawtypes,unchecked
+ newBlock = newBlock.with((Property) matchingProp, oldState.get(matchingProp));
+ }
+ }
+ return newBlock;
+ }
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/mixin/YouInjectButtonMixin.java b/src/main/java/net/moonleay/gimbal/mixin/YouInjectButtonMixin.java
new file mode 100644
index 0000000..efa2a9c
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/mixin/YouInjectButtonMixin.java
@@ -0,0 +1,104 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.mixin;
+
+import net.minecraft.client.gui.screen.GameMenuScreen;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.TitleScreen;
+import net.minecraft.client.gui.widget.TexturedButtonWidget;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import net.moonleay.gimbal.build.BuildConstants;
+import net.moonleay.gimbal.client.ClientMain;
+import net.moonleay.gimbal.client.screen.GimbalSettingsGui;
+import net.moonleay.gimbal.constants.TranslationKeys;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+// What is my purpose?
+public class YouInjectButtonMixin {
+ // Go my god.
+
+ @Mixin(TitleScreen.class)
+ public static abstract class TitleScreenMixin extends Screen {
+
+ @Unique
+ private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
+
+ protected TitleScreenMixin(Text title) {
+ super(title);
+ }
+
+ @Inject(method = "init", at = @At(value = "RETURN"))
+ private void func(CallbackInfo ci) {
+ int l = this.height / 4 + 48;
+ this.addDrawableChild(
+ new TexturedButtonWidget(
+ this.width / 2 - 124 - 24,
+ l + 72 + 12,
+ 20,
+ 20,
+ 0,
+ 0,
+ 20,
+ GIMBAL_TEXTURE,
+ 20,
+ 40,
+ button -> this.client.setScreen(new GimbalSettingsGui(this, ClientMain.CONFIG)),
+ Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)
+ )
+ );
+ }
+ }
+
+
+ @Mixin(GameMenuScreen.class)
+ public static abstract class GameMenuScreenMixin extends Screen {
+ @Unique
+ private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
+
+ protected GameMenuScreenMixin(Text title) {
+ super(title);
+ }
+
+ @Inject(method = "initWidgets", at = @At(value = "RETURN"))
+ private void func(CallbackInfo ci) {
+ this.addDrawableChild(
+ new TexturedButtonWidget(
+ this.width / 2 - 124,
+ this.height / 4 + 96 + -16,
+ 20,
+ 20,
+ 0,
+ 0,
+ 20,
+ GIMBAL_TEXTURE,
+ 20,
+ 40,
+ button -> this.client.setScreen(new GimbalSettingsGui(this, ClientMain.CONFIG)),
+ Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)
+ )
+ );
+ }
+ }
+
+}
diff --git a/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt b/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt
new file mode 100644
index 0000000..fa179df
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt
@@ -0,0 +1,70 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.networking
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.cbor.Cbor
+import kotlinx.serialization.decodeFromByteArray
+import kotlinx.serialization.encodeToByteArray
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
+import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
+import net.minecraft.network.PacketByteBuf
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.client.editor.ClientEditor
+import net.moonleay.gimbal.constants.PacketIDs
+import net.moonleay.gimbal.editor.state.EditorState
+import net.moonleay.gimbal.editor.state.GimbalPolicyType
+import net.moonleay.gimbal.editor.state.GimbalServerState
+
+object GimbalClient {
+
+ fun registerPacketHandlers() {
+ ClientPlayNetworking.registerGlobalReceiver(PacketIDs.GIMBAL_POLICY_PACKET_ID) { _, _, buf, handler ->
+ val state = this.getServerState(buf)
+ val isUsable = this.isGimbalUsable(state)
+ if (isUsable) {
+ val buf = PacketByteBufs.create()
+ buf.writeByteArray(Cbor.encodeToByteArray(ClientEditor.getClientState()))
+ handler.sendPacket(PacketIDs.UPDATE_EDITOR_STATE_ID, buf)
+ }
+ ClientEditor.onPolicyReceived(state, false)
+ }
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ private fun getServerState(buf: PacketByteBuf): GimbalServerState {
+ val serverState = Cbor.decodeFromByteArray(buf.readByteArray())
+ return serverState
+ }
+
+ private fun isGimbalUsable(state: GimbalServerState): Boolean {
+ return state.policyType == GimbalPolicyType.ALLOWED && state.protocolVersion.toString() == BuildConstants.protocolVersion
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ private fun createStatePacket(state: EditorState): PacketByteBuf {
+ val buf = PacketByteBufs.create()
+ buf.writeByteArray(Cbor.encodeToByteArray(state))
+ return buf
+ }
+
+ fun sendStatePacket(state: EditorState) {
+ ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, createStatePacket(state))
+ }
+}
diff --git a/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt b/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt
new file mode 100644
index 0000000..fd0e654
--- /dev/null
+++ b/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt
@@ -0,0 +1,74 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.networking
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.cbor.Cbor
+import kotlinx.serialization.decodeFromByteArray
+import kotlinx.serialization.encodeToByteArray
+import me.lucko.fabric.api.permissions.v0.Permissions
+import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
+import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
+import net.minecraft.network.PacketByteBuf
+import net.minecraft.server.network.ServerPlayerEntity
+import net.moonleay.gimbal.build.BuildConstants
+import net.moonleay.gimbal.constants.PacketIDs
+import net.moonleay.gimbal.constants.PermissionIDs
+import net.moonleay.gimbal.editor.ServerEditorManager
+import net.moonleay.gimbal.editor.state.EditorState
+import net.moonleay.gimbal.editor.state.GimbalPolicyType
+import net.moonleay.gimbal.editor.state.GimbalServerState
+import org.apache.logging.log4j.LogManager
+
+object GimbalServer {
+ private val LOGGER = LogManager.getLogger(BuildConstants.modName)
+
+ fun registerPacketHandler() {
+ ServerPlayNetworking
+ .registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
+ { _, player, _, buf, _ ->
+ handleStateUpdate(player, buf)
+ }
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ fun notifyPlayerOfPolicy(player: ServerPlayerEntity) {
+ LOGGER.info("Sending policy to " + player.name.string)
+ val buf = PacketByteBufs.create()
+ buf.writeByteArray(
+ Cbor.encodeToByteArray(
+ GimbalServerState(
+ BuildConstants.protocolVersion.toInt(),
+ if (this.isPlayerAllowedToUseGimbal(player)) GimbalPolicyType.ALLOWED else GimbalPolicyType.DENIED
+ )
+ )
+ )
+ ServerPlayNetworking.send(player, PacketIDs.GIMBAL_POLICY_PACKET_ID, buf)
+ }
+
+ private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
+ val state = Cbor.decodeFromByteArray(buf.readByteArray())
+ ServerEditorManager.updateEditorState(player.uuid, state)
+// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
+ }
+
+ private fun isPlayerAllowedToUseGimbal(player: ServerPlayerEntity): Boolean {
+ return player.hasPermissionLevel(2) || Permissions.check(player, PermissionIDs.GIMBAL_USAGE_PERMISSION)
+ }
+}
diff --git a/src/main/java/net/moonleay/gimble/Main.kt b/src/main/java/net/moonleay/gimble/Main.kt
deleted file mode 100644
index 5cdb815..0000000
--- a/src/main/java/net/moonleay/gimble/Main.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.moonleay.gimble
-
-import net.moonleay.gimble.build.BuildConstants
-import net.fabricmc.api.ModInitializer
-import net.moonleay.gimble.networking.GimbleServer
-import org.apache.logging.log4j.LogManager
-
-internal object Main : ModInitializer {
- private val LOGGER = LogManager.getLogger(BuildConstants.modName)
-
- override fun onInitialize() {
- LOGGER.info("Initializing Gimble on the common side...")
- LOGGER.info("Registering packets...")
- GimbleServer.registerPacketHandler()
- LOGGER.info("Packets have been registered.")
- LOGGER.info("Gimble has been initialized on the common side.")
- LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/ClientMain.kt b/src/main/java/net/moonleay/gimble/client/ClientMain.kt
deleted file mode 100644
index c520c08..0000000
--- a/src/main/java/net/moonleay/gimble/client/ClientMain.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.moonleay.gimble.client
-
-import net.fabricmc.api.ClientModInitializer
-import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
-import net.moonleay.gimble.build.BuildConstants
-import net.moonleay.gimble.client.keybindings.KeybindingManager
-import net.moonleay.gimble.client.keybindings.KeybindingRegistrar
-import net.moonleay.gimble.networking.GimbleClient
-import org.apache.logging.log4j.LogManager
-
-internal object ClientMain : ClientModInitializer {
- private val LOGGER = LogManager.getLogger(BuildConstants.modName)
-
-
- override fun onInitializeClient() {
- LOGGER.info("Initializing Gimble on the client side...")
- KeybindingRegistrar.registerKeybindings()
- registerEvents()
- LOGGER.info("Registering packets...")
- GimbleClient.registerPacketHandlers()
- LOGGER.info("Packets have been registered.")
- LOGGER.info("Gimble has been initialized on the client side.")
- }
-
- private fun registerEvents() {
- LOGGER.info("Registering client events...")
- ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
- KeybindingManager.onClientTick(client)
- })
- LOGGER.info("Client events have been registered.")
- }
-
-}
diff --git a/src/main/java/net/moonleay/gimble/client/editor/ClientEditor.kt b/src/main/java/net/moonleay/gimble/client/editor/ClientEditor.kt
deleted file mode 100644
index 894ba28..0000000
--- a/src/main/java/net/moonleay/gimble/client/editor/ClientEditor.kt
+++ /dev/null
@@ -1,193 +0,0 @@
-package net.moonleay.gimble.client.editor
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.text.Text
-import net.moonleay.gimble.client.util.ChatUtil
-import net.moonleay.gimble.editor.ServerEditorManager
-import net.moonleay.gimble.editor.state.EditorState
-import net.moonleay.gimble.editor.state.GimblePolicyType
-import net.moonleay.gimble.editor.state.mode.Capability
-import net.moonleay.gimble.editor.state.mode.Mode
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-import net.moonleay.gimble.editor.util.EditorUtil
-import net.moonleay.gimble.editor.util.GimblePolicy
-import net.moonleay.gimble.networking.GimbleClient
-
-object ClientEditor {
- private var POLICY = GimblePolicyType.NOT_PRESENT
-
- private var CURRENT_MODE = Mode.NORMAL
- private var TEMP_DISABLED_MODE = Mode.UNKNOWN
-
- private val CURRENT_MODE_MODIFIER = mutableListOf()
- private val TEMP_DISABLED_MODIFIERS = mutableListOf()
-
- private val DISABLED_MODIFIERS_STORAGE = mutableListOf()
-
-
- fun onConnectedToNewWorld() {
- POLICY = GimblePolicyType.NOT_PRESENT
- GimbleClient.checkIfServerHasGimble(EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER))
- if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
- TEMP_DISABLED_MODE = CURRENT_MODE
- }
- CURRENT_MODE = Mode.INSERT
- DISABLED_MODIFIERS_STORAGE.addAll(CURRENT_MODE_MODIFIER)
- CURRENT_MODE_MODIFIER.clear()
- }
-
- fun onAllowedCheck(data: GimblePolicy) {
- POLICY = data.policy
- if (data.policy == GimblePolicyType.ALLOWED) {
- if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
- CURRENT_MODE = TEMP_DISABLED_MODE
- TEMP_DISABLED_MODE = Mode.UNKNOWN
- }
- CURRENT_MODE_MODIFIER.addAll(DISABLED_MODIFIERS_STORAGE)
- DISABLED_MODIFIERS_STORAGE.clear()
- this.onUpdated()
- }
- }
-
- fun isAllowed(): Boolean {
- return POLICY == GimblePolicyType.ALLOWED
- }
-
- fun shouldClient(capability: Capability): Boolean {
- return EditorUtil.shouldPlayer(capability, EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER))
- }
-
- fun isInNonDefaultMode(): Boolean {
- return CURRENT_MODE != Mode.NORMAL
- }
-
- /*
- * Send an updated player state to the server
- * */
- private fun updateServerState() {
- val state = EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
- GimbleClient.sendEditorState(state)
- ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
- }
-
-
- /*
- * Set the current mode
- * */
- fun setMode(mode: Mode) {
- if (!isAllowed()) {
- ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modes", MinecraftClient.getInstance())
- return
- }
- if (!MinecraftClient.getInstance().player!!.isCreative)
- return
- CURRENT_MODE = mode
-
- this.onUpdated()
- }
-
- /*
- * Toggle a mode modifier
- * */
- fun toggleModifier(mod: ModeModifier) {
- if (!isAllowed()) {
- ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modifiers", MinecraftClient.getInstance())
- return
- }
- if (!MinecraftClient.getInstance().player!!.isCreative)
- return
-
- if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
- if (TEMP_DISABLED_MODIFIERS.contains(mod))
- TEMP_DISABLED_MODIFIERS.remove(mod)
- else
- TEMP_DISABLED_MODIFIERS.add(mod)
- }
- else {
- if (CURRENT_MODE_MODIFIER.contains(mod))
- CURRENT_MODE_MODIFIER.remove(mod)
- else
- CURRENT_MODE_MODIFIER.add(mod)
- }
-
- this.onUpdated()
- }
-
- private fun onUpdated() {
- CURRENT_MODE_MODIFIER.sortBy {
- it.displayName
- }
- this.checkForIncompatibleModeModifiers()
- }
-
- /**
- * This runs on Mode updated
- */
- private fun checkForIncompatibleModeModifiers() {
- if (TEMP_DISABLED_MODIFIERS.size > 0) {
- CURRENT_MODE_MODIFIER.addAll(
- TEMP_DISABLED_MODIFIERS
- )
- TEMP_DISABLED_MODIFIERS.clear()
- }
-
- val incompatibleModeModifiers = CURRENT_MODE.incompatibleModifiers
- for (mod in CURRENT_MODE_MODIFIER) {
- if (incompatibleModeModifiers.contains(mod)) {
- TEMP_DISABLED_MODIFIERS.add(mod)
- }
- }
- for (mod in TEMP_DISABLED_MODIFIERS) {
- if (CURRENT_MODE_MODIFIER.contains(mod)) { // This check is probably useless.
- CURRENT_MODE_MODIFIER.remove(mod)
- }
- }
-
- CURRENT_MODE_MODIFIER.sortBy {
- it.displayName
- }
-
- // Update State
- this.updateServerState()
-
- if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
- ChatUtil.showToastToSelf("${CURRENT_MODE.displayName} Mode disabled", getListAsString(TEMP_DISABLED_MODIFIERS), MinecraftClient.getInstance())
- }
- }
-
- private fun getListAsString(list: List): String{
- if(list.isEmpty())
- return "Empty list"
- val sb = StringBuilder()
- for (mod in list) {
- sb.append(mod.displayName)
- sb.append(", ")
- }
- return sb.toString().dropLast(2)
- }
-
- /*
- * Get the display text to display in the HUD
- * */
- fun getModeDisplayText(): Text {
- val displayText = StringBuilder(CURRENT_MODE.displayName)
- if (CURRENT_MODE_MODIFIER.isNotEmpty() && this.isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) {
- displayText.append(" [")
- for (i in CURRENT_MODE_MODIFIER.indices) {
- displayText.append(CURRENT_MODE_MODIFIER[i].displayName)
- if (i != CURRENT_MODE_MODIFIER.size - 1) {
- displayText.append(", ")
- }
- }
- displayText.append("]")
- } else if (!this.isAllowed() || !MinecraftClient.getInstance().player?.isCreative!!) {
- displayText.clear()
- displayText.append("[GIMBLE DISABLED]")
- }
- return Text.of(displayText.toString())
- }
-
- fun getCurrentColor(): Int {
- return CURRENT_MODE.color
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/KeybindingManager.kt b/src/main/java/net/moonleay/gimble/client/keybindings/KeybindingManager.kt
deleted file mode 100644
index 5257977..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/KeybindingManager.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.moonleay.gimble.client.keybindings
-
-import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl
-import net.minecraft.client.MinecraftClient
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-
-object KeybindingManager {
-
- private val shortcuts = mutableListOf()
-
- /**
- * Register a shortcut. This will also register the keybinding.
- * */
- fun registerShortcut(shortcut: GimbleShortcut) {
- shortcuts.add(shortcut)
- KeyBindingRegistryImpl.registerKeyBinding(shortcut.keyBinding)
- }
-
- fun onClientTick(client: MinecraftClient){
- // Sadly, this cannot be done without iterating over all shortcuts :madge:
- for (shortcut in shortcuts)
- if (shortcut.keyBinding.wasPressed())
- shortcut.onPressed(client)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/GimbleShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/GimbleShortcut.kt
deleted file mode 100644
index fdaa1a3..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/GimbleShortcut.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-
-abstract class GimbleShortcut(val keyBinding: KeyBinding) {
-
- abstract fun onPressed(client: MinecraftClient)
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt
deleted file mode 100644
index a77abdf..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableInsertModeShortcut.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.Mode
-
-
-class EnableInsertModeShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.setMode(Mode.INSERT)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt
deleted file mode 100644
index dfa9316..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableReplaceModeShortcut.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.Mode
-
-
-class EnableReplaceModeShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.setMode(Mode.REPLACE)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt
deleted file mode 100644
index 36711aa..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormode/EnableVisualModeShortcut.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.Mode
-
-
-class EnableVisualModeShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.setMode(Mode.VISUAL)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt
deleted file mode 100644
index 3fd31be..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleBulldozerModifierShortcut.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-
-class ToggleBulldozerModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.toggleModifier(ModeModifier.BULLDOZER)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt
deleted file mode 100644
index eae4119..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleForcePlaceModifierShortcut.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-
-class ToggleForcePlaceModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.toggleModifier(ModeModifier.FORCE_PLACE)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt
deleted file mode 100644
index 40a0940..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoClipModifierShortcut.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-
-class ToggleNoClipModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.toggleModifier(ModeModifier.NO_CLIP)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt
deleted file mode 100644
index 5380fdf..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/editormodemodifier/ToggleNoUpdatesModifierShortcut.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-
-class ToggleNoUpdatesModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ClientEditor.toggleModifier(ModeModifier.NO_UPDATES)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/CreativeModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/CreativeModeShortcut.kt
deleted file mode 100644
index 57008a4..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/CreativeModeShortcut.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.gamemode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.client.util.ChatUtil
-
-class CreativeModeShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ChatUtil.sendCommand("/gamemode creative", client, false)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt
deleted file mode 100644
index 346e783..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SpectatorModeShortcut.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.gamemode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.client.util.ChatUtil
-
-class SpectatorModeShortcut(key: KeyBinding): GimbleShortcut(key) {
- override fun onPressed(client: MinecraftClient) {
- ChatUtil.sendCommand("/gamemode spectator", client, false)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt b/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt
deleted file mode 100644
index 387ea8d..0000000
--- a/src/main/java/net/moonleay/gimble/client/keybindings/impl/gamemode/SurvivalModeShortcut.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.moonleay.gimble.client.keybindings.impl.gamemode
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.option.KeyBinding
-import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
-import net.moonleay.gimble.client.util.ChatUtil
-
-
-class SurvivalModeShortcut(key: KeyBinding) : GimbleShortcut(key) {
-
- override fun onPressed(client: MinecraftClient) {
- ChatUtil.sendCommand("/gamemode survival", client, false)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/client/util/ChatUtil.kt b/src/main/java/net/moonleay/gimble/client/util/ChatUtil.kt
deleted file mode 100644
index cc30396..0000000
--- a/src/main/java/net/moonleay/gimble/client/util/ChatUtil.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.moonleay.gimble.client.util
-
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.toast.SystemToast
-import net.minecraft.text.Text
-
-object ChatUtil {
- /**
- * Note: command arg should contain "/" at the beginning.
- * */
- fun sendCommand(command: String, client: MinecraftClient, addToHistory: Boolean = true): Boolean {
- if (addToHistory) {
- client.inGameHud.chatHud.addToMessageHistory(command)
- }
- return client.player?.sendCommand(command.substring(1))?: false
- }
-
- fun addToChatHistory(message: String, client: MinecraftClient) {
- client.inGameHud.chatHud.addMessage(Text.of(message))
- }
-
- fun showToastToSelf(title: String, description: String, client: MinecraftClient) {
- val toast = SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.of(title), Text.of(description))
- client.toastManager.add(toast)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/datagen/DataGenerator.kt b/src/main/java/net/moonleay/gimble/datagen/DataGenerator.kt
deleted file mode 100644
index a2267c8..0000000
--- a/src/main/java/net/moonleay/gimble/datagen/DataGenerator.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.moonleay.gimble.datagen
-
-import net.moonleay.gimble.build.BuildConstants
-import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint
-import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
-import org.apache.logging.log4j.LogManager
-
-internal class DataGenerator : DataGeneratorEntrypoint {
- private val LOGGER = LogManager.getLogger(BuildConstants.modName)
-
- override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
- LOGGER.info("Starting Data Generation")
- fabricDataGenerator.addProvider(En_us_GimbleLanguageProvider(fabricDataGenerator))
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/datagen/En_us_GimbleLanguageProvider.kt b/src/main/java/net/moonleay/gimble/datagen/En_us_GimbleLanguageProvider.kt
deleted file mode 100644
index cca1464..0000000
--- a/src/main/java/net/moonleay/gimble/datagen/En_us_GimbleLanguageProvider.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.moonleay.gimble.datagen
-
-import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
-import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
-
-class En_us_GimbleLanguageProvider(dataGenerator: FabricDataGenerator?) :
- FabricLanguageProvider(dataGenerator, "en_us") {
-
- override fun generateTranslations(translationBuilder: TranslationBuilder?) {
- if (translationBuilder == null) return
- // Editor modes
- translationBuilder.add("gimble.category.editormode", "Editor Modes")
- translationBuilder.add("gimble.key.editor.mode.insert", "Enter Insert Mode")
- translationBuilder.add("gimble.key.editor.mode.replace", "Enter Replace Mode")
- translationBuilder.add("gimble.key.editor.mode.visual", "Enter Visual Mode")
-
-
- // Editor mode modifiers
- translationBuilder.add("gimble.category.editormodifier", "Editor Mode Modifiers")
- translationBuilder.add("gimble.key.editor.modifier.bulldozer", "Toggle Bulldozer Modifier")
- translationBuilder.add("gimble.key.editor.modifier.forceplace", "Toggle Force Place Modifier")
- translationBuilder.add("gimble.key.editor.modifier.noupdates", "Toggle No Updates Modifier")
- translationBuilder.add("gimble.key.editor.modifier.noclip", "Toggle No Clip Modifier")
-
- // Game mode
- translationBuilder.add("gimble.category.gamemode", "Game Mode")
- translationBuilder.add("gimble.key.game.mode.survival", "Enable Survival Mode")
- translationBuilder.add("gimble.key.game.mode.creative", "Enable Creative Mode")
- translationBuilder.add("gimble.key.game.mode.spectator", "Enable Spectator Mode")
-
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/ServerEditorManager.kt b/src/main/java/net/moonleay/gimble/editor/ServerEditorManager.kt
deleted file mode 100644
index 25a3513..0000000
--- a/src/main/java/net/moonleay/gimble/editor/ServerEditorManager.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.moonleay.gimble.editor
-
-import net.moonleay.gimble.build.BuildConstants
-import net.moonleay.gimble.editor.state.EditorState
-import net.moonleay.gimble.editor.state.mode.Capability
-import net.moonleay.gimble.editor.util.EditorUtil
-import org.apache.logging.log4j.LogManager
-import java.util.*
-
-object ServerEditorManager {
- private val LOGGER = LogManager.getLogger(BuildConstants.modName)
-
- private val STATEMAP = mutableMapOf()
-
- fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
- STATEMAP[playerUUID] = editorState
- LOGGER.info("$playerUUID: ${editorState.editorMode} with ${editorState.editorModifier}")
- }
-
-
- /*
- * Check if a player should be able to perform an action
- * */
- fun shouldPlayer(playerUUID: UUID, capability: Capability): Boolean {
- if (!STATEMAP.containsKey(playerUUID))
- return false
- val state = STATEMAP[playerUUID]!!
- return EditorUtil.shouldPlayer(capability, state)
- }
-
-
-// fun playerHasModifier(playerUUID: UUID, modifier: ModeModifier): Boolean {
-// if (!STATEMAP.containsKey(playerUUID))
-// return false
-// return STATEMAP[playerUUID]!!.editorModifier.contains(modifier) ?: false
-// }
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/state/EditorState.kt b/src/main/java/net/moonleay/gimble/editor/state/EditorState.kt
deleted file mode 100644
index 57e0d5f..0000000
--- a/src/main/java/net/moonleay/gimble/editor/state/EditorState.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.moonleay.gimble.editor.state
-
-import kotlinx.serialization.Serializable
-import net.moonleay.gimble.editor.state.mode.Mode
-import net.moonleay.gimble.editor.state.mode.ModeModifier
-
-@Serializable
-data class EditorState(
- var editorMode: Mode,
- var editorModifier: MutableList,
-)
diff --git a/src/main/java/net/moonleay/gimble/editor/state/GimblePolicyType.kt b/src/main/java/net/moonleay/gimble/editor/state/GimblePolicyType.kt
deleted file mode 100644
index 52cda45..0000000
--- a/src/main/java/net/moonleay/gimble/editor/state/GimblePolicyType.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.moonleay.gimble.editor.state
-
-enum class GimblePolicyType {
- ALLOWED,
- DENIED,
- NOT_PRESENT
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/state/mode/Capability.kt b/src/main/java/net/moonleay/gimble/editor/state/mode/Capability.kt
deleted file mode 100644
index 14dd079..0000000
--- a/src/main/java/net/moonleay/gimble/editor/state/mode/Capability.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.moonleay.gimble.editor.state.mode
-
-enum class Capability {
- INSERT,
- REPLACE,
- CAN_INTERACT,
- NO_CLIP,
- FORCE_PLACE,
- NO_UPDATES,
- BULLDOZER,
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/state/mode/Mode.kt b/src/main/java/net/moonleay/gimble/editor/state/mode/Mode.kt
deleted file mode 100644
index 95d7961..0000000
--- a/src/main/java/net/moonleay/gimble/editor/state/mode/Mode.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.moonleay.gimble.editor.state.mode
-
-enum class Mode(val displayName: String, val color: Int, val incompatibleModifiers: List){
- UNKNOWN("UNKNOWN", 0x000000, listOf()), // Unknown mode. This mode cannot be entered
- NORMAL("NORMAL", 0x90a959, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
- INSERT("INSERT", 0xf4bf75, listOf()), // Place and break blocks
- REPLACE("REPLACE", 0xac4242, listOf()), // Replace blocks
- VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/state/mode/ModeModifier.kt b/src/main/java/net/moonleay/gimble/editor/state/mode/ModeModifier.kt
deleted file mode 100644
index f7bc6bb..0000000
--- a/src/main/java/net/moonleay/gimble/editor/state/mode/ModeModifier.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.moonleay.gimble.editor.state.mode
-
-enum class ModeModifier(val displayName: String) {
-// NONE("None"), // No Modifiers - default behavior
- NO_UPDATES("NO UPDATES"), // Do not update blocks when placing
- BULLDOZER("BULLDOZER"), // Break blocks fast
- FORCE_PLACE("FORCE"), // Ignore block placement restrictions
- NO_CLIP("NO CLIP"), // Do not collide with blocks
-}
diff --git a/src/main/java/net/moonleay/gimble/editor/util/GimblePolicy.kt b/src/main/java/net/moonleay/gimble/editor/util/GimblePolicy.kt
deleted file mode 100644
index 620e682..0000000
--- a/src/main/java/net/moonleay/gimble/editor/util/GimblePolicy.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.moonleay.gimble.editor.util
-
-import kotlinx.serialization.Serializable
-import net.moonleay.gimble.editor.state.GimblePolicyType
-
-@Serializable
-data class GimblePolicy(
- val policy: GimblePolicyType,
-)
diff --git a/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin.java b/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin.java
deleted file mode 100644
index 1134cd5..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.network.ClientPlayerEntity;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import org.jetbrains.annotations.Nullable;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-
-import java.util.Objects;
-
-@Mixin(MinecraftClient.class)
-public abstract class BulldozerMixin {
-
- @Shadow protected int attackCooldown;
-
- @Shadow
- @Nullable
- public ClientPlayerEntity player;
-
- @Inject(method = "doAttack", at = @At(value = "HEAD"))
- private void func(CallbackInfoReturnable cir) {
- if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
- return;
- }
- this.attackCooldown = 0;
- }
-
- @Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
- private void func2(boolean breaking, CallbackInfo ci) {
- if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
- return;
- }
- this.attackCooldown = 0;
- }
-
-
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin2.java b/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin2.java
deleted file mode 100644
index ae8d081..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/BulldozerMixin2.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.network.ClientPlayerInteractionManager;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.Direction;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-
-import java.util.Objects;
-
-@Mixin(ClientPlayerInteractionManager.class)
-public class BulldozerMixin2 {
-
- @Shadow private int blockBreakingCooldown;
-
- @Shadow
- @Final
- private MinecraftClient client;
-
- @Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
- private void func(BlockPos pos, Direction direction, CallbackInfoReturnable cir) {
- if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
- return;
- }
- this.blockBreakingCooldown = 0;
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/GimblePolicyCheckMixin.java b/src/main/java/net/moonleay/gimble/mixin/GimblePolicyCheckMixin.java
deleted file mode 100644
index 951c4aa..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/GimblePolicyCheckMixin.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(DownloadingTerrainScreen.class)
-public class GimblePolicyCheckMixin {
-
-
- @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/DownloadingTerrainScreen;close()V", ordinal = -1))
- private void func(CallbackInfo ci) {
- ClientEditor.INSTANCE.onConnectedToNewWorld();
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/HudMixin.java b/src/main/java/net/moonleay/gimble/mixin/HudMixin.java
deleted file mode 100644
index dd16008..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/HudMixin.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
-import net.minecraft.client.gui.hud.InGameHud;
-import net.minecraft.client.util.math.MatrixStack;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(InGameHud.class)
-public class HudMixin {
-
- @Shadow @Final private MinecraftClient client;
-
- @Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
- private void render(MatrixStack matrices, CallbackInfo ci) {
- TextRenderer tr = this.client.textRenderer;
- tr.drawWithShadow(matrices,
- ClientEditor.INSTANCE.getModeDisplayText(),
- 4, 4,
- ClientEditor.INSTANCE.getCurrentColor());
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/NoClipCameraFixMixin.java b/src/main/java/net/moonleay/gimble/mixin/NoClipCameraFixMixin.java
deleted file mode 100644
index 0874f9a..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/NoClipCameraFixMixin.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.render.Camera;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-
-@Mixin(Camera.class)
-public class NoClipCameraFixMixin {
-
- @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
- private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable cir) {
- if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
- return;
- }
- cir.setReturnValue(desiredCameraDistance);
- cir.cancel();
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/NoClipMixin.java b/src/main/java/net/moonleay/gimble/mixin/NoClipMixin.java
deleted file mode 100644
index f66885d..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/NoClipMixin.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import com.mojang.authlib.GameProfile;
-import net.minecraft.entity.EntityPose;
-import net.minecraft.entity.EntityType;
-import net.minecraft.entity.LivingEntity;
-import net.minecraft.entity.player.PlayerAbilities;
-import net.minecraft.entity.player.PlayerEntity;
-import net.minecraft.world.World;
-import net.moonleay.gimble.editor.ServerEditorManager;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import java.util.UUID;
-
-@Mixin(PlayerEntity.class)
-public abstract class NoClipMixin extends LivingEntity {
- @Shadow public abstract GameProfile getGameProfile();
-
- @Shadow public abstract PlayerAbilities getAbilities();
-
- @Shadow
- public abstract boolean isCreative();
-
- protected NoClipMixin(EntityType extends LivingEntity> entityType, World world) {
- super(entityType, world);
- } // Server side
-
-
- @Inject(method = "tick", at = @At(value = "FIELD",
- target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER)
- ) private void enoClip(CallbackInfo ci) {
- if (!this.isCreative())
- return;
- UUID uuid = this.getGameProfile().getId();
-
- if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) {
- return; // NoClip is not enabled
- }
- if (!this.getAbilities().flying) {
- return;
- }
- // Enable NoClip
- this.noClip = true;
- }
-
- @Inject(method = "updatePose", at = @At("HEAD"))
- private void onUpdatePose(CallbackInfo ci) {
- UUID uuid = this.getGameProfile().getId();
-
- if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
- return; // NoClip is not enabled
- if (!this.getAbilities().flying)
- return;
-
- // Force standing pose in NoClip mode
-
- this.setPose(EntityPose.STANDING);
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/mixin/ReplaceModeMixin.java b/src/main/java/net/moonleay/gimble/mixin/ReplaceModeMixin.java
deleted file mode 100644
index cfaed01..0000000
--- a/src/main/java/net/moonleay/gimble/mixin/ReplaceModeMixin.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package net.moonleay.gimble.mixin;
-
-import net.minecraft.block.BlockState;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.network.ClientPlayerEntity;
-import net.minecraft.client.network.ClientPlayerInteractionManager;
-import net.minecraft.client.particle.ParticleManager;
-import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
-import net.minecraft.util.Hand;
-import net.minecraft.util.hit.BlockHitResult;
-import net.minecraft.util.hit.HitResult;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.Direction;
-import net.moonleay.gimble.client.editor.ClientEditor;
-import net.moonleay.gimble.editor.state.mode.Capability;
-import org.jetbrains.annotations.Nullable;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(MinecraftClient.class)
-public abstract class ReplaceModeMixin {
-
-
- @Shadow protected abstract void handleBlockBreaking(boolean breaking);
-
- @Shadow @Nullable public ClientPlayerInteractionManager interactionManager;
-
- @Shadow @Final public ParticleManager particleManager;
-
- @Shadow @Nullable public ClientPlayerEntity player;
-
- @Shadow @Nullable public HitResult crosshairTarget;
-
- @Inject(method = "doItemUse", at = @At("HEAD"))
- private void replaceBlock(CallbackInfo ci) {
- assert this.player != null;
- if (!this.player.isCreative())
- return;
- // Check if should run
- if (!ClientEditor.INSTANCE.shouldClient(Capability.REPLACE))
- return; // Mode is not REPLACE, ignore
- MinecraftClient client = MinecraftClient.getInstance();
- assert this.interactionManager != null;
- if (!this.interactionManager.getCurrentGameMode().isCreative())
- return;
- if (!(this.crosshairTarget instanceof BlockHitResult blockHitResult))
- return;
- if (blockHitResult == null)
- return;
-
- // Gather data
- BlockPos pos = blockHitResult.getBlockPos();
- Direction direction = blockHitResult.getSide();
- BlockState blockState = client.world.getBlockState(pos);
-
- // Start sending shit
- client.getTutorialManager().onBlockBreaking(client.world, pos, blockState, 1.0F);
- this.interactionManager.sendSequencedPacket(client.world, sequence -> {
- this.interactionManager.breakBlock(pos);
- return new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, direction, sequence);
- });
- this.player.swingHand(Hand.MAIN_HAND);
- }
-
-}
diff --git a/src/main/java/net/moonleay/gimble/networking/GimbleClient.kt b/src/main/java/net/moonleay/gimble/networking/GimbleClient.kt
deleted file mode 100644
index 718c7c8..0000000
--- a/src/main/java/net/moonleay/gimble/networking/GimbleClient.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.moonleay.gimble.networking
-
-import kotlinx.serialization.ExperimentalSerializationApi
-import kotlinx.serialization.cbor.Cbor
-import kotlinx.serialization.decodeFromByteArray
-import kotlinx.serialization.encodeToByteArray
-import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
-import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
-import net.minecraft.network.PacketByteBuf
-import net.moonleay.gimble.client.editor.ClientEditor
-import net.moonleay.gimble.editor.state.EditorState
-import net.moonleay.gimble.editor.util.GimblePolicy
-
-object GimbleClient {
-
- fun registerPacketHandlers() {
- ClientPlayNetworking.registerGlobalReceiver(PacketIDs.TRANSFER_GIMBLE_POLICY_ID) { _, _, buf, _ ->
- onAllowedCheck(buf)
- }
- }
-
- private fun onAllowedCheck(buf: PacketByteBuf) {
- val policy = Cbor.decodeFromByteArray(buf.readByteArray())
- ClientEditor.onAllowedCheck(policy) // Update the client's policy
- }
-
- /**
- * Sends the given [EditorState] to the server.
- */
- @OptIn(ExperimentalSerializationApi::class)
- fun sendEditorState(state: EditorState) {
- val buf = PacketByteBufs.create()
- buf.writeByteArray(Cbor.encodeToByteArray(state))
- ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, buf)
- }
-
- fun checkIfServerHasGimble(state: EditorState) {
- val buf = PacketByteBufs.create()
- buf.writeByteArray(Cbor.encodeToByteArray(state))
- ClientPlayNetworking.send(PacketIDs.GIMBLE_PRERENCE_CHECK_ID, buf)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/networking/GimbleServer.kt b/src/main/java/net/moonleay/gimble/networking/GimbleServer.kt
deleted file mode 100644
index 8b182b5..0000000
--- a/src/main/java/net/moonleay/gimble/networking/GimbleServer.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.moonleay.gimble.networking
-
-import kotlinx.serialization.cbor.Cbor
-import kotlinx.serialization.decodeFromByteArray
-import kotlinx.serialization.encodeToByteArray
-import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
-import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
-import net.minecraft.network.PacketByteBuf
-import net.minecraft.server.network.ServerPlayerEntity
-import net.moonleay.gimble.editor.ServerEditorManager
-import net.moonleay.gimble.editor.state.EditorState
-import net.moonleay.gimble.editor.state.GimblePolicyType
-import net.moonleay.gimble.editor.util.GimblePolicy
-
-object GimbleServer {
-
- fun registerPacketHandler() {
- ServerPlayNetworking
- .registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
- { server, player, handler, buf, responseSender ->
- handleStateUpdate(player, buf)
- }
- ServerPlayNetworking
- .registerGlobalReceiver(PacketIDs.GIMBLE_PRERENCE_CHECK_ID)
- { server, player, handler, buf, responseSender ->
- handlePresenceCheck(player, buf)
- }
- }
-
- private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
- val state = Cbor.decodeFromByteArray(buf.readByteArray())
- ServerEditorManager.updateEditorState(player.uuid, state)
-// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
- }
-
- private fun handlePresenceCheck(player: ServerPlayerEntity, buf: PacketByteBuf) {
- val state = Cbor.decodeFromByteArray(buf.readByteArray())
- ServerEditorManager.updateEditorState(player.uuid, state)
-
- val buffer = PacketByteBufs.create()
- buffer.writeByteArray(Cbor.encodeToByteArray(GimblePolicy(GimblePolicyType.ALLOWED)))
- ServerPlayNetworking.send(player, PacketIDs.TRANSFER_GIMBLE_POLICY_ID, buffer)
- }
-}
diff --git a/src/main/java/net/moonleay/gimble/networking/PacketIDs.kt b/src/main/java/net/moonleay/gimble/networking/PacketIDs.kt
deleted file mode 100644
index 4587ff8..0000000
--- a/src/main/java/net/moonleay/gimble/networking/PacketIDs.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.moonleay.gimble.networking
-
-import net.minecraft.util.Identifier
-import net.moonleay.gimble.build.BuildConstants
-
-object PacketIDs {
- val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
- val GIMBLE_PRERENCE_CHECK_ID = Identifier(BuildConstants.modId, "gimble_preference_check")
- val TRANSFER_GIMBLE_POLICY_ID = Identifier(BuildConstants.modId, "gimble_is_present")
-
-}
diff --git a/src/main/resources/assets/gimbal/logo.png b/src/main/resources/assets/gimbal/logo.png
new file mode 100644
index 0000000..07dbd45
Binary files /dev/null and b/src/main/resources/assets/gimbal/logo.png differ
diff --git a/src/main/resources/assets/gimbal/textures/gimbal_options_texture_button.png b/src/main/resources/assets/gimbal/textures/gimbal_options_texture_button.png
new file mode 100644
index 0000000..e11bf08
Binary files /dev/null and b/src/main/resources/assets/gimbal/textures/gimbal_options_texture_button.png differ
diff --git a/src/main/resources/assets/gimble/logo.png b/src/main/resources/assets/gimble/logo.png
deleted file mode 100644
index ab1e23e..0000000
Binary files a/src/main/resources/assets/gimble/logo.png and /dev/null differ
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index f653362..0f9c789 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -3,16 +3,19 @@
"id": "${modId}",
"version": "${modVersion}",
"name": "${modName}",
- "description": "An open source building assist mod featuring vim-like modes and modifiers.",
+ "description": "An open source building assist mod featuring Vim-like modes and modifiers.",
"authors": [
"moonleay"
],
+ "contributors": [
+ "Cookieso"
+ ],
"icon": "assets/${modId}/logo.png",
"contact": {
"email": "contact@moonleay.net",
"homepage": "https://moonleay.net",
- "sources": "https://codeberg.org/moonleay/Gimble",
- "issues": "https://codeberg.org/moonleay/Gimble/issues"
+ "sources": "https://codeberg.org/moonleay/Gimbal",
+ "issues": "https://codeberg.org/moonleay/Gimbal/issues"
},
"license": "GPL-3.0",
"environment": "*",
@@ -20,19 +23,19 @@
"client": [
{
"adapter": "kotlin",
- "value": "net.moonleay.gimble.client.ClientMain"
+ "value": "net.moonleay.gimbal.client.ClientMain"
}
],
"main": [
{
"adapter": "kotlin",
- "value": "net.moonleay.gimble.Main"
+ "value": "net.moonleay.gimbal.Main"
}
],
"fabric-datagen": [
{
"adapter": "kotlin",
- "value": "net.moonleay.gimble.datagen.DataGenerator"
+ "value": "net.moonleay.gimbal.datagen.DataGenerator"
}
]
},
diff --git a/src/main/resources/gimble.accesswidener b/src/main/resources/gimbal.accesswidener
similarity index 81%
rename from src/main/resources/gimble.accesswidener
rename to src/main/resources/gimbal.accesswidener
index e659ad2..ee44473 100644
--- a/src/main/resources/gimble.accesswidener
+++ b/src/main/resources/gimbal.accesswidener
@@ -2,3 +2,4 @@ accessWidener v2 named
accessible method net/minecraft/client/MinecraftClient handleBlockBreaking (Z)V
accessible method net/minecraft/client/network/ClientPlayerInteractionManager sendSequencedPacket (Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/client/network/SequencedPacketCreator;)V
+accessible field net/minecraft/state/State owner Ljava/lang/Object;
diff --git a/src/main/resources/gimbal.mixins.json b/src/main/resources/gimbal.mixins.json
new file mode 100644
index 0000000..9de8288
--- /dev/null
+++ b/src/main/resources/gimbal.mixins.json
@@ -0,0 +1,26 @@
+{
+ "required": true,
+ "minVersion": "0.8",
+ "package": "net.moonleay.gimbal.mixin",
+ "compatibilityLevel": "JAVA_17",
+ "mixins": [
+ "ForcePlaceMixin",
+ "NoBlockUpdatesMixin",
+ "NoClipMixin$PlayerEntityMixin",
+ "ReplaceModeMixin$BlockItemMixin",
+ "ReplaceModeMixin$ItemPlacementContextMixin"
+ ],
+ "client": [
+ "BulldozerMixin$ClientPlayerInteractionManagerMixin",
+ "BulldozerMixin$MinecraftClientMixin",
+ "HudMixin",
+ "NoClipMixin$CameraMixin",
+ "NormalModeMixin",
+ "PlayerFlySpeedMixin",
+ "YouInjectButtonMixin$GameMenuScreenMixin",
+ "YouInjectButtonMixin$TitleScreenMixin"
+ ],
+ "injectors": {
+ "defaultRequire": 1
+ }
+}
diff --git a/src/main/resources/gimble.mixins.json b/src/main/resources/gimble.mixins.json
deleted file mode 100644
index 9ec9090..0000000
--- a/src/main/resources/gimble.mixins.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "required": true,
- "minVersion": "0.8",
- "package": "net.moonleay.gimble.mixin",
- "compatibilityLevel": "JAVA_17",
- "mixins": [
- "ForcePlaceMixin",
- "NoBlockUpdatesMixin",
- "NoClipMixin"
- ],
- "client": [
- "BulldozerMixin",
- "BulldozerMixin2",
- "GimblePolicyCheckMixin",
- "HudMixin",
- "NoClipCameraFixMixin",
- "NormalModeMixin",
- "ReplaceModeMixin"
- ],
- "injectors": {
- "defaultRequire": 1
- }
-}
diff --git a/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt b/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt
new file mode 100644
index 0000000..d90f0ff
--- /dev/null
+++ b/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt
@@ -0,0 +1,27 @@
+/*
+ * Gimbal
+ * Copyright (C) 2024 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.gimbal.build
+
+internal object BuildConstants {
+ const val modId = "${modId}"
+ const val modName = "${modName}"
+ const val modVersion = "${modVersion}"
+ const val protocolVersion = "${protocolVersion}"
+}
+
diff --git a/src/main/templates/net/moonleay/gimble/build/BuildConstants.kt b/src/main/templates/net/moonleay/gimble/build/BuildConstants.kt
deleted file mode 100644
index 85b65ee..0000000
--- a/src/main/templates/net/moonleay/gimble/build/BuildConstants.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.moonleay.gimble.build
-
-internal object BuildConstants {
- const val modId = "${modId}"
- const val modName = "${modName}"
- const val modVersion = "${modVersion}"
-}