Compare commits

...

32 commits

Author SHA1 Message Date
dc732cc39f
feat: add ESC resets mode setting 2024-06-13 18:52:04 +02:00
d59cf8f9f0
feat: add default mode setting 2024-06-13 18:39:27 +02:00
5252d9abdf
feat: changed server side state log to debug 2024-06-13 18:20:18 +02:00
42737446b2
feat: added player fly speed controls
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-17 01:10:54 +02:00
6a89e5683f
refactor: combined NoClip and ReplaceMode mixins into one mixin each
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-16 16:35:44 +02:00
4c8404d306
refactor: combined Bulldozer and YouInjectButton mixin into one mixin each
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-16 03:52:34 +02:00
b4f46ee703
feat: added option and config for player fly speed
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-16 03:31:41 +02:00
19f4b3649a
feat: created custom slider widget
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-16 03:29:57 +02:00
7325798098
feat: improved loading and saving logic, made Json loader ignore unknown keys
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-11 03:06:01 +02:00
302f486f1c chore/add-ci (#3)
Added ci for dev and release builds.

Reviewed-on: https://codeberg.org/moonleay/Gimbal/pulls/3
Co-authored-by: moonleay <contact@moonleay.net>
Co-committed-by: moonleay <contact@moonleay.net>
2024-05-10 15:17:26 +00:00
68e9eeceb6
chore: bumped protocol version, because server side component changed
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-07 01:14:11 +02:00
moonleay
60e638a3d8 Merge pull request 'fix: Dynamic Property Copying in Replace Mode' (#2) from Cookieso/Gimbal:master into master
Reviewed-on: https://codeberg.org/moonleay/Gimbal/pulls/2
2024-05-06 23:11:57 +00:00
31bab51603 fix: Made replace mode more dynamic to copy properties for all blocks 2024-05-06 21:43:57 +02:00
6002af93a5
feat: added settings and a config system
refactor: Reworked translation key system

Signed-off-by: moonleay <contact@moonleay.net>
2024-05-06 02:52:28 +02:00
e7355f9781
chore: removed unused vars
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-05 20:04:44 +02:00
f10897bf5d
Merge remote-tracking branch 'origin/master' 2024-05-05 20:04:23 +02:00
d26f96ee04
feat: finished HUD pos conf system
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-05 20:03:59 +02:00
89dee6841a
feat: finished HUD pos conf system
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-05 20:03:29 +02:00
5c77165d17
feat: added config, added config ui, started working on HUD configurator
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-05 05:11:33 +02:00
13cbbfa72f
chore: replaced println() with proper logging util
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-04 02:48:56 +02:00
7cf65cffd2
chore: updated overlooked mentions of old name
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-04 02:39:54 +02:00
b5d65623aa
chore!: bumped version to 0.3.0, bumped protocol version to 2
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-04 02:36:41 +02:00
dca01b275f
feat!: reworked replace mode to work server side, added propper stair replacement support
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-04 02:35:49 +02:00
c321746b08
feat: bump version, set correct protocol version
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-01 19:56:31 +02:00
8bcbcc021b
fix: fixed not being able to join worlds in multiplayer and singleplayer
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-01 19:55:53 +02:00
8b7e576d3d
feat: added permission checks to server, reworked login process, upgraded gradle, upgraded loom
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-01 18:42:50 +02:00
8203d74b90
chore: updated README.md
Signed-off-by: moonleay <contact@moonleay.net>
2024-05-01 01:13:23 +02:00
cfbd5d721c
chore: updated copyright in other files
Signed-off-by: moonleay <contact@moonleay.net>
2024-04-29 23:11:38 +02:00
be062885ed
chore: updated logo
Signed-off-by: moonleay <contact@moonleay.net>
2024-04-29 15:11:56 +02:00
c14cdffeed
chore: renamed to Gimbal, because I cannot spell apparently
Signed-off-by: moonleay <contact@moonleay.net>
2024-04-29 15:08:02 +02:00
1c7138bb58
feat!: added No Updates to incompatibleModifier list of replace mode
Signed-off-by: moonleay <contact@moonleay.net>
2024-04-28 16:11:48 +02:00
499863cba9
chore: added copyright notice to top of files
Signed-off-by: moonleay <contact@moonleay.net>
2024-04-28 03:59:27 +02:00
110 changed files with 3491 additions and 1067 deletions

View file

@ -0,0 +1,42 @@
on:
push:
branches-ignore:
- refs/tags/
jobs:
dev:
runs-on: nodebullshit
steps:
- uses: actions/checkout@v3
name: Checkout
- name: Set short git commit reference
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- uses: https://github.com/actions/setup-java@v4
name: Setup Java
with:
distribution: temurin
java-version: 17
- uses: https://github.com/gradle/actions/setup-gradle@v3
name: Setup Gradle
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew runDatagen
name: Generate assets
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew build
name: Build project
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew publish
name: Upload
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
PACKAGE_REPO_KEY: ${{ secrets.PACKAGE_REPO_KEY }}

View file

@ -0,0 +1,54 @@
on:
release:
types:
- released
- prereleased
- created
- published
jobs:
release:
runs-on: nodebullshit
steps:
- uses: actions/checkout@v3
name: Checkout
- name: Fetch the full git repository
run: git fetch --prune --unshallow
- name: Set short git commit reference
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- uses: https://github.com/actions/setup-java@v4
name: Setup Java
with:
distribution: temurin
java-version: 17
- uses: https://github.com/gradle/actions/setup-gradle@v3
name: Setup Gradle
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew runDatagen
name: Generate assets
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew build
name: Build project
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
- run: ./gradlew publish
name: Upload
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
PACKAGE_REPO_KEY: ${{ secrets.PACKAGE_REPO_KEY }}
- run: ./gradlew modrinth
name: Publish to Modrinth
env:
GIT_SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}

View file

@ -631,7 +631,7 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
Gimble Gimbal
Copyright (C) 2024 moonleay Copyright (C) 2024 moonleay
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode: notice like this when it starts in an interactive mode:
Gimble Copyright (C) 2024 moonleay Gimbal Copyright (C) 2024 moonleay
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.

View file

@ -1,6 +1,21 @@
# The Gimble project # The Gimbal project
This project aims to improve the experience of creating structures in Minecraft. This project aims to improve the experience of creating structures in Minecraft.
# Links
<a href="https://discord.gg/rQUVrsttzz" target="_blank">
<img src="https://img.shields.io/badge/Join_the-Discord-5865F2" alt="Join the Discord" />
</a>
<a href="https://codeberg.org/moonleay/Gimbal/wiki/?action=_pages">
<img src="https://img.shields.io/badge/Read_the-wiki-ffffff" alt="Read the wiki" />
</a>
<a href="https://codeberg.org/moonleay/Gimbal">
<img src="https://img.shields.io/badge/Clone_the-source_code-green" alt="Clone the source code" />
</a>
<a href="https://codeberg.org/moonleay/Gimbal/issues">
<img src="https://img.shields.io/badge/Report_a-problem-red" alt="Report a problem"/>
</a>
## Features ## Features
- **Modes** Use different modes to edit structures. Think Vim for Minecraft. [x] - **Modes** Use different modes to edit structures. Think Vim for Minecraft. [x]
- **Modifier** Use modifiers to change the behavior of the modes and your building experience. [x] - **Modifier** Use modifiers to change the behavior of the modes and your building experience. [x]

View file

@ -1,3 +1,21 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import org.jetbrains.gradle.ext.ProjectSettings import org.jetbrains.gradle.ext.ProjectSettings
import org.jetbrains.gradle.ext.TaskTriggersConfig import org.jetbrains.gradle.ext.TaskTriggersConfig
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -9,13 +27,23 @@ 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 mavenVersion = System.getenv("CI_COMMIT_TAG") ?: System.getenv("CI_COMMIT_SHORT_SHA")?.let { "$it-dev" } val ver = if ((System.getenv("GITHUB_REF") ?: "local").startsWith("refs/tags/"))
?: "0.1.0-dev" //""0.0.0-SNAPSHOT" System.getenv("GITHUB_REF_NAME") ?: "err" else System.getenv("GIT_SHA_SHORT") ?: "0.0.0"
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
@ -32,6 +60,9 @@ 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 {
@ -48,6 +79,10 @@ 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
@ -58,6 +93,7 @@ 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,
@ -151,17 +187,18 @@ publishing {
} }
repositories { repositories {
if (System.getenv("CI_JOB_TOKEN") != null) { if (System.getenv("CI") != null) {
maven { maven {
name = "GitLab" name = "Codeberg"
val projectId = System.getenv("CI_PROJECT_ID") val repoOwner = System.getenv("GITHUB_REPOSITORY_OWNER")
val apiV4 = System.getenv("CI_API_V4_URL") val serverUrl = System.getenv("GITHUB_SERVER_URL")
url = uri("$apiV4/projects/$projectId/packages/maven") val accessToken = System.getenv("PACKAGE_REPO_KEY")
url = uri("$serverUrl/api/packages/$repoOwner/maven")
authentication { authentication {
create("token", HttpHeaderAuthentication::class.java) { create("header", HttpHeaderAuthentication::class.java) {
credentials(HttpHeaderCredentials::class.java) { credentials(HttpHeaderCredentials::class) {
name = "Job-Token" name = "Authorization"
value = System.getenv("CI_JOB_TOKEN") value = "token $accessToken"
} }
} }
} }
@ -170,6 +207,33 @@ publishing {
} }
} }
// build.gradle.kts
modrinth {
token.set(System.getenv("MODRINTH_TOKEN")) // Remember to have the MODRINTH_TOKEN environment variable set or else this will fail - just make sure it stays private!
projectId.set(modId) // This can be the project ID or the slug. Either will work!
versionNumber.set(mavenVersion) // You don't need to set this manually. Will fail if Modrinth has this version already
versionName.set("$modName $mavenVersion for $minecraftVersion")
versionType.set("alpha") // This is the default -- can also be `beta` or `alpha`
uploadFile.set(tasks.remapJar) // With Loom, this MUST be set to `remapJar` instead of `jar`!
gameVersions.addAll(listOf(project.ext["minecraft.version"] as String)) // Must be an array, even with only one version
loaders.add("fabric") // Must also be an array - no need to specify this if you're using Loom or ForgeGradle
changelog.set(
"Changelog v$mavenVersion\n\nCheckout the changelog [on codeberg](${System.getenv("GITHUB_SERVER_URL") ?: ""}/${
System.getenv(
"GITHUB_REPOSITORY"
) ?: ""
}/releases/tag/${System.getenv("GITHUB_REF_NAME") ?: ""})"
)
dependencies { // A special DSL for creating dependencies
// scope.type
// The scope can be `required`, `optional`, `incompatible`, or `embedded`
// The type can either be `project` or `version`
required.project("fabric-api") // Creates a new required dependency on Fabric API
required.project("fabric-language-kotlin")
}
}
rootProject.idea.project { rootProject.idea.project {
this as ExtensionAware this as ExtensionAware
configure<ProjectSettings> { configure<ProjectSettings> {

View file

@ -1,18 +1,36 @@
#
# Gimbal
# Copyright (C) 2024 moonleay
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
#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.4.6 fabric.loom.version=1.6-SNAPSHOT
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
idea-ext.version=1.1.6 idea-ext.version=1.1.6
org.gradle.jvmargs=-Xmx2G org.gradle.jvmargs=-Xmx2G
modId=gimble modId=gimbal
kotlinx.serialization.version=1.6.2 kotlinx.serialization.version=1.6.2
fabric.kotlin.version=1.10.18+kotlin.1.9.22 fabric.kotlin.version=1.10.18+kotlin.1.9.22
mavenGroup=net.moonleay mavenGroup=net.moonleay
kotlin.code.style=official kotlin.code.style=official
minecraft.version=1.19.2 minecraft.version=1.19.2
modName=Gimble modName=Gimbal
#fabric.loader.version=0.15.10 #fabric.loader.version=0.15.10
mavenArtifact=gimble mavenArtifact=gimbal
fabric.loader.version=0.14.0 fabric.loader.version=0.14.0

View file

@ -1,6 +1,24 @@
#
# Gimbal
# Copyright (C) 2024 moonleay
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

22
gradlew vendored
View file

@ -1,19 +1,21 @@
#!/bin/sh #!/bin/sh
# #
# Copyright © 2015-2021 the original authors. # Gimbal
# Copyright (C) 2024 moonleay
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # This program is free software: you can redistribute it and/or modify
# you may not use this file except in compliance with the License. # it under the terms of the GNU General Public License as published by
# You may obtain a copy of the License at # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# #
# https://www.apache.org/licenses/LICENSE-2.0 # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# #
# Unless required by applicable law or agreed to in writing, software # You should have received a copy of the GNU General Public License
# distributed under the License is distributed on an "AS IS" BASIS, # along with this program. If not, see <https://www.gnu.org/licenses/>.
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
############################################################################## ##############################################################################

View file

@ -1,3 +1,21 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pluginManagement { pluginManagement {
repositories { repositories {
maven { maven {

View file

@ -0,0 +1,43 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal
import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.networking.GimbalServer
import org.apache.logging.log4j.LogManager
internal object Main : ModInitializer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
override fun onInitialize() {
LOGGER.info("Initializing Gimbal on the common side...")
LOGGER.info("Registering packets...")
GimbalServer.registerPacketHandler()
LOGGER.info("Packets have been registered.")
LOGGER.info("Registering events...")
ServerPlayConnectionEvents.INIT.register(ServerPlayConnectionEvents.Init { handler, server ->
GimbalServer.notifyPlayerOfPolicy(handler.player)
})
LOGGER.info("Events have been registered.")
LOGGER.info("Gimbal has been initialized on the common side.")
LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
}
}

View file

@ -0,0 +1,67 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client
import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents
import net.fabricmc.loader.api.FabricLoader
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.client.config.ClientConfigHolder
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.KeybindingManager
import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar
import net.moonleay.gimbal.networking.GimbalClient
import org.apache.logging.log4j.LogManager
internal object ClientMain : ClientModInitializer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
lateinit var CONFIG: ClientConfigHolder
override fun onInitializeClient() {
LOGGER.info("Initializing Gimbal on the client side...")
KeybindingRegistrar.registerKeybindings()
this.registerEvents()
LOGGER.info("Registering packets...")
GimbalClient.registerPacketHandlers()
LOGGER.info("Packets have been registered.")
LOGGER.info("Loading client config.")
val gimbalConfigPath = FabricLoader.getInstance().configDir.resolve(BuildConstants.modId + "/client.json")
CONFIG = ClientConfigHolder(gimbalConfigPath)
LOGGER.info("Config has been loaded.")
LOGGER.info("Applying Config to client.")
ClientEditor.applyConfig(CONFIG.config)
LOGGER.info("Config has been applied.")
LOGGER.info("Gimbal has been initialized on the client side.")
}
private fun registerEvents() {
LOGGER.info("Registering client events...")
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
KeybindingManager.onClientTick(client)
})
ClientLoginConnectionEvents.INIT.register(ClientLoginConnectionEvents.Init { _, _ ->
ClientEditor.onConnectedToNewWorld() // Client is connecting to a new server, reset the editor
})
LOGGER.info("Client events have been registered.")
}
}

View file

@ -0,0 +1,79 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,33 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,28 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.config.enums
import kotlinx.serialization.Serializable
@Serializable
enum class HorizontalAnchor {
LEFT,
CENTER,
RIGHT,
}

View file

@ -0,0 +1,31 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,28 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,316 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.editor
import net.minecraft.client.MinecraftClient
import net.minecraft.text.Text
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.client.ClientMain
import net.moonleay.gimbal.client.config.GimbalClientConfig
import net.moonleay.gimbal.client.config.enums.HudOptions
import net.moonleay.gimbal.client.util.ChatUtil
import net.moonleay.gimbal.client.util.ToastType
import net.moonleay.gimbal.editor.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.state.GimbalServerState
import net.moonleay.gimbal.editor.state.mode.Capability
import net.moonleay.gimbal.editor.state.mode.Mode
import net.moonleay.gimbal.editor.state.mode.ModeModifier
import net.moonleay.gimbal.editor.util.EditorUtil
import net.moonleay.gimbal.networking.GimbalClient
import org.apache.logging.log4j.LogManager
object ClientEditor {
private var POLICY = GimbalPolicyType.NOT_PRESENT
private lateinit var CURRENT_MODE: Mode
private var TEMP_DISABLED_MODE = Mode.UNKNOWN
private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
private val TEMP_DISABLED_MODIFIERS = 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() {
POLICY = GimbalPolicyType.NOT_PRESENT
if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
TEMP_DISABLED_MODE =
CURRENT_MODE
}
CURRENT_MODE = Mode.INSERT
DISABLED_MODIFIERS_STORAGE.addAll(
CURRENT_MODE_MODIFIER
)
CURRENT_MODE_MODIFIER.clear()
}
fun onPolicyReceived(data: GimbalServerState, shouldUpdateServer: Boolean = true) {
POLICY = data.policyType
if (data.policyType == GimbalPolicyType.ALLOWED) {
if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
CURRENT_MODE =
TEMP_DISABLED_MODE
TEMP_DISABLED_MODE = Mode.UNKNOWN
}
CURRENT_MODE_MODIFIER.addAll(
DISABLED_MODIFIERS_STORAGE
)
DISABLED_MODIFIERS_STORAGE.clear()
onUpdated(shouldUpdateServer)
if (!shouldUpdateServer) {
val player = MinecraftClient.getInstance().player
if (player == null) {
LOGGER.warn("Player is null!") //FIXME: Fix player is null at world join!
return
}
ServerEditorManager.updateEditorState(
MinecraftClient.getInstance().player!!.uuid,
this.getClientState()
)
}
}
}
fun isAllowed(): Boolean {
return POLICY == GimbalPolicyType.ALLOWED
}
fun shouldClient(capability: Capability): Boolean {
return EditorUtil.shouldPlayer(
capability, EditorState(
CURRENT_MODE,
CURRENT_MODE_MODIFIER
)
)
}
fun isInNonDefaultMode(): Boolean {
return CURRENT_MODE != ClientMain.CONFIG.config.defaultMode
}
/*
* Send an updated player state to the server
* */
private fun updateServerState() {
val state = this.getClientState()
GimbalClient.sendStatePacket(state)
ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
}
/*
* Set the current mode
* */
fun setMode(mode: Mode) {
if (!isAllowed()) {
ChatUtil.showToastToSelf(
"Gimbal is disabled",
"You cannot change modes",
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
return
}
if (!MinecraftClient.getInstance().player!!.isCreative)
return
CURRENT_MODE = mode
onUpdated()
}
/*
* Toggle a mode modifier
* */
fun toggleModifier(mod: ModeModifier) {
if (!isAllowed()) {
ChatUtil.showToastToSelf(
"Gimbal is disabled",
"You cannot change modifiers",
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
return
}
if (!MinecraftClient.getInstance().player!!.isCreative)
return
if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
if (TEMP_DISABLED_MODIFIERS.contains(mod)) {
TEMP_DISABLED_MODIFIERS.remove(mod)
} else {
TEMP_DISABLED_MODIFIERS.add(mod)
}
}
else {
if (CURRENT_MODE_MODIFIER.contains(mod)) {
CURRENT_MODE_MODIFIER.remove(mod)
ChatUtil.showToastToSelf(
"Disabled ${mod.displayName}",
"[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
ToastType.TOGGLE, ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
} else {
CURRENT_MODE_MODIFIER.add(mod)
ChatUtil.showToastToSelf(
"Enabled ${mod.displayName}",
"[${this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER)}]",
ToastType.TOGGLE, ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
}
}
onUpdated()
}
private fun onUpdated(shouldUpdateServer: Boolean = true) {
CURRENT_MODE_MODIFIER.sortBy {
it.displayName
}
checkForIncompatibleModeModifiers(shouldUpdateServer)
}
/**
* This runs on Mode updated
*/
private fun checkForIncompatibleModeModifiers(shouldUpdateServer: Boolean = true) {
if (TEMP_DISABLED_MODIFIERS.size > 0) {
CURRENT_MODE_MODIFIER.addAll(
TEMP_DISABLED_MODIFIERS
)
TEMP_DISABLED_MODIFIERS.clear()
}
val incompatibleModeModifiers = CURRENT_MODE.incompatibleModifiers
for (mod in CURRENT_MODE_MODIFIER) {
if (incompatibleModeModifiers.contains(mod)) {
TEMP_DISABLED_MODIFIERS.add(mod)
}
}
for (mod in TEMP_DISABLED_MODIFIERS) {
if (CURRENT_MODE_MODIFIER.contains(mod)) { // This check is probably useless.
CURRENT_MODE_MODIFIER.remove(mod)
}
}
CURRENT_MODE_MODIFIER.sortBy {
it.displayName
}
// Update State
if (shouldUpdateServer)
updateServerState()
if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
ChatUtil.showToastToSelf(
"${CURRENT_MODE.displayName} Mode disabled",
getDisplayNameListAsString(TEMP_DISABLED_MODIFIERS),
ToastType.SYSTEM,
ClientMain.CONFIG.config,
MinecraftClient.getInstance()
)
}
}
private fun getDisplayNameListAsString(list: List<ModeModifier>): String {
if(list.isEmpty())
return ""
val sb = StringBuilder()
for (mod in list) {
sb.append(mod.displayName)
sb.append(", ")
}
return sb.toString().dropLast(2)
}
private fun getShortNameListAsString(list: List<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
* */
fun getModeDisplayText(config: GimbalClientConfig): Text {
val displayText = StringBuilder(CURRENT_MODE.displayName)
if (isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) {
when (config.guiSettings.hudOptions) {
HudOptions.ALL -> {
if (CURRENT_MODE_MODIFIER.size > 0) {
displayText.append(" [")
displayText.append(this.getDisplayNameListAsString(CURRENT_MODE_MODIFIER))
displayText.append("]")
}
return Text.of(displayText.toString())
}
HudOptions.NUMBER -> {
displayText.append(" (")
displayText.append(CURRENT_MODE_MODIFIER.size)
displayText.append(")")
return Text.of(displayText.toString())
}
HudOptions.INITIAL -> {
if (CURRENT_MODE_MODIFIER.size > 0) {
displayText.append(" [")
displayText.append(this.getShortNameListAsString(CURRENT_MODE_MODIFIER))
displayText.append("]")
}
return Text.of(displayText.toString())
}
HudOptions.ONLY_MODE -> return Text.of(displayText.toString())
}
}
return Text.of("[GIMBAL DISABLED]")
}
fun getCurrentColor(): Int {
return CURRENT_MODE.color
}
fun getClientState(): EditorState {
return EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
}
}

View file

@ -0,0 +1,43 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl
import net.minecraft.client.MinecraftClient
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
object KeybindingManager {
private val shortcuts = mutableListOf<GimbalShortcut>()
/**
* Register a shortcut. This will also register the keybinding.
* */
fun registerShortcut(shortcut: GimbalShortcut) {
shortcuts.add(shortcut)
KeyBindingRegistryImpl.registerKeyBinding(shortcut.keyBinding)
}
fun onClientTick(client: MinecraftClient){
// Sadly, this cannot be done without iterating over all shortcuts :madge:
for (shortcut in shortcuts)
if (shortcut.keyBinding.wasPressed())
shortcut.onPressed(client)
}
}

View file

@ -1,17 +1,36 @@
package net.moonleay.gimble.client.keybindings /*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings
import net.minecraft.client.option.KeyBinding import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil import net.minecraft.client.util.InputUtil
import net.moonleay.gimble.build.BuildConstants import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimble.client.keybindings.impl.editormode.EnableInsertModeShortcut import net.moonleay.gimbal.client.keybindings.impl.editormode.EnableInsertModeShortcut
import net.moonleay.gimble.client.keybindings.impl.editormode.EnableReplaceModeShortcut import net.moonleay.gimbal.client.keybindings.impl.editormode.EnableReplaceModeShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleNoUpdatesModifierShortcut import net.moonleay.gimbal.client.keybindings.impl.editormodemodifier.ToggleNoUpdatesModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.gamemode.CreativeModeShortcut import net.moonleay.gimbal.client.keybindings.impl.gamemode.CreativeModeShortcut
import net.moonleay.gimble.client.keybindings.impl.gamemode.SpectatorModeShortcut import net.moonleay.gimbal.client.keybindings.impl.gamemode.SpectatorModeShortcut
import net.moonleay.gimble.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
@ -29,28 +48,28 @@ object KeybindingRegistrar {
private fun registerSetEditorModeModifierKeybindings() { private fun registerSetEditorModeModifierKeybindings() {
val toggleBulldozerModifierShortcut = KeyBinding( val toggleBulldozerModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.bulldozer", TranslationKeys.Keybindings.Binding.Editor.Modifier.BULLDOZER,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier" TranslationKeys.Keybindings.Category.Editor.MODIFIER
) )
val toggleForcePlaceModifierShortcut = KeyBinding( val toggleForcePlaceModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.forceplace", TranslationKeys.Keybindings.Binding.Editor.Modifier.FORCE_PLACE,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier" TranslationKeys.Keybindings.Category.Editor.MODIFIER
) )
val toggleNoUpdatesModifierShortcut = KeyBinding( val toggleNoUpdatesModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noupdates", TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_UPDATES,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier" TranslationKeys.Keybindings.Category.Editor.MODIFIER
) )
val toggleNoClipModifierShortcut = KeyBinding( val toggleNoClipModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noclip", TranslationKeys.Keybindings.Binding.Editor.Modifier.NO_CLIP,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier" TranslationKeys.Keybindings.Category.Editor.MODIFIER
) )
KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut)) KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut))
@ -61,22 +80,22 @@ object KeybindingRegistrar {
private fun registerSetEditorModeKeybindings() { private fun registerSetEditorModeKeybindings() {
val insertKeyBinding = KeyBinding( val insertKeyBinding = KeyBinding(
"gimble.key.editor.mode.insert", TranslationKeys.Keybindings.Binding.Editor.Mode.INSERT,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_I, GLFW.GLFW_KEY_I,
"gimble.category.editormode" TranslationKeys.Keybindings.Category.Editor.MODE
) )
val replaceKeyBinding = KeyBinding( val replaceKeyBinding = KeyBinding(
"gimble.key.editor.mode.replace", TranslationKeys.Keybindings.Binding.Editor.Mode.REPLACE,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_R, GLFW.GLFW_KEY_R,
"gimble.category.editormode" TranslationKeys.Keybindings.Category.Editor.MODE
) )
// val visualKeyBinding = KeyBinding( // val visualKeyBinding = KeyBinding(
// "gimble.key.editor.mode.visual", // "gimbal.key.editor.mode.visual",
// InputUtil.Type.KEYSYM, // InputUtil.Type.KEYSYM,
// GLFW.GLFW_KEY_V, // GLFW.GLFW_KEY_V,
// "gimble.category.editormode" // "gimbal.category.editormode"
// ) // )
KeybindingManager.registerShortcut(EnableInsertModeShortcut(insertKeyBinding)) KeybindingManager.registerShortcut(EnableInsertModeShortcut(insertKeyBinding))
KeybindingManager.registerShortcut(EnableReplaceModeShortcut(replaceKeyBinding)) KeybindingManager.registerShortcut(EnableReplaceModeShortcut(replaceKeyBinding))
@ -85,22 +104,22 @@ object KeybindingRegistrar {
private fun registerSetGameModeKeybindings() { private fun registerSetGameModeKeybindings() {
val survivalKeyBinding = KeyBinding( val survivalKeyBinding = KeyBinding(
"gimble.key.game.mode.survival", TranslationKeys.Keybindings.Binding.Game.Mode.SURVIVAL,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.gamemode" TranslationKeys.Keybindings.Category.Game.GAMEMODE
) )
val creativeKeyBinding = KeyBinding( val creativeKeyBinding = KeyBinding(
"gimble.key.game.mode.creative", TranslationKeys.Keybindings.Binding.Game.Mode.CREATIVE,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.gamemode" TranslationKeys.Keybindings.Category.Game.GAMEMODE
) )
val spectatorKeyBinding = KeyBinding( val spectatorKeyBinding = KeyBinding(
"gimble.key.game.mode.spectator", TranslationKeys.Keybindings.Binding.Game.Mode.SPECTATOR,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN, GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.gamemode" TranslationKeys.Keybindings.Category.Game.GAMEMODE
) )
KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding)) KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding))
KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding)) KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding))

View file

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
abstract class GimbalShortcut(val keyBinding: KeyBinding) {
abstract fun onPressed(client: MinecraftClient)
}

View file

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.Mode
class EnableInsertModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.INSERT)
}
}

View file

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.Mode
class EnableReplaceModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.REPLACE)
}
}

View file

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.Mode
class EnableVisualModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.VISUAL)
}
}

View file

@ -0,0 +1,31 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.ModeModifier
class ToggleBulldozerModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.BULLDOZER)
}
}

View file

@ -0,0 +1,31 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.ModeModifier
class ToggleForcePlaceModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.FORCE_PLACE)
}
}

View file

@ -0,0 +1,31 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.ModeModifier
class ToggleNoClipModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.NO_CLIP)
}
}

View file

@ -0,0 +1,31 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.editor.state.mode.ModeModifier
class ToggleNoUpdatesModifierShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.NO_UPDATES)
}
}

View file

@ -0,0 +1,30 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.client.util.ChatUtil
class CreativeModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode creative", client, false)
}
}

View file

@ -0,0 +1,30 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.client.util.ChatUtil
class SpectatorModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode spectator", client, false)
}
}

View file

@ -0,0 +1,32 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimbal.client.keybindings.impl.GimbalShortcut
import net.moonleay.gimbal.client.util.ChatUtil
class SurvivalModeShortcut(key: KeyBinding) : GimbalShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode survival", client, false)
}
}

View file

@ -0,0 +1,151 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,290 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -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.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

@ -0,0 +1,54 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.util
import net.minecraft.client.MinecraftClient
import net.minecraft.client.toast.SystemToast
import net.minecraft.text.Text
import net.moonleay.gimbal.client.config.GimbalClientConfig
object ChatUtil {
/**
* Note: command arg should contain "/" at the beginning.
* */
fun sendCommand(command: String, client: MinecraftClient, addToHistory: Boolean = true): Boolean {
if (addToHistory) {
client.inGameHud.chatHud.addToMessageHistory(command)
}
return client.player?.sendCommand(command.substring(1))?: false
}
fun addToChatHistory(message: String, client: MinecraftClient) {
client.inGameHud.chatHud.addMessage(Text.of(message))
}
fun showToastToSelf(
title: String,
description: String,
type: ToastType,
config: GimbalClientConfig,
client: MinecraftClient,
) {
if (!config.toastSettings.allowedTypes.contains(type))
return
val toast = SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.of(title), Text.of(description))
client.toastManager.add(toast)
}
}

View file

@ -0,0 +1,44 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,24 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.client.util
enum class ToastType {
TOGGLE,
SYSTEM,
}

View file

@ -0,0 +1,71 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,28 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.constants
import net.minecraft.util.Identifier
import net.moonleay.gimbal.build.BuildConstants
object PacketIDs {
val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
val GIMBAL_POLICY_PACKET_ID = Identifier(BuildConstants.modId, "gimbal_policy")
}

View file

@ -0,0 +1,23 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.constants
object PermissionIDs {
const val GIMBAL_USAGE_PERMISSION = "gimbal.use"
}

View file

@ -0,0 +1,127 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,33 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.datagen
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
import net.moonleay.gimbal.build.BuildConstants
import org.apache.logging.log4j.LogManager
internal class DataGenerator : DataGeneratorEntrypoint {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
LOGGER.info("Starting Data Generation")
fabricDataGenerator.addProvider(EnUsLanguageProvider(fabricDataGenerator))
}
}

View file

@ -0,0 +1,96 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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,55 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.mode.Capability
import net.moonleay.gimbal.editor.util.EditorUtil
import org.apache.logging.log4j.LogManager
import java.util.*
object ServerEditorManager {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
private val STATEMAP = mutableMapOf<UUID, EditorState>()
fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
STATEMAP[playerUUID] = editorState
LOGGER.debug("{}: {} with {}", playerUUID, editorState.editorMode, editorState.editorModifier)
}
/*
* Check if a player should be able to perform an action
* */
fun shouldPlayer(playerUUID: UUID, capability: Capability): Boolean {
if (!STATEMAP.containsKey(playerUUID))
return false
val state = STATEMAP[playerUUID]!!
return EditorUtil.shouldPlayer(capability, state)
}
// fun playerHasModifier(playerUUID: UUID, modifier: ModeModifier): Boolean {
// if (!STATEMAP.containsKey(playerUUID))
// return false
// return STATEMAP[playerUUID]!!.editorModifier.contains(modifier) ?: false
// }
}

View file

@ -0,0 +1,29 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state
import kotlinx.serialization.Serializable
import net.moonleay.gimbal.editor.state.mode.Mode
import net.moonleay.gimbal.editor.state.mode.ModeModifier
@Serializable
data class EditorState(
var editorMode: Mode,
var editorModifier: MutableList<ModeModifier>,
)

View file

@ -0,0 +1,28 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state
import kotlinx.serialization.Serializable
@Serializable
enum class GimbalPolicyType {
ALLOWED,
DENIED,
NOT_PRESENT,
}

View file

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,29 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state.mode
enum class Capability {
INSERT,
REPLACE,
CAN_INTERACT,
NO_CLIP,
FORCE_PLACE,
NO_UPDATES,
BULLDOZER,
}

View file

@ -0,0 +1,28 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state.mode
enum class Mode(val displayName: String, val color: Int, val hidden: Boolean, val incompatibleModifiers: List<ModeModifier>){
UNKNOWN("UNKNOWN", 0x000000, true, listOf()), // Unknown mode. This mode cannot be entered
NORMAL("NORMAL", 0x90a959, false, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
INSERT("INSERT", 0xf4bf75, false, listOf()), // Place and break blocks
REPLACE("REPLACE", 0xac4242, false, listOf(ModeModifier.NO_UPDATES)), // Replace blocks
// Add hidden modes after this comment
VISUAL("VISUAL", 0x6a9fb5, true, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
}

View file

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.state.mode
enum class ModeModifier(val displayName: String, val shortName: String) {
// NONE("None"), // No Modifiers - default behavior
NO_UPDATES("NO UPDATES", "NU"), // Do not update blocks when placing
BULLDOZER("BULLDOZER", "BLR"), // Break blocks fast
FORCE_PLACE("FORCE", "FP"), // Ignore block placement restrictions
NO_CLIP("NO CLIP", "NC"), // Do not collide with blocks
}

View file

@ -1,9 +1,28 @@
package net.moonleay.gimble.editor.util /*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.util
import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.mode.Capability
import net.moonleay.gimbal.editor.state.mode.Mode
import net.moonleay.gimbal.editor.state.mode.ModeModifier
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.state.mode.Capability
import net.moonleay.gimble.editor.state.mode.Mode
import net.moonleay.gimble.editor.state.mode.ModeModifier
object EditorUtil { object EditorUtil {

View file

@ -0,0 +1,27 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.editor.util
import kotlinx.serialization.Serializable
import net.moonleay.gimbal.editor.state.GimbalPolicyType
@Serializable
data class GimbalPolicy(
val policy: GimbalPolicyType,
)

View file

@ -0,0 +1,84 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
public abstract class BulldozerMixin {
@Mixin(MinecraftClient.class)
public static abstract class MinecraftClientMixin {
@Shadow
@Nullable
public ClientPlayerEntity player;
@Shadow
protected int attackCooldown;
@Inject(method = "doAttack", at = @At(value = "HEAD"))
private void func(CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
return;
}
this.attackCooldown = 0;
}
@Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
private void func2(boolean breaking, CallbackInfo ci) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
return;
}
this.attackCooldown = 0;
}
}
@Mixin(ClientPlayerInteractionManager.class)
public static abstract class ClientPlayerInteractionManagerMixin {
@Shadow
private int blockBreakingCooldown;
@Shadow
@Final
private MinecraftClient client;
@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
return;
}
this.blockBreakingCooldown = 0;
}
}
}

View file

@ -1,10 +1,28 @@
package net.moonleay.gimble.mixin; /*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.moonleay.gimble.editor.ServerEditorManager; import net.moonleay.gimbal.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
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;

View file

@ -0,0 +1,74 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.moonleay.gimbal.client.ClientMain;
import net.moonleay.gimbal.client.config.GimbalGuiSettings;
import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.client.util.screen.ScreenUtil;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InGameHud.class)
public abstract class HudMixin {
@Shadow @Final private MinecraftClient client;
@Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
private void render(MatrixStack matrices, CallbackInfo ci) {
TextRenderer tr = this.client.textRenderer;
GimbalGuiSettings conf = ClientMain.CONFIG.getConfig().getGuiSettings();
if (!conf.getShowHud())
return;
int scaleFactor = this.client.getWindow()
.calculateScaleFactor(
this.client.options.getGuiScale().getValue(),
this.client.forcesUnicodeFont()
);
Text displayText = ClientEditor.INSTANCE.getModeDisplayText(ClientMain.CONFIG.getConfig());
tr.drawWithShadow(
matrices,
displayText,
ScreenUtil.INSTANCE.getXForAnchor(
ScreenUtil.INSTANCE.getReal(
this.client.getWindow().getWidth(),
conf.getOffset().getScaledX() / scaleFactor),
conf.getHorizontalAnchor(),
this.client.textRenderer.getWidth(displayText)
),
ScreenUtil.INSTANCE.getYForAnchor(
ScreenUtil.INSTANCE.getReal(
this.client.getWindow().getHeight(),
conf.getOffset().getScaledY() / scaleFactor),
conf.getVerticalAnchor(),
this.client.textRenderer.fontHeight
),
ClientEditor.INSTANCE.getCurrentColor()
);
}
}

View file

@ -1,11 +1,29 @@
package net.moonleay.gimble.mixin; /*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.moonleay.gimble.editor.ServerEditorManager; import net.moonleay.gimbal.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.Capability; import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
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;

View file

@ -0,0 +1,106 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World;
import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimbal.editor.ServerEditorManager;
import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.UUID;
public abstract class NoClipMixin {
@Mixin(PlayerEntity.class) // Serverside, allows clipping
public static abstract class PlayerEntityMixin extends LivingEntity {
protected PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
super(entityType, world);
}
@Shadow
public abstract GameProfile getGameProfile();
@Shadow
public abstract PlayerAbilities getAbilities();
@Shadow
public abstract boolean isCreative();
@Inject(method = "tick", at = @At(value = "FIELD",
target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER)
)
private void enoClip(CallbackInfo ci) {
if (!this.isCreative())
return;
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) {
return; // NoClip is not enabled
}
if (!this.getAbilities().flying) {
return;
}
// Enable NoClip
this.noClip = true;
}
@Inject(method = "updatePose", at = @At("HEAD"))
private void onUpdatePose(CallbackInfo ci) {
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
return; // NoClip is not enabled
if (!this.getAbilities().flying)
return;
// Force standing pose in NoClip mode
this.setPose(EntityPose.STANDING);
}
}
@Mixin(Camera.class) // Clientside, fixes camera
public static abstract class CameraMixin {
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<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

@ -1,11 +1,29 @@
package net.moonleay.gimble.mixin; /*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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.gimble.client.editor.ClientEditor; import net.moonleay.gimbal.client.ClientMain;
import net.moonleay.gimble.editor.state.mode.Capability; import net.moonleay.gimbal.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Mode; import net.moonleay.gimbal.editor.state.mode.Capability;
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;
@ -25,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 setNormalMode(boolean pause, CallbackInfo ci) { private void setDefaultMode(boolean pause, CallbackInfo ci) {
if (ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) { if (ClientMain.CONFIG.getConfig().getShouldEscResetMode() && 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(Mode.NORMAL); ClientEditor.INSTANCE.setMode(ClientMain.CONFIG.getConfig().getDefaultMode());
ci.cancel(); ci.cancel();
} }
} }

View file

@ -0,0 +1,45 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket;
import net.moonleay.gimbal.client.ClientMain;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayNetworkHandler.class)
public abstract class PlayerFlySpeedMixin {
@Shadow
@Final
private MinecraftClient client;
@Inject(method = "onPlayerAbilities", at = @At(value = "RETURN"))
private void func(PlayerAbilitiesS2CPacket packet, CallbackInfo ci) {
this.client.player.getAbilities().setFlySpeed((ClientMain.CONFIG.getConfig().getPlayerFlySpeed() / 100) * 0.05f);
//client!!.player!!.abilities.flySpeed = (this.playerFlySpeed / 100) * 0.05f
}
}

View file

@ -0,0 +1,104 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.state.property.Property;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.moonleay.gimbal.editor.ServerEditorManager;
import net.moonleay.gimbal.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.UUID;
public abstract class ReplaceModeMixin {
@Mixin(ItemPlacementContext.class)
public static abstract class ItemPlacementContextMixin extends ItemUsageContext {
@Shadow
protected boolean canReplaceExisting;
@Mutable
@Shadow
@Final
private BlockPos placementPos;
public ItemPlacementContextMixin(PlayerEntity player, Hand hand, BlockHitResult hit) {
super(player, hand, hit);
}
@Inject(method = "<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"))
private void func(World world, PlayerEntity playerEntity, Hand hand, ItemStack itemStack, BlockHitResult blockHitResult, CallbackInfo ci) {
if (playerEntity == null)
return;
UUID id = playerEntity.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE))
return;
this.canReplaceExisting = true;
this.placementPos = blockHitResult.getBlockPos();
}
}
@Mixin(BlockItem.class)
public static abstract class BlockItemMixin extends Item {
public BlockItemMixin(Settings settings) {
super(settings);
}
@Shadow
protected abstract boolean place(ItemPlacementContext context, BlockState state);
@Redirect(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z"))
private boolean func(BlockItem instance, ItemPlacementContext context, BlockState state) {
if (context.getPlayer() == null)
return this.place(context, state);
UUID id = context.getPlayer().getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE))
return this.place(context, state);
BlockState oldState = context.getWorld().getBlockState(context.getBlockPos());
return this.place(context, getTargetBlockState(oldState, instance.getBlock().getDefaultState()));
}
@Unique
public BlockState getTargetBlockState(BlockState oldState, BlockState newBlock) {
var oldManager = oldState.getBlock().getStateManager();
var newManager = newBlock.getBlock().getStateManager();
for (var prop : oldManager.getProperties()) {
var matchingProp = newManager.getProperty(prop.getName());
if (matchingProp != null) {
//noinspection rawtypes,unchecked
newBlock = newBlock.with((Property) matchingProp, oldState.get(matchingProp));
}
}
return newBlock;
}
}
}

View file

@ -0,0 +1,104 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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

@ -0,0 +1,70 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.networking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.minecraft.network.PacketByteBuf
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.constants.PacketIDs
import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.state.GimbalServerState
object GimbalClient {
fun registerPacketHandlers() {
ClientPlayNetworking.registerGlobalReceiver(PacketIDs.GIMBAL_POLICY_PACKET_ID) { _, _, buf, handler ->
val state = this.getServerState(buf)
val isUsable = this.isGimbalUsable(state)
if (isUsable) {
val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(ClientEditor.getClientState()))
handler.sendPacket(PacketIDs.UPDATE_EDITOR_STATE_ID, buf)
}
ClientEditor.onPolicyReceived(state, false)
}
}
@OptIn(ExperimentalSerializationApi::class)
private fun getServerState(buf: PacketByteBuf): GimbalServerState {
val serverState = Cbor.decodeFromByteArray<GimbalServerState>(buf.readByteArray())
return serverState
}
private fun isGimbalUsable(state: GimbalServerState): Boolean {
return state.policyType == GimbalPolicyType.ALLOWED && state.protocolVersion.toString() == BuildConstants.protocolVersion
}
@OptIn(ExperimentalSerializationApi::class)
private fun createStatePacket(state: EditorState): PacketByteBuf {
val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state))
return buf
}
fun sendStatePacket(state: EditorState) {
ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, createStatePacket(state))
}
}

View file

@ -0,0 +1,74 @@
/*
* Gimbal
* Copyright (C) 2024 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.gimbal.networking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import me.lucko.fabric.api.permissions.v0.Permissions
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.constants.PacketIDs
import net.moonleay.gimbal.constants.PermissionIDs
import net.moonleay.gimbal.editor.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.state.GimbalServerState
import org.apache.logging.log4j.LogManager
object GimbalServer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
fun registerPacketHandler() {
ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
{ _, player, _, buf, _ ->
handleStateUpdate(player, buf)
}
}
@OptIn(ExperimentalSerializationApi::class)
fun notifyPlayerOfPolicy(player: ServerPlayerEntity) {
LOGGER.info("Sending policy to " + player.name.string)
val buf = PacketByteBufs.create()
buf.writeByteArray(
Cbor.encodeToByteArray(
GimbalServerState(
BuildConstants.protocolVersion.toInt(),
if (this.isPlayerAllowedToUseGimbal(player)) GimbalPolicyType.ALLOWED else GimbalPolicyType.DENIED
)
)
)
ServerPlayNetworking.send(player, PacketIDs.GIMBAL_POLICY_PACKET_ID, buf)
}
private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
val state = Cbor.decodeFromByteArray<EditorState>(buf.readByteArray())
ServerEditorManager.updateEditorState(player.uuid, state)
// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
}
private fun isPlayerAllowedToUseGimbal(player: ServerPlayerEntity): Boolean {
return player.hasPermissionLevel(2) || Permissions.check(player, PermissionIDs.GIMBAL_USAGE_PERMISSION)
}
}

View file

@ -1,19 +0,0 @@
package net.moonleay.gimble
import net.moonleay.gimble.build.BuildConstants
import net.fabricmc.api.ModInitializer
import net.moonleay.gimble.networking.GimbleServer
import org.apache.logging.log4j.LogManager
internal object Main : ModInitializer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
override fun onInitialize() {
LOGGER.info("Initializing Gimble on the common side...")
LOGGER.info("Registering packets...")
GimbleServer.registerPacketHandler()
LOGGER.info("Packets have been registered.")
LOGGER.info("Gimble has been initialized on the common side.")
LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
}
}

View file

@ -1,33 +0,0 @@
package net.moonleay.gimble.client
import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import net.moonleay.gimble.build.BuildConstants
import net.moonleay.gimble.client.keybindings.KeybindingManager
import net.moonleay.gimble.client.keybindings.KeybindingRegistrar
import net.moonleay.gimble.networking.GimbleClient
import org.apache.logging.log4j.LogManager
internal object ClientMain : ClientModInitializer {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
override fun onInitializeClient() {
LOGGER.info("Initializing Gimble on the client side...")
KeybindingRegistrar.registerKeybindings()
registerEvents()
LOGGER.info("Registering packets...")
GimbleClient.registerPacketHandlers()
LOGGER.info("Packets have been registered.")
LOGGER.info("Gimble has been initialized on the client side.")
}
private fun registerEvents() {
LOGGER.info("Registering client events...")
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
KeybindingManager.onClientTick(client)
})
LOGGER.info("Client events have been registered.")
}
}

View file

@ -1,193 +0,0 @@
package net.moonleay.gimble.client.editor
import net.minecraft.client.MinecraftClient
import net.minecraft.text.Text
import net.moonleay.gimble.client.util.ChatUtil
import net.moonleay.gimble.editor.ServerEditorManager
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.state.GimblePolicyType
import net.moonleay.gimble.editor.state.mode.Capability
import net.moonleay.gimble.editor.state.mode.Mode
import net.moonleay.gimble.editor.state.mode.ModeModifier
import net.moonleay.gimble.editor.util.EditorUtil
import net.moonleay.gimble.editor.util.GimblePolicy
import net.moonleay.gimble.networking.GimbleClient
object ClientEditor {
private var POLICY = GimblePolicyType.NOT_PRESENT
private var CURRENT_MODE = Mode.NORMAL
private var TEMP_DISABLED_MODE = Mode.UNKNOWN
private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>()
private val DISABLED_MODIFIERS_STORAGE = mutableListOf<ModeModifier>()
fun onConnectedToNewWorld() {
POLICY = GimblePolicyType.NOT_PRESENT
GimbleClient.checkIfServerHasGimble(EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER))
if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
TEMP_DISABLED_MODE = CURRENT_MODE
}
CURRENT_MODE = Mode.INSERT
DISABLED_MODIFIERS_STORAGE.addAll(CURRENT_MODE_MODIFIER)
CURRENT_MODE_MODIFIER.clear()
}
fun onAllowedCheck(data: GimblePolicy) {
POLICY = data.policy
if (data.policy == GimblePolicyType.ALLOWED) {
if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
CURRENT_MODE = TEMP_DISABLED_MODE
TEMP_DISABLED_MODE = Mode.UNKNOWN
}
CURRENT_MODE_MODIFIER.addAll(DISABLED_MODIFIERS_STORAGE)
DISABLED_MODIFIERS_STORAGE.clear()
this.onUpdated()
}
}
fun isAllowed(): Boolean {
return POLICY == GimblePolicyType.ALLOWED
}
fun shouldClient(capability: Capability): Boolean {
return EditorUtil.shouldPlayer(capability, EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER))
}
fun isInNonDefaultMode(): Boolean {
return CURRENT_MODE != Mode.NORMAL
}
/*
* Send an updated player state to the server
* */
private fun updateServerState() {
val state = EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
GimbleClient.sendEditorState(state)
ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
}
/*
* Set the current mode
* */
fun setMode(mode: Mode) {
if (!isAllowed()) {
ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modes", MinecraftClient.getInstance())
return
}
if (!MinecraftClient.getInstance().player!!.isCreative)
return
CURRENT_MODE = mode
this.onUpdated()
}
/*
* Toggle a mode modifier
* */
fun toggleModifier(mod: ModeModifier) {
if (!isAllowed()) {
ChatUtil.showToastToSelf("Gimble is disabled", "You cannot change modifiers", MinecraftClient.getInstance())
return
}
if (!MinecraftClient.getInstance().player!!.isCreative)
return
if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
if (TEMP_DISABLED_MODIFIERS.contains(mod))
TEMP_DISABLED_MODIFIERS.remove(mod)
else
TEMP_DISABLED_MODIFIERS.add(mod)
}
else {
if (CURRENT_MODE_MODIFIER.contains(mod))
CURRENT_MODE_MODIFIER.remove(mod)
else
CURRENT_MODE_MODIFIER.add(mod)
}
this.onUpdated()
}
private fun onUpdated() {
CURRENT_MODE_MODIFIER.sortBy {
it.displayName
}
this.checkForIncompatibleModeModifiers()
}
/**
* This runs on Mode updated
*/
private fun checkForIncompatibleModeModifiers() {
if (TEMP_DISABLED_MODIFIERS.size > 0) {
CURRENT_MODE_MODIFIER.addAll(
TEMP_DISABLED_MODIFIERS
)
TEMP_DISABLED_MODIFIERS.clear()
}
val incompatibleModeModifiers = CURRENT_MODE.incompatibleModifiers
for (mod in CURRENT_MODE_MODIFIER) {
if (incompatibleModeModifiers.contains(mod)) {
TEMP_DISABLED_MODIFIERS.add(mod)
}
}
for (mod in TEMP_DISABLED_MODIFIERS) {
if (CURRENT_MODE_MODIFIER.contains(mod)) { // This check is probably useless.
CURRENT_MODE_MODIFIER.remove(mod)
}
}
CURRENT_MODE_MODIFIER.sortBy {
it.displayName
}
// Update State
this.updateServerState()
if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
ChatUtil.showToastToSelf("${CURRENT_MODE.displayName} Mode disabled", getListAsString(TEMP_DISABLED_MODIFIERS), MinecraftClient.getInstance())
}
}
private fun getListAsString(list: List<ModeModifier>): String{
if(list.isEmpty())
return "Empty list"
val sb = StringBuilder()
for (mod in list) {
sb.append(mod.displayName)
sb.append(", ")
}
return sb.toString().dropLast(2)
}
/*
* Get the display text to display in the HUD
* */
fun getModeDisplayText(): Text {
val displayText = StringBuilder(CURRENT_MODE.displayName)
if (CURRENT_MODE_MODIFIER.isNotEmpty() && this.isAllowed() && MinecraftClient.getInstance().player?.isCreative == true) {
displayText.append(" [")
for (i in CURRENT_MODE_MODIFIER.indices) {
displayText.append(CURRENT_MODE_MODIFIER[i].displayName)
if (i != CURRENT_MODE_MODIFIER.size - 1) {
displayText.append(", ")
}
}
displayText.append("]")
} else if (!this.isAllowed() || !MinecraftClient.getInstance().player?.isCreative!!) {
displayText.clear()
displayText.append("[GIMBLE DISABLED]")
}
return Text.of(displayText.toString())
}
fun getCurrentColor(): Int {
return CURRENT_MODE.color
}
}

View file

@ -1,25 +0,0 @@
package net.moonleay.gimble.client.keybindings
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl
import net.minecraft.client.MinecraftClient
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
object KeybindingManager {
private val shortcuts = mutableListOf<GimbleShortcut>()
/**
* Register a shortcut. This will also register the keybinding.
* */
fun registerShortcut(shortcut: GimbleShortcut) {
shortcuts.add(shortcut)
KeyBindingRegistryImpl.registerKeyBinding(shortcut.keyBinding)
}
fun onClientTick(client: MinecraftClient){
// Sadly, this cannot be done without iterating over all shortcuts :madge:
for (shortcut in shortcuts)
if (shortcut.keyBinding.wasPressed())
shortcut.onPressed(client)
}
}

View file

@ -1,9 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
abstract class GimbleShortcut(val keyBinding: KeyBinding) {
abstract fun onPressed(client: MinecraftClient)
}

View file

@ -1,14 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.Mode
class EnableInsertModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.INSERT)
}
}

View file

@ -1,14 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.Mode
class EnableReplaceModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.REPLACE)
}
}

View file

@ -1,14 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.Mode
class EnableVisualModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.setMode(Mode.VISUAL)
}
}

View file

@ -1,13 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.ModeModifier
class ToggleBulldozerModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.BULLDOZER)
}
}

View file

@ -1,13 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.ModeModifier
class ToggleForcePlaceModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.FORCE_PLACE)
}
}

View file

@ -1,13 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.ModeModifier
class ToggleNoClipModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.NO_CLIP)
}
}

View file

@ -1,13 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.editor.state.mode.ModeModifier
class ToggleNoUpdatesModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.toggleModifier(ModeModifier.NO_UPDATES)
}
}

View file

@ -1,12 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.client.util.ChatUtil
class CreativeModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode creative", client, false)
}
}

View file

@ -1,12 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.client.util.ChatUtil
class SpectatorModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode spectator", client, false)
}
}

View file

@ -1,14 +0,0 @@
package net.moonleay.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.gimble.client.util.ChatUtil
class SurvivalModeShortcut(key: KeyBinding) : GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode survival", client, false)
}
}

View file

@ -1,26 +0,0 @@
package net.moonleay.gimble.client.util
import net.minecraft.client.MinecraftClient
import net.minecraft.client.toast.SystemToast
import net.minecraft.text.Text
object ChatUtil {
/**
* Note: command arg should contain "/" at the beginning.
* */
fun sendCommand(command: String, client: MinecraftClient, addToHistory: Boolean = true): Boolean {
if (addToHistory) {
client.inGameHud.chatHud.addToMessageHistory(command)
}
return client.player?.sendCommand(command.substring(1))?: false
}
fun addToChatHistory(message: String, client: MinecraftClient) {
client.inGameHud.chatHud.addMessage(Text.of(message))
}
fun showToastToSelf(title: String, description: String, client: MinecraftClient) {
val toast = SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.of(title), Text.of(description))
client.toastManager.add(toast)
}
}

View file

@ -1,15 +0,0 @@
package net.moonleay.gimble.datagen
import net.moonleay.gimble.build.BuildConstants
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
import org.apache.logging.log4j.LogManager
internal class DataGenerator : DataGeneratorEntrypoint {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
LOGGER.info("Starting Data Generation")
fabricDataGenerator.addProvider(En_us_GimbleLanguageProvider(fabricDataGenerator))
}
}

View file

@ -1,32 +0,0 @@
package net.moonleay.gimble.datagen
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
class En_us_GimbleLanguageProvider(dataGenerator: FabricDataGenerator?) :
FabricLanguageProvider(dataGenerator, "en_us") {
override fun generateTranslations(translationBuilder: TranslationBuilder?) {
if (translationBuilder == null) return
// Editor modes
translationBuilder.add("gimble.category.editormode", "Editor Modes")
translationBuilder.add("gimble.key.editor.mode.insert", "Enter Insert Mode")
translationBuilder.add("gimble.key.editor.mode.replace", "Enter Replace Mode")
translationBuilder.add("gimble.key.editor.mode.visual", "Enter Visual Mode")
// Editor mode modifiers
translationBuilder.add("gimble.category.editormodifier", "Editor Mode Modifiers")
translationBuilder.add("gimble.key.editor.modifier.bulldozer", "Toggle Bulldozer Modifier")
translationBuilder.add("gimble.key.editor.modifier.forceplace", "Toggle Force Place Modifier")
translationBuilder.add("gimble.key.editor.modifier.noupdates", "Toggle No Updates Modifier")
translationBuilder.add("gimble.key.editor.modifier.noclip", "Toggle No Clip Modifier")
// Game mode
translationBuilder.add("gimble.category.gamemode", "Game Mode")
translationBuilder.add("gimble.key.game.mode.survival", "Enable Survival Mode")
translationBuilder.add("gimble.key.game.mode.creative", "Enable Creative Mode")
translationBuilder.add("gimble.key.game.mode.spectator", "Enable Spectator Mode")
}
}

View file

@ -1,37 +0,0 @@
package net.moonleay.gimble.editor
import net.moonleay.gimble.build.BuildConstants
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.state.mode.Capability
import net.moonleay.gimble.editor.util.EditorUtil
import org.apache.logging.log4j.LogManager
import java.util.*
object ServerEditorManager {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
private val STATEMAP = mutableMapOf<UUID, EditorState>()
fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
STATEMAP[playerUUID] = editorState
LOGGER.info("$playerUUID: ${editorState.editorMode} with ${editorState.editorModifier}")
}
/*
* Check if a player should be able to perform an action
* */
fun shouldPlayer(playerUUID: UUID, capability: Capability): Boolean {
if (!STATEMAP.containsKey(playerUUID))
return false
val state = STATEMAP[playerUUID]!!
return EditorUtil.shouldPlayer(capability, state)
}
// fun playerHasModifier(playerUUID: UUID, modifier: ModeModifier): Boolean {
// if (!STATEMAP.containsKey(playerUUID))
// return false
// return STATEMAP[playerUUID]!!.editorModifier.contains(modifier) ?: false
// }
}

View file

@ -1,11 +0,0 @@
package net.moonleay.gimble.editor.state
import kotlinx.serialization.Serializable
import net.moonleay.gimble.editor.state.mode.Mode
import net.moonleay.gimble.editor.state.mode.ModeModifier
@Serializable
data class EditorState(
var editorMode: Mode,
var editorModifier: MutableList<ModeModifier>,
)

View file

@ -1,7 +0,0 @@
package net.moonleay.gimble.editor.state
enum class GimblePolicyType {
ALLOWED,
DENIED,
NOT_PRESENT
}

View file

@ -1,11 +0,0 @@
package net.moonleay.gimble.editor.state.mode
enum class Capability {
INSERT,
REPLACE,
CAN_INTERACT,
NO_CLIP,
FORCE_PLACE,
NO_UPDATES,
BULLDOZER,
}

View file

@ -1,9 +0,0 @@
package net.moonleay.gimble.editor.state.mode
enum class Mode(val displayName: String, val color: Int, val incompatibleModifiers: List<ModeModifier>){
UNKNOWN("UNKNOWN", 0x000000, listOf()), // Unknown mode. This mode cannot be entered
NORMAL("NORMAL", 0x90a959, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
INSERT("INSERT", 0xf4bf75, listOf()), // Place and break blocks
REPLACE("REPLACE", 0xac4242, listOf()), // Replace blocks
VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
}

View file

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

View file

@ -1,9 +0,0 @@
package net.moonleay.gimble.editor.util
import kotlinx.serialization.Serializable
import net.moonleay.gimble.editor.state.GimblePolicyType
@Serializable
data class GimblePolicy(
val policy: GimblePolicyType,
)

View file

@ -1,43 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
@Mixin(MinecraftClient.class)
public abstract class BulldozerMixin {
@Shadow protected int attackCooldown;
@Shadow
@Nullable
public ClientPlayerEntity player;
@Inject(method = "doAttack", at = @At(value = "HEAD"))
private void func(CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
return;
}
this.attackCooldown = 0;
}
@Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
private void func2(boolean breaking, CallbackInfo ci) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
return;
}
this.attackCooldown = 0;
}
}

View file

@ -1,34 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
@Mixin(ClientPlayerInteractionManager.class)
public class BulldozerMixin2 {
@Shadow private int blockBreakingCooldown;
@Shadow
@Final
private MinecraftClient client;
@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
return;
}
this.blockBreakingCooldown = 0;
}
}

View file

@ -1,18 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import net.moonleay.gimble.client.editor.ClientEditor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(DownloadingTerrainScreen.class)
public class GimblePolicyCheckMixin {
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/DownloadingTerrainScreen;close()V", ordinal = -1))
private void func(CallbackInfo ci) {
ClientEditor.INSTANCE.onConnectedToNewWorld();
}
}

View file

@ -1,28 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack;
import net.moonleay.gimble.client.editor.ClientEditor;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InGameHud.class)
public class HudMixin {
@Shadow @Final private MinecraftClient client;
@Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
private void render(MatrixStack matrices, CallbackInfo ci) {
TextRenderer tr = this.client.textRenderer;
tr.drawWithShadow(matrices,
ClientEditor.INSTANCE.getModeDisplayText(),
4, 4,
ClientEditor.INSTANCE.getCurrentColor());
}
}

View file

@ -1,23 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Camera.class)
public class NoClipCameraFixMixin {
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<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

@ -1,64 +0,0 @@
package net.moonleay.gimble.mixin;
import com.mojang.authlib.GameProfile;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World;
import net.moonleay.gimble.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.UUID;
@Mixin(PlayerEntity.class)
public abstract class NoClipMixin extends LivingEntity {
@Shadow public abstract GameProfile getGameProfile();
@Shadow public abstract PlayerAbilities getAbilities();
@Shadow
public abstract boolean isCreative();
protected NoClipMixin(EntityType<? extends LivingEntity> entityType, World world) {
super(entityType, world);
} // Server side
@Inject(method = "tick", at = @At(value = "FIELD",
target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER)
) private void enoClip(CallbackInfo ci) {
if (!this.isCreative())
return;
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) {
return; // NoClip is not enabled
}
if (!this.getAbilities().flying) {
return;
}
// Enable NoClip
this.noClip = true;
}
@Inject(method = "updatePose", at = @At("HEAD"))
private void onUpdatePose(CallbackInfo ci) {
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
return; // NoClip is not enabled
if (!this.getAbilities().flying)
return;
// Force standing pose in NoClip mode
this.setPose(EntityPose.STANDING);
}
}

View file

@ -1,69 +0,0 @@
package net.moonleay.gimble.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public abstract class ReplaceModeMixin {
@Shadow protected abstract void handleBlockBreaking(boolean breaking);
@Shadow @Nullable public ClientPlayerInteractionManager interactionManager;
@Shadow @Final public ParticleManager particleManager;
@Shadow @Nullable public ClientPlayerEntity player;
@Shadow @Nullable public HitResult crosshairTarget;
@Inject(method = "doItemUse", at = @At("HEAD"))
private void replaceBlock(CallbackInfo ci) {
assert this.player != null;
if (!this.player.isCreative())
return;
// Check if should run
if (!ClientEditor.INSTANCE.shouldClient(Capability.REPLACE))
return; // Mode is not REPLACE, ignore
MinecraftClient client = MinecraftClient.getInstance();
assert this.interactionManager != null;
if (!this.interactionManager.getCurrentGameMode().isCreative())
return;
if (!(this.crosshairTarget instanceof BlockHitResult blockHitResult))
return;
if (blockHitResult == null)
return;
// Gather data
BlockPos pos = blockHitResult.getBlockPos();
Direction direction = blockHitResult.getSide();
BlockState blockState = client.world.getBlockState(pos);
// Start sending shit
client.getTutorialManager().onBlockBreaking(client.world, pos, blockState, 1.0F);
this.interactionManager.sendSequencedPacket(client.world, sequence -> {
this.interactionManager.breakBlock(pos);
return new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, direction, sequence);
});
this.player.swingHand(Hand.MAIN_HAND);
}
}

View file

@ -1,42 +0,0 @@
package net.moonleay.gimble.networking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.minecraft.network.PacketByteBuf
import net.moonleay.gimble.client.editor.ClientEditor
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.util.GimblePolicy
object GimbleClient {
fun registerPacketHandlers() {
ClientPlayNetworking.registerGlobalReceiver(PacketIDs.TRANSFER_GIMBLE_POLICY_ID) { _, _, buf, _ ->
onAllowedCheck(buf)
}
}
private fun onAllowedCheck(buf: PacketByteBuf) {
val policy = Cbor.decodeFromByteArray<GimblePolicy>(buf.readByteArray())
ClientEditor.onAllowedCheck(policy) // Update the client's policy
}
/**
* Sends the given [EditorState] to the server.
*/
@OptIn(ExperimentalSerializationApi::class)
fun sendEditorState(state: EditorState) {
val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state))
ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, buf)
}
fun checkIfServerHasGimble(state: EditorState) {
val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state))
ClientPlayNetworking.send(PacketIDs.GIMBLE_PRERENCE_CHECK_ID, buf)
}
}

View file

@ -1,44 +0,0 @@
package net.moonleay.gimble.networking
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity
import net.moonleay.gimble.editor.ServerEditorManager
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.state.GimblePolicyType
import net.moonleay.gimble.editor.util.GimblePolicy
object GimbleServer {
fun registerPacketHandler() {
ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
{ server, player, handler, buf, responseSender ->
handleStateUpdate(player, buf)
}
ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.GIMBLE_PRERENCE_CHECK_ID)
{ server, player, handler, buf, responseSender ->
handlePresenceCheck(player, buf)
}
}
private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
val state = Cbor.decodeFromByteArray<EditorState>(buf.readByteArray())
ServerEditorManager.updateEditorState(player.uuid, state)
// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
}
private fun handlePresenceCheck(player: ServerPlayerEntity, buf: PacketByteBuf) {
val state = Cbor.decodeFromByteArray<EditorState>(buf.readByteArray())
ServerEditorManager.updateEditorState(player.uuid, state)
val buffer = PacketByteBufs.create()
buffer.writeByteArray(Cbor.encodeToByteArray(GimblePolicy(GimblePolicyType.ALLOWED)))
ServerPlayNetworking.send(player, PacketIDs.TRANSFER_GIMBLE_POLICY_ID, buffer)
}
}

Some files were not shown because too many files have changed in this diff Show more