Compare commits

..

No commits in common. "master" and "0.1.1" have entirely different histories.

51 changed files with 361 additions and 1933 deletions

View file

@ -1,42 +0,0 @@
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 }}

View file

@ -1,54 +0,0 @@
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 }}

View file

@ -27,23 +27,13 @@ plugins {
`maven-publish` `maven-publish`
eclipse eclipse
id("org.jetbrains.gradle.plugin.idea-ext") id("org.jetbrains.gradle.plugin.idea-ext")
id("com.modrinth.minotaur") version "2.+"
} }
val ver = if ((System.getenv("GITHUB_REF") ?: "local").startsWith("refs/tags/")) val mavenVersion = System.getenv("CI_COMMIT_TAG") ?: System.getenv("CI_COMMIT_SHORT_SHA")?.let { "$it-dev" }
System.getenv("GITHUB_REF_NAME") ?: "err" else System.getenv("GIT_SHA_SHORT") ?: "0.0.0" ?: "0.1.1-dev" //""0.0.0-SNAPSHOT"
val mavenVersion = ver
val modId: String by project val modId: String by project
val modName: String by project val modName: String by project
/*
* Gimbal version stuff
* */
val gimbalProtocolVersion = 3
val mavenGroup: String by project val mavenGroup: String by project
val mavenArtifact: String by project val mavenArtifact: String by project
@ -60,9 +50,6 @@ group = mavenGroup
project.base.archivesName.set(mavenArtifact) project.base.archivesName.set(mavenArtifact)
repositories { repositories {
maven { // Dependency api
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
} }
fabricApi { fabricApi {
@ -79,10 +66,6 @@ dependencies {
modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion") modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion")
modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
modApi("me.lucko:fabric-permissions-api:0.2-SNAPSHOT")
{
exclude(group = "net.fabricmc")
}
} }
val targetJavaVersion = 17 val targetJavaVersion = 17
@ -93,7 +76,6 @@ val templateProps = mapOf(
"modVersion" to project.version as String, "modVersion" to project.version as String,
"modId" to modId, "modId" to modId,
"modName" to modName, "modName" to modName,
"protocolVersion" to gimbalProtocolVersion,
"minecraftVersion" to minecraftVersion, "minecraftVersion" to minecraftVersion,
"fabricLoaderVersion" to fabricLoaderVersion, "fabricLoaderVersion" to fabricLoaderVersion,
"fabricKotlinVersion" to fabricKotlinVersion, "fabricKotlinVersion" to fabricKotlinVersion,
@ -187,18 +169,17 @@ publishing {
} }
repositories { repositories {
if (System.getenv("CI") != null) { if (System.getenv("CI_JOB_TOKEN") != null) {
maven { maven {
name = "Codeberg" name = "GitLab"
val repoOwner = System.getenv("GITHUB_REPOSITORY_OWNER") val projectId = System.getenv("CI_PROJECT_ID")
val serverUrl = System.getenv("GITHUB_SERVER_URL") val apiV4 = System.getenv("CI_API_V4_URL")
val accessToken = System.getenv("PACKAGE_REPO_KEY") url = uri("$apiV4/projects/$projectId/packages/maven")
url = uri("$serverUrl/api/packages/$repoOwner/maven")
authentication { authentication {
create("header", HttpHeaderAuthentication::class.java) { create("token", HttpHeaderAuthentication::class.java) {
credentials(HttpHeaderCredentials::class) { credentials(HttpHeaderCredentials::class.java) {
name = "Authorization" name = "Job-Token"
value = "token $accessToken" value = System.getenv("CI_JOB_TOKEN")
} }
} }
} }
@ -207,33 +188,6 @@ 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 { rootProject.idea.project {
this as ExtensionAware this as ExtensionAware
configure<ProjectSettings> { configure<ProjectSettings> {

View file

@ -18,7 +18,7 @@
#Generated by fabric-mod-template #Generated by fabric-mod-template
#Sun Apr 21 19:29:15 CEST 2024 #Sun Apr 21 19:29:15 CEST 2024
fabric.loom.version=1.6-SNAPSHOT fabric.loom.version=1.4.6
kotlin.version=1.9.22 kotlin.version=1.9.22
fabric.api.version=0.77.0+1.19.2 fabric.api.version=0.77.0+1.19.2
yarn.version=1.19.2+build.28 yarn.version=1.19.2+build.28

View file

@ -18,7 +18,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View file

@ -19,7 +19,6 @@
package net.moonleay.gimbal package net.moonleay.gimbal
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.networking.GimbalServer import net.moonleay.gimbal.networking.GimbalServer
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
@ -32,11 +31,6 @@ internal object Main : ModInitializer {
LOGGER.info("Registering packets...") LOGGER.info("Registering packets...")
GimbalServer.registerPacketHandler() GimbalServer.registerPacketHandler()
LOGGER.info("Packets have been registered.") 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("Gimbal has been initialized on the common side.")
LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay") LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
} }

View file

@ -20,11 +20,7 @@ package net.moonleay.gimbal.client
import net.fabricmc.api.ClientModInitializer import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents 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.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.KeybindingManager
import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar
import net.moonleay.gimbal.networking.GimbalClient import net.moonleay.gimbal.networking.GimbalClient
@ -32,23 +28,15 @@ import org.apache.logging.log4j.LogManager
internal object ClientMain : ClientModInitializer { internal object ClientMain : ClientModInitializer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName) private val LOGGER = LogManager.getLogger(BuildConstants.modName)
lateinit var CONFIG: ClientConfigHolder
override fun onInitializeClient() { override fun onInitializeClient() {
LOGGER.info("Initializing Gimbal on the client side...") LOGGER.info("Initializing Gimbal on the client side...")
KeybindingRegistrar.registerKeybindings() KeybindingRegistrar.registerKeybindings()
this.registerEvents() registerEvents()
LOGGER.info("Registering packets...") LOGGER.info("Registering packets...")
GimbalClient.registerPacketHandlers() GimbalClient.registerPacketHandlers()
LOGGER.info("Packets have been registered.") 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.") LOGGER.info("Gimbal has been initialized on the client side.")
} }
@ -57,10 +45,6 @@ internal object ClientMain : ClientModInitializer {
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client -> ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
KeybindingManager.onClientTick(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.") LOGGER.info("Client events have been registered.")
} }

View file

@ -1,79 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<GimbalClientConfig>(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<GimbalClientConfig>(conf, it)
}
oStream.close()
}
}

View file

@ -1,32 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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
)

View file

@ -1,33 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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,
)

View file

@ -1,27 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.config
import kotlinx.serialization.Serializable
@Serializable
data class ScaledRes(
val scaledX: Double, // offsetX
val scaledY: Double, // offsetY
)

View file

@ -1,27 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.config.enums
enum class Centerpoint {
TOP_LEFT,
TOP_RIGHT,
BOTTOM_RIGHT,
BOTTOM_LEFT,
CENTER
}

View file

@ -1,31 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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)),
}

View file

@ -1,32 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<ToastType>) {
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())
}

View file

@ -1,28 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.config.enums
import kotlinx.serialization.Serializable
@Serializable
enum class VerticalAnchor {
TOP,
CENTER,
BOTTOM,
}

View file

@ -20,48 +20,37 @@ package net.moonleay.gimbal.client.editor
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.text.Text 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.ChatUtil
import net.moonleay.gimbal.client.util.ToastType
import net.moonleay.gimbal.editor.ServerEditorManager import net.moonleay.gimbal.editor.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType 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.Capability
import net.moonleay.gimbal.editor.state.mode.Mode import net.moonleay.gimbal.editor.state.mode.Mode
import net.moonleay.gimbal.editor.state.mode.ModeModifier import net.moonleay.gimbal.editor.state.mode.ModeModifier
import net.moonleay.gimbal.editor.util.EditorUtil import net.moonleay.gimbal.editor.util.EditorUtil
import net.moonleay.gimbal.editor.util.GimbalPolicy
import net.moonleay.gimbal.networking.GimbalClient import net.moonleay.gimbal.networking.GimbalClient
import org.apache.logging.log4j.LogManager
object ClientEditor { object ClientEditor {
private var POLICY = GimbalPolicyType.NOT_PRESENT private var POLICY = GimbalPolicyType.NOT_PRESENT
private lateinit var CURRENT_MODE: Mode private var CURRENT_MODE = Mode.NORMAL
private var TEMP_DISABLED_MODE = Mode.UNKNOWN private var TEMP_DISABLED_MODE = Mode.UNKNOWN
private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>() private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>() private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>()
private val DISABLED_MODIFIERS_STORAGE = mutableListOf<ModeModifier>() private val DISABLED_MODIFIERS_STORAGE = mutableListOf<ModeModifier>()
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() { fun onConnectedToNewWorld() {
POLICY = GimbalPolicyType.NOT_PRESENT POLICY = GimbalPolicyType.NOT_PRESENT
GimbalClient.checkIfServerHasGimble(
EditorState(
CURRENT_MODE,
CURRENT_MODE_MODIFIER
)
)
if (TEMP_DISABLED_MODE == Mode.UNKNOWN) { if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
TEMP_DISABLED_MODE = TEMP_DISABLED_MODE =
CURRENT_MODE CURRENT_MODE
@ -73,9 +62,9 @@ object ClientEditor {
CURRENT_MODE_MODIFIER.clear() CURRENT_MODE_MODIFIER.clear()
} }
fun onPolicyReceived(data: GimbalServerState, shouldUpdateServer: Boolean = true) { fun onAllowedCheck(data: GimbalPolicy) {
POLICY = data.policyType POLICY = data.policy
if (data.policyType == GimbalPolicyType.ALLOWED) { if (data.policy == GimbalPolicyType.ALLOWED) {
if (TEMP_DISABLED_MODE != Mode.UNKNOWN) { if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
CURRENT_MODE = CURRENT_MODE =
TEMP_DISABLED_MODE TEMP_DISABLED_MODE
@ -85,19 +74,7 @@ object ClientEditor {
DISABLED_MODIFIERS_STORAGE DISABLED_MODIFIERS_STORAGE
) )
DISABLED_MODIFIERS_STORAGE.clear() DISABLED_MODIFIERS_STORAGE.clear()
onUpdated(shouldUpdateServer) onUpdated()
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()
)
}
} }
} }
@ -115,15 +92,18 @@ object ClientEditor {
} }
fun isInNonDefaultMode(): Boolean { fun isInNonDefaultMode(): Boolean {
return CURRENT_MODE != ClientMain.CONFIG.config.defaultMode return CURRENT_MODE != Mode.NORMAL
} }
/* /*
* Send an updated player state to the server * Send an updated player state to the server
* */ * */
private fun updateServerState() { private fun updateServerState() {
val state = this.getClientState() val state = EditorState(
GimbalClient.sendStatePacket(state) CURRENT_MODE,
CURRENT_MODE_MODIFIER
)
GimbalClient.sendEditorState(state)
ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state) ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
} }
@ -133,13 +113,7 @@ object ClientEditor {
* */ * */
fun setMode(mode: Mode) { fun setMode(mode: Mode) {
if (!isAllowed()) { if (!isAllowed()) {
ChatUtil.showToastToSelf( ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modes", MinecraftClient.getInstance())
"Gimbal is disabled",
"You cannot change modes",
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
return return
} }
if (!MinecraftClient.getInstance().player!!.isCreative) if (!MinecraftClient.getInstance().player!!.isCreative)
@ -154,60 +128,39 @@ object ClientEditor {
* */ * */
fun toggleModifier(mod: ModeModifier) { fun toggleModifier(mod: ModeModifier) {
if (!isAllowed()) { if (!isAllowed()) {
ChatUtil.showToastToSelf( ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modifiers", MinecraftClient.getInstance())
"Gimbal is disabled",
"You cannot change modifiers",
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
return return
} }
if (!MinecraftClient.getInstance().player!!.isCreative) if (!MinecraftClient.getInstance().player!!.isCreative)
return return
if (CURRENT_MODE.incompatibleModifiers.contains(mod)){ if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
if (TEMP_DISABLED_MODIFIERS.contains(mod)) { if (TEMP_DISABLED_MODIFIERS.contains(mod))
TEMP_DISABLED_MODIFIERS.remove(mod) TEMP_DISABLED_MODIFIERS.remove(mod)
} else { else
TEMP_DISABLED_MODIFIERS.add(mod) TEMP_DISABLED_MODIFIERS.add(mod)
}
} }
else { else {
if (CURRENT_MODE_MODIFIER.contains(mod)) { if (CURRENT_MODE_MODIFIER.contains(mod))
CURRENT_MODE_MODIFIER.remove(mod) CURRENT_MODE_MODIFIER.remove(mod)
ChatUtil.showToastToSelf( else
"Disabled ${mod.displayName}",
"[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
ToastType.TOGGLE, ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
} else {
CURRENT_MODE_MODIFIER.add(mod) CURRENT_MODE_MODIFIER.add(mod)
ChatUtil.showToastToSelf(
"Enabled ${mod.displayName}",
"[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
ToastType.TOGGLE, ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
}
} }
onUpdated() onUpdated()
} }
private fun onUpdated(shouldUpdateServer: Boolean = true) { private fun onUpdated() {
CURRENT_MODE_MODIFIER.sortBy { CURRENT_MODE_MODIFIER.sortBy {
it.displayName it.displayName
} }
checkForIncompatibleModeModifiers(shouldUpdateServer) checkForIncompatibleModeModifiers()
} }
/** /**
* This runs on Mode updated * This runs on Mode updated
*/ */
private fun checkForIncompatibleModeModifiers(shouldUpdateServer: Boolean = true) { private fun checkForIncompatibleModeModifiers() {
if (TEMP_DISABLED_MODIFIERS.size > 0) { if (TEMP_DISABLED_MODIFIERS.size > 0) {
CURRENT_MODE_MODIFIER.addAll( CURRENT_MODE_MODIFIER.addAll(
TEMP_DISABLED_MODIFIERS TEMP_DISABLED_MODIFIERS
@ -232,23 +185,19 @@ object ClientEditor {
} }
// Update State // Update State
if (shouldUpdateServer) updateServerState()
updateServerState()
if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) { if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
ChatUtil.showToastToSelf( ChatUtil.showToastToSelf(
"${CURRENT_MODE.displayName} Mode disabled", "${CURRENT_MODE.displayName} Mode disabled",
getDisplayNameListAsString(TEMP_DISABLED_MODIFIERS), getListAsString(TEMP_DISABLED_MODIFIERS), MinecraftClient.getInstance()
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
) )
} }
} }
private fun getDisplayNameListAsString(list: List<ModeModifier>): String { private fun getListAsString(list: List<ModeModifier>): String{
if(list.isEmpty()) if(list.isEmpty())
return "" return "Empty list"
val sb = StringBuilder() val sb = StringBuilder()
for (mod in list) { for (mod in list) {
sb.append(mod.displayName) sb.append(mod.displayName)
@ -257,60 +206,28 @@ object ClientEditor {
return sb.toString().dropLast(2) return sb.toString().dropLast(2)
} }
private fun getShortNameListAsString(list: List<ModeModifier>): 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 * Get the display text to display in the HUD
* */ * */
fun getModeDisplayText(config: GimbalClientConfig): Text { fun getModeDisplayText(): Text {
val displayText = StringBuilder(CURRENT_MODE.displayName) val displayText = StringBuilder(CURRENT_MODE.displayName)
if (isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) { if (CURRENT_MODE_MODIFIER.isNotEmpty() && isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) {
when (config.guiSettings.hudOptions) { displayText.append(" [")
HudOptions.ALL -> { for (i in CURRENT_MODE_MODIFIER.indices) {
if (CURRENT_MODE_MODIFIER.size > 0) { displayText.append(CURRENT_MODE_MODIFIER[i].displayName)
displayText.append(" [") if (i != CURRENT_MODE_MODIFIER.size - 1) {
displayText.append(this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)) displayText.append(", ")
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())
} }
displayText.append("]")
} else if (!isAllowed() || !MinecraftClient.getInstance().player?.isCreative!!) {
displayText.clear()
displayText.append("[GIMBLE DISABLED]")
} }
return Text.of("[GIMBAL DISABLED]") return Text.of(displayText.toString())
} }
fun getCurrentColor(): Int { fun getCurrentColor(): Int {
return CURRENT_MODE.color return CURRENT_MODE.color
} }
fun getClientState(): EditorState {
return EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
}
} }

View file

@ -30,7 +30,6 @@ import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleNoUp
import net.moonleay.gimbal.client.keybindings.impl.gamemode.CreativeModeShortcut 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.SpectatorModeShortcut
import net.moonleay.gimbal.client.keybindings.impl.gamemode.SurvivalModeShortcut import net.moonleay.gimbal.client.keybindings.impl.gamemode.SurvivalModeShortcut
import net.moonleay.gimbal.constants.TranslationKeys
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
@ -48,28 +47,28 @@ object KeybindingRegistrar {
private fun registerSetEditorModeModifierKeybindings() { private fun registerSetEditorModeModifierKeybindings() {
val toggleBulldozerModifierShortcut = KeyBinding( val toggleBulldozerModifierShortcut = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Modifier.BULLDOZER, "gimbal.key.editor.modifier.bulldozer",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Editor.MODIFIER "gimbal.category.editormodifier"
) )
val toggleForcePlaceModifierShortcut = KeyBinding( val toggleForcePlaceModifierShortcut = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Modifier.FORCE_PLACE, "gimbal.key.editor.modifier.forceplace",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Editor.MODIFIER "gimbal.category.editormodifier"
) )
val toggleNoUpdatesModifierShortcut = KeyBinding( val toggleNoUpdatesModifierShortcut = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_UPDATES, "gimbal.key.editor.modifier.noupdates",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Editor.MODIFIER "gimbal.category.editormodifier"
) )
val toggleNoClipModifierShortcut = KeyBinding( val toggleNoClipModifierShortcut = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_CLIP, "gimbal.key.editor.modifier.noclip",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Editor.MODIFIER "gimbal.category.editormodifier"
) )
KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut)) KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut))
@ -80,16 +79,16 @@ object KeybindingRegistrar {
private fun registerSetEditorModeKeybindings() { private fun registerSetEditorModeKeybindings() {
val insertKeyBinding = KeyBinding( val insertKeyBinding = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Mode.INSERT, "gimbal.key.editor.mode.insert",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_I, GLFW.GLFW_KEY_I,
TranslationKeys.Keybindings.Category.Editor.MODE "gimbal.category.editormode"
) )
val replaceKeyBinding = KeyBinding( val replaceKeyBinding = KeyBinding(
TranslationKeys.Keybindings.Binding.Editor.Mode.REPLACE, "gimbal.key.editor.mode.replace",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_R, GLFW.GLFW_KEY_R,
TranslationKeys.Keybindings.Category.Editor.MODE "gimbal.category.editormode"
) )
// val visualKeyBinding = KeyBinding( // val visualKeyBinding = KeyBinding(
// "gimbal.key.editor.mode.visual", // "gimbal.key.editor.mode.visual",
@ -104,22 +103,22 @@ object KeybindingRegistrar {
private fun registerSetGameModeKeybindings() { private fun registerSetGameModeKeybindings() {
val survivalKeyBinding = KeyBinding( val survivalKeyBinding = KeyBinding(
TranslationKeys.Keybindings.Binding.Game.Mode.SURVIVAL, "gimbal.key.game.mode.survival",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Game.GAMEMODE "gimbal.category.gamemode"
) )
val creativeKeyBinding = KeyBinding( val creativeKeyBinding = KeyBinding(
TranslationKeys.Keybindings.Binding.Game.Mode.CREATIVE, "gimbal.key.game.mode.creative",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Game.GAMEMODE "gimbal.category.gamemode"
) )
val spectatorKeyBinding = KeyBinding( val spectatorKeyBinding = KeyBinding(
TranslationKeys.Keybindings.Binding.Game.Mode.SPECTATOR, "gimbal.key.game.mode.spectator",
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
TranslationKeys.Keybindings.Category.Game.GAMEMODE "gimbal.category.gamemode"
) )
KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding)) KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding))
KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding)) KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding))

View file

@ -1,151 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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)
}
}

View file

@ -1,290 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<Boolean?>?, 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<HudOptions>>(
CyclingButtonWidget.builder<HudOptions> { 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<HudOptions>?, 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<ToastSettings>>(
CyclingButtonWidget.builder<ToastSettings> { 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<ToastSettings>?, 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<Boolean?>?, 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<Mode>>(
CyclingButtonWidget.builder<Mode> { 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<Mode>?, 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)
}
}

View file

@ -1,50 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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)
}
}

View file

@ -21,7 +21,6 @@ package net.moonleay.gimbal.client.util
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.client.toast.SystemToast import net.minecraft.client.toast.SystemToast
import net.minecraft.text.Text import net.minecraft.text.Text
import net.moonleay.gimbal.client.config.GimbalClientConfig
object ChatUtil { object ChatUtil {
/** /**
@ -38,16 +37,7 @@ object ChatUtil {
client.inGameHud.chatHud.addMessage(Text.of(message)) client.inGameHud.chatHud.addMessage(Text.of(message))
} }
fun showToastToSelf( fun showToastToSelf(title: String, description: String, client: MinecraftClient) {
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)) val toast = SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.of(title), Text.of(description))
client.toastManager.add(toast) client.toastManager.add(toast)
} }

View file

@ -1,44 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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.")
}
}

View file

@ -1,24 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.util
enum class ToastType {
TOGGLE,
SYSTEM,
}

View file

@ -1,71 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<HorizontalAnchor, VerticalAnchor> {
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
}
}

View file

@ -1,23 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.constants
object PermissionIDs {
const val GIMBAL_USAGE_PERMISSION = "gimbal.use"
}

View file

@ -1,127 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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"
}
}
}
}
}

View file

@ -28,6 +28,6 @@ internal class DataGenerator : DataGeneratorEntrypoint {
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
LOGGER.info("Starting Data Generation") LOGGER.info("Starting Data Generation")
fabricDataGenerator.addProvider(EnUsLanguageProvider(fabricDataGenerator)) fabricDataGenerator.addProvider(En_us_GimbalLanguageProvider(fabricDataGenerator))
} }
} }

View file

@ -1,96 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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")
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.datagen
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
class En_us_GimbalLanguageProvider(dataGenerator: FabricDataGenerator?) :
FabricLanguageProvider(dataGenerator, "en_us") {
override fun generateTranslations(translationBuilder: TranslationBuilder?) {
if (translationBuilder == null) return
// Editor modes
translationBuilder.add("gimbal.category.editormode", "Editor Modes")
translationBuilder.add("gimbal.key.editor.mode.insert", "Enter Insert Mode")
translationBuilder.add("gimbal.key.editor.mode.replace", "Enter Replace Mode")
translationBuilder.add("gimbal.key.editor.mode.visual", "Enter Visual Mode")
// Editor mode modifiers
translationBuilder.add("gimbal.category.editormodifier", "Editor Mode Modifiers")
translationBuilder.add("gimbal.key.editor.modifier.bulldozer", "Toggle Bulldozer Modifier")
translationBuilder.add("gimbal.key.editor.modifier.forceplace", "Toggle Force Place Modifier")
translationBuilder.add("gimbal.key.editor.modifier.noupdates", "Toggle No Updates Modifier")
translationBuilder.add("gimbal.key.editor.modifier.noclip", "Toggle No Clip Modifier")
// Game mode
translationBuilder.add("gimbal.category.gamemode", "Game Mode")
translationBuilder.add("gimbal.key.game.mode.survival", "Enable Survival Mode")
translationBuilder.add("gimbal.key.game.mode.creative", "Enable Creative Mode")
translationBuilder.add("gimbal.key.game.mode.spectator", "Enable Spectator Mode")
}
}

View file

@ -32,7 +32,7 @@ object ServerEditorManager {
fun updateEditorState(playerUUID: UUID, editorState: EditorState) { fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
STATEMAP[playerUUID] = editorState STATEMAP[playerUUID] = editorState
LOGGER.debug("{}: {} with {}", playerUUID, editorState.editorMode, editorState.editorModifier) LOGGER.info("$playerUUID: ${editorState.editorMode} with ${editorState.editorModifier}")
} }

View file

@ -18,11 +18,8 @@
package net.moonleay.gimbal.editor.state package net.moonleay.gimbal.editor.state
import kotlinx.serialization.Serializable
@Serializable
enum class GimbalPolicyType { enum class GimbalPolicyType {
ALLOWED, ALLOWED,
DENIED, DENIED,
NOT_PRESENT, NOT_PRESENT
} }

View file

@ -1,27 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state
import kotlinx.serialization.Serializable
@Serializable
data class GimbalServerState(
val protocolVersion: Int,
val policyType: GimbalPolicyType,
)

View file

@ -18,11 +18,10 @@
package net.moonleay.gimbal.editor.state.mode package net.moonleay.gimbal.editor.state.mode
enum class Mode(val displayName: String, val color: Int, val hidden: Boolean, val incompatibleModifiers: List<ModeModifier>){ enum class Mode(val displayName: String, val color: Int, val incompatibleModifiers: List<ModeModifier>){
UNKNOWN("UNKNOWN", 0x000000, true, listOf()), // Unknown mode. This mode cannot be entered UNKNOWN("UNKNOWN", 0x000000, listOf()), // Unknown mode. This mode cannot be entered
NORMAL("NORMAL", 0x90a959, false, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing NORMAL("NORMAL", 0x90a959, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
INSERT("INSERT", 0xf4bf75, false, listOf()), // Place and break blocks INSERT("INSERT", 0xf4bf75, listOf()), // Place and break blocks
REPLACE("REPLACE", 0xac4242, false, listOf(ModeModifier.NO_UPDATES)), // Replace blocks REPLACE("REPLACE", 0xac4242, listOf(ModeModifier.NO_UPDATES)), // Replace blocks
// Add hidden modes after this comment VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
VISUAL("VISUAL", 0x6a9fb5, true, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
} }

View file

@ -18,10 +18,10 @@
package net.moonleay.gimbal.editor.state.mode package net.moonleay.gimbal.editor.state.mode
enum class ModeModifier(val displayName: String, val shortName: String) { enum class ModeModifier(val displayName: String) {
// NONE("None"), // No Modifiers - default behavior // NONE("None"), // No Modifiers - default behavior
NO_UPDATES("NO UPDATES", "NU"), // Do not update blocks when placing NO_UPDATES("NO UPDATES"), // Do not update blocks when placing
BULLDOZER("BULLDOZER", "BLR"), // Break blocks fast BULLDOZER("BULLDOZER"), // Break blocks fast
FORCE_PLACE("FORCE", "FP"), // Ignore block placement restrictions FORCE_PLACE("FORCE"), // Ignore block placement restrictions
NO_CLIP("NO CLIP", "NC"), // Do not collide with blocks NO_CLIP("NO CLIP"), // Do not collide with blocks
} }

View file

@ -20,13 +20,9 @@ package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity; 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.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@ -36,49 +32,30 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects; import java.util.Objects;
@Mixin(MinecraftClient.class)
public abstract class BulldozerMixin { public abstract class BulldozerMixin {
@Mixin(MinecraftClient.class) @Shadow protected int attackCooldown;
public static abstract class MinecraftClientMixin {
@Shadow
@Nullable
public ClientPlayerEntity player;
@Shadow
protected int attackCooldown;
@Inject(method = "doAttack", at = @At(value = "HEAD")) @Shadow
private void func(CallbackInfoReturnable<Boolean> cir) { @Nullable
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) { public ClientPlayerEntity player;
return;
}
this.attackCooldown = 0;
}
@Inject(method = "handleBlockBreaking", at = @At(value = "HEAD")) @Inject(method = "doAttack", at = @At(value = "HEAD"))
private void func2(boolean breaking, CallbackInfo ci) { private void func(CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) { if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
return; return;
}
this.attackCooldown = 0;
} }
this.attackCooldown = 0;
} }
@Mixin(ClientPlayerInteractionManager.class) @Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
public static abstract class ClientPlayerInteractionManagerMixin { private void func2(boolean breaking, CallbackInfo ci) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
@Shadow return;
private int blockBreakingCooldown;
@Shadow
@Final
private MinecraftClient client;
@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
return;
}
this.blockBreakingCooldown = 0;
} }
this.attackCooldown = 0;
} }
} }

View file

@ -19,27 +19,34 @@
package net.moonleay.gimbal.mixin; package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket; import net.minecraft.util.math.BlockPos;
import net.moonleay.gimbal.client.ClientMain; import net.minecraft.util.math.Direction;
import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ClientPlayNetworkHandler.class) import java.util.Objects;
public abstract class PlayerFlySpeedMixin {
@Mixin(ClientPlayerInteractionManager.class)
public class BulldozerMixin2 {
@Shadow private int blockBreakingCooldown;
@Shadow @Shadow
@Final @Final
private MinecraftClient client; private MinecraftClient client;
@Inject(method = "onPlayerAbilities", at = @At(value = "RETURN")) @Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
private void func(PlayerAbilitiesS2CPacket packet, CallbackInfo ci) { private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
this.client.player.getAbilities().setFlySpeed((ClientMain.CONFIG.getConfig().getPlayerFlySpeed() / 100) * 0.05f); if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
//client!!.player!!.abilities.flySpeed = (this.playerFlySpeed / 100) * 0.05f return;
}
this.blockBreakingCooldown = 0;
} }
} }

View file

@ -16,13 +16,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package net.moonleay.gimbal.client.config.enums package net.moonleay.gimbal.mixin;
import kotlinx.serialization.Serializable import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import net.moonleay.gimbal.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;
@Serializable @Mixin(DownloadingTerrainScreen.class)
enum class HorizontalAnchor { public class GimbalPolicyCheckMixin {
LEFT,
CENTER,
RIGHT, @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();
}
} }

View file

@ -22,11 +22,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack; 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.editor.ClientEditor;
import net.moonleay.gimbal.client.util.screen.ScreenUtil;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -35,40 +31,16 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InGameHud.class) @Mixin(InGameHud.class)
public abstract class HudMixin { public class HudMixin {
@Shadow @Final private MinecraftClient client; @Shadow @Final private MinecraftClient client;
@Inject(method = "renderStatusEffectOverlay", at = @At("HEAD")) @Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
private void render(MatrixStack matrices, CallbackInfo ci) { private void render(MatrixStack matrices, CallbackInfo ci) {
TextRenderer tr = this.client.textRenderer; TextRenderer tr = this.client.textRenderer;
GimbalGuiSettings conf = ClientMain.CONFIG.getConfig().getGuiSettings(); tr.drawWithShadow(matrices,
if (!conf.getShowHud()) ClientEditor.INSTANCE.getModeDisplayText(),
return; 4, 4,
int scaleFactor = this.client.getWindow() ClientEditor.INSTANCE.getCurrentColor());
.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()
);
} }
} }

View file

@ -0,0 +1,41 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.moonleay.gimbal.client.editor.ClientEditor;
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;
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<Double> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
return;
}
cir.setReturnValue(desiredCameraDistance);
cir.cancel();
}
}

View file

@ -19,15 +19,12 @@
package net.moonleay.gimbal.mixin; package net.moonleay.gimbal.mixin;
import com.mojang.authlib.GameProfile; 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.EntityPose;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.ServerEditorManager; import net.moonleay.gimbal.editor.ServerEditorManager;
import net.moonleay.gimbal.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -35,72 +32,51 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.UUID; import java.util.UUID;
public abstract class NoClipMixin { @Mixin(PlayerEntity.class)
public abstract class NoClipMixin extends LivingEntity {
@Shadow public abstract GameProfile getGameProfile();
@Mixin(PlayerEntity.class) // Serverside, allows clipping @Shadow public abstract PlayerAbilities getAbilities();
public static abstract class PlayerEntityMixin extends LivingEntity {
protected PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) { @Shadow
super(entityType, world); 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) {
@Shadow return;
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);
} }
// Enable NoClip
this.noClip = true;
} }
@Inject(method = "updatePose", at = @At("HEAD"))
private void onUpdatePose(CallbackInfo ci) {
UUID uuid = this.getGameProfile().getId();
@Mixin(Camera.class) // Clientside, fixes camera if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
public static abstract class CameraMixin { return; // NoClip is not enabled
if (!this.getAbilities().flying)
return;
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true) // Force standing pose in NoClip mode
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<Double> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) { this.setPose(EntityPose.STANDING);
return;
}
cir.setReturnValue(desiredCameraDistance);
cir.cancel();
}
} }
} }

View file

@ -21,9 +21,9 @@ package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.option.GameOptions; import net.minecraft.client.option.GameOptions;
import net.moonleay.gimbal.client.ClientMain;
import net.moonleay.gimbal.client.editor.ClientEditor; import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import net.moonleay.gimbal.editor.state.mode.Mode;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -43,12 +43,12 @@ public class NormalModeMixin {
public ClientPlayerEntity player; public ClientPlayerEntity player;
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true) @Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
private void setDefaultMode(boolean pause, CallbackInfo ci) { private void setNormalMode(boolean pause, CallbackInfo ci) {
if (ClientMain.CONFIG.getConfig().getShouldEscResetMode() && ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) { if (ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
assert this.player != null; assert this.player != null;
if (this.player.isCreative()) { if (this.player.isCreative()) {
// Set the editor mode to normal // Set the editor mode to normal
ClientEditor.INSTANCE.setMode(ClientMain.CONFIG.getConfig().getDefaultMode()); ClientEditor.INSTANCE.setMode(Mode.NORMAL);
ci.cancel(); ci.cancel();
} }
} }

View file

@ -19,86 +19,69 @@
package net.moonleay.gimbal.mixin; package net.moonleay.gimbal.mixin;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.client.MinecraftClient;
import net.minecraft.item.*; import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.state.property.Property; 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.Hand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.util.math.Direction;
import net.moonleay.gimbal.editor.ServerEditorManager; import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.*; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.UUID; @Mixin(MinecraftClient.class)
public abstract class ReplaceModeMixin { public abstract class ReplaceModeMixin {
@Mixin(ItemPlacementContext.class)
public static abstract class ItemPlacementContextMixin extends ItemUsageContext {
@Shadow
protected boolean canReplaceExisting;
@Mutable @Shadow protected abstract void handleBlockBreaking(boolean breaking);
@Shadow
@Final
private BlockPos placementPos;
public ItemPlacementContextMixin(PlayerEntity player, Hand hand, BlockHitResult hit) { @Shadow @Nullable public ClientPlayerInteractionManager interactionManager;
super(player, hand, hit);
}
@Inject(method = "<init>(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")) @Shadow @Final public ParticleManager particleManager;
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; @Shadow @Nullable public ClientPlayerEntity player;
this.placementPos = blockHitResult.getBlockPos();
}
}
@Mixin(BlockItem.class) @Shadow @Nullable public HitResult crosshairTarget;
public static abstract class BlockItemMixin extends Item {
public BlockItemMixin(Settings settings) { @Inject(method = "doItemUse", at = @At("HEAD"))
super(settings); 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;
@Shadow // Gather data
protected abstract boolean place(ItemPlacementContext context, BlockState state); BlockPos pos = blockHitResult.getBlockPos();
Direction direction = blockHitResult.getSide();
BlockState blockState = client.world.getBlockState(pos);
@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")) // Start sending shit
private boolean func(BlockItem instance, ItemPlacementContext context, BlockState state) { client.getTutorialManager().onBlockBreaking(client.world, pos, blockState, 1.0F);
if (context.getPlayer() == null) this.interactionManager.sendSequencedPacket(client.world, sequence -> {
return this.place(context, state); this.interactionManager.breakBlock(pos);
UUID id = context.getPlayer().getGameProfile().getId(); return new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, direction, sequence);
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE)) });
return this.place(context, state); this.player.swingHand(Hand.MAIN_HAND);
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;
}
} }
} }

View file

@ -1,104 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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)
)
);
}
}
}

View file

@ -25,46 +25,38 @@ import kotlinx.serialization.encodeToByteArray
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.minecraft.network.PacketByteBuf import net.minecraft.network.PacketByteBuf
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.client.editor.ClientEditor 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.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType import net.moonleay.gimbal.editor.util.GimbalPolicy
import net.moonleay.gimbal.editor.state.GimbalServerState
object GimbalClient { object GimbalClient {
fun registerPacketHandlers() { fun registerPacketHandlers() {
ClientPlayNetworking.registerGlobalReceiver(PacketIDs.GIMBAL_POLICY_PACKET_ID) { _, _, buf, handler -> ClientPlayNetworking.registerGlobalReceiver(PacketIDs.TRANSFER_GIMBLE_POLICY_ID) { _, _, buf, _ ->
val state = this.getServerState(buf) onAllowedCheck(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) @OptIn(ExperimentalSerializationApi::class)
private fun getServerState(buf: PacketByteBuf): GimbalServerState { private fun onAllowedCheck(buf: PacketByteBuf) {
val serverState = Cbor.decodeFromByteArray<GimbalServerState>(buf.readByteArray()) val policy = Cbor.decodeFromByteArray<GimbalPolicy>(buf.readByteArray())
return serverState ClientEditor.onAllowedCheck(policy) // Update the client's policy
} }
private fun isGimbalUsable(state: GimbalServerState): Boolean { /**
return state.policyType == GimbalPolicyType.ALLOWED && state.protocolVersion.toString() == BuildConstants.protocolVersion * 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)
} }
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
private fun createStatePacket(state: EditorState): PacketByteBuf { fun checkIfServerHasGimble(state: EditorState) {
val buf = PacketByteBufs.create() val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state)) buf.writeByteArray(Cbor.encodeToByteArray(state))
return buf ClientPlayNetworking.send(PacketIDs.GIMBLE_PRERENCE_CHECK_ID, buf)
}
fun sendStatePacket(state: EditorState) {
ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, createStatePacket(state))
} }
} }

View file

@ -18,48 +18,31 @@
package net.moonleay.gimbal.networking package net.moonleay.gimbal.networking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray 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.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.network.PacketByteBuf import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity 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.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.state.GimbalServerState import net.moonleay.gimbal.editor.util.GimbalPolicy
import org.apache.logging.log4j.LogManager
object GimbalServer { object GimbalServer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
fun registerPacketHandler() { fun registerPacketHandler() {
ServerPlayNetworking ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID) .registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
{ _, player, _, buf, _ -> { server, player, handler, buf, responseSender ->
handleStateUpdate(player, buf) handleStateUpdate(player, buf)
} }
} ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.GIMBLE_PRERENCE_CHECK_ID)
@OptIn(ExperimentalSerializationApi::class) { server, player, handler, buf, responseSender ->
fun notifyPlayerOfPolicy(player: ServerPlayerEntity) { handlePresenceCheck(player, buf)
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){ private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
@ -68,7 +51,12 @@ object GimbalServer {
// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}")) // player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
} }
private fun isPlayerAllowedToUseGimbal(player: ServerPlayerEntity): Boolean { private fun handlePresenceCheck(player: ServerPlayerEntity, buf: PacketByteBuf) {
return player.hasPermissionLevel(2) || Permissions.check(player, PermissionIDs.GIMBAL_USAGE_PERMISSION) val state = Cbor.decodeFromByteArray<EditorState>(buf.readByteArray())
ServerEditorManager.updateEditorState(player.uuid, state)
val buffer = PacketByteBufs.create()
buffer.writeByteArray(Cbor.encodeToByteArray(GimbalPolicy(GimbalPolicyType.ALLOWED)))
ServerPlayNetworking.send(player, PacketIDs.TRANSFER_GIMBLE_POLICY_ID, buffer)
} }
} }

View file

@ -16,13 +16,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package net.moonleay.gimbal.constants package net.moonleay.gimbal.networking
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.build.BuildConstants
object PacketIDs { object PacketIDs {
val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state") val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
val GIMBAL_POLICY_PACKET_ID = Identifier(BuildConstants.modId, "gimbal_policy") val GIMBLE_PRERENCE_CHECK_ID = Identifier(BuildConstants.modId, "gimble_preference_check")
val TRANSFER_GIMBLE_POLICY_ID = Identifier(BuildConstants.modId, "gimble_is_present")
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -7,9 +7,6 @@
"authors": [ "authors": [
"moonleay" "moonleay"
], ],
"contributors": [
"Cookieso"
],
"icon": "assets/${modId}/logo.png", "icon": "assets/${modId}/logo.png",
"contact": { "contact": {
"email": "contact@moonleay.net", "email": "contact@moonleay.net",

View file

@ -2,4 +2,3 @@ accessWidener v2 named
accessible method net/minecraft/client/MinecraftClient handleBlockBreaking (Z)V 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 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;

View file

@ -6,19 +6,16 @@
"mixins": [ "mixins": [
"ForcePlaceMixin", "ForcePlaceMixin",
"NoBlockUpdatesMixin", "NoBlockUpdatesMixin",
"NoClipMixin$PlayerEntityMixin", "NoClipMixin"
"ReplaceModeMixin$BlockItemMixin",
"ReplaceModeMixin$ItemPlacementContextMixin"
], ],
"client": [ "client": [
"BulldozerMixin$ClientPlayerInteractionManagerMixin", "BulldozerMixin",
"BulldozerMixin$MinecraftClientMixin", "BulldozerMixin2",
"GimbalPolicyCheckMixin",
"HudMixin", "HudMixin",
"NoClipMixin$CameraMixin", "NoClipCameraFixMixin",
"NormalModeMixin", "NormalModeMixin",
"PlayerFlySpeedMixin", "ReplaceModeMixin"
"YouInjectButtonMixin$GameMenuScreenMixin",
"YouInjectButtonMixin$TitleScreenMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View file

@ -22,6 +22,4 @@ internal object BuildConstants {
const val modId = "${modId}" const val modId = "${modId}"
const val modName = "${modName}" const val modName = "${modName}"
const val modVersion = "${modVersion}" const val modVersion = "${modVersion}"
const val protocolVersion = "${protocolVersion}"
} }