mirror of
https://codeberg.org/moonleay/Gimbal.git
synced 2025-04-11 17:04:15 +02:00
Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
dc732cc39f | |||
d59cf8f9f0 | |||
5252d9abdf | |||
42737446b2 | |||
6a89e5683f | |||
4c8404d306 | |||
b4f46ee703 | |||
19f4b3649a |
24 changed files with 490 additions and 331 deletions
|
@ -46,6 +46,9 @@ internal object ClientMain : ClientModInitializer {
|
||||||
val gimbalConfigPath = FabricLoader.getInstance().configDir.resolve(BuildConstants.modId + "/client.json")
|
val gimbalConfigPath = FabricLoader.getInstance().configDir.resolve(BuildConstants.modId + "/client.json")
|
||||||
CONFIG = ClientConfigHolder(gimbalConfigPath)
|
CONFIG = ClientConfigHolder(gimbalConfigPath)
|
||||||
LOGGER.info("Config has been loaded.")
|
LOGGER.info("Config has been loaded.")
|
||||||
|
LOGGER.info("Applying Config to client.")
|
||||||
|
ClientEditor.applyConfig(CONFIG.config)
|
||||||
|
LOGGER.info("Config has been applied.")
|
||||||
LOGGER.info("Gimbal has been initialized on the client side.")
|
LOGGER.info("Gimbal has been initialized on the client side.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
import kotlinx.serialization.json.encodeToStream
|
import kotlinx.serialization.json.encodeToStream
|
||||||
|
import net.moonleay.gimbal.client.editor.ClientEditor
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ class ClientConfigHolder(private val path: Path) {
|
||||||
fun updateConfig(new: GimbalClientConfig) {
|
fun updateConfig(new: GimbalClientConfig) {
|
||||||
this.config = new
|
this.config = new
|
||||||
this.save(config)
|
this.save(config)
|
||||||
|
ClientEditor.applyConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
|
|
|
@ -20,9 +20,13 @@ package net.moonleay.gimbal.client.config
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import net.moonleay.gimbal.client.config.enums.ToastSettings
|
import net.moonleay.gimbal.client.config.enums.ToastSettings
|
||||||
|
import net.moonleay.gimbal.editor.state.mode.Mode
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GimbalClientConfig(
|
data class GimbalClientConfig(
|
||||||
val guiSettings: GimbalGuiSettings = GimbalGuiSettings(),
|
val guiSettings: GimbalGuiSettings = GimbalGuiSettings(),
|
||||||
val toastSettings: ToastSettings = ToastSettings.ALL,
|
val toastSettings: ToastSettings = ToastSettings.ALL,
|
||||||
|
val playerFlySpeed: Int = 100,
|
||||||
|
val shouldEscResetMode: Boolean = true,
|
||||||
|
val defaultMode: Mode = Mode.NORMAL
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,6 +22,6 @@ import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ScaledRes(
|
data class ScaledRes(
|
||||||
val scaledX: Double,
|
val scaledX: Double, // offsetX
|
||||||
val scaledY: Double,
|
val scaledY: Double, // offsetY
|
||||||
)
|
)
|
||||||
|
|
|
@ -40,17 +40,25 @@ import org.apache.logging.log4j.LogManager
|
||||||
object ClientEditor {
|
object ClientEditor {
|
||||||
private var POLICY = GimbalPolicyType.NOT_PRESENT
|
private var POLICY = GimbalPolicyType.NOT_PRESENT
|
||||||
|
|
||||||
private var CURRENT_MODE = Mode.NORMAL
|
private lateinit var CURRENT_MODE: Mode
|
||||||
private var TEMP_DISABLED_MODE = Mode.UNKNOWN
|
private var TEMP_DISABLED_MODE = Mode.UNKNOWN
|
||||||
|
|
||||||
private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
|
private val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
|
||||||
private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>()
|
private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>()
|
||||||
|
|
||||||
private val DISABLED_MODIFIERS_STORAGE = mutableListOf<ModeModifier>()
|
private val DISABLED_MODIFIERS_STORAGE = mutableListOf<ModeModifier>()
|
||||||
|
|
||||||
|
|
||||||
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
|
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
|
||||||
|
|
||||||
|
fun applyConfig(config: GimbalClientConfig, isBoot: Boolean = true) {
|
||||||
|
if (isBoot) {
|
||||||
|
this.CURRENT_MODE = config.defaultMode
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!config.shouldEscResetMode) return
|
||||||
|
this.CURRENT_MODE = config.defaultMode
|
||||||
|
onUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
fun onConnectedToNewWorld() {
|
fun onConnectedToNewWorld() {
|
||||||
POLICY = GimbalPolicyType.NOT_PRESENT
|
POLICY = GimbalPolicyType.NOT_PRESENT
|
||||||
|
@ -107,7 +115,7 @@ object ClientEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInNonDefaultMode(): Boolean {
|
fun isInNonDefaultMode(): Boolean {
|
||||||
return CURRENT_MODE != Mode.NORMAL
|
return CURRENT_MODE != ClientMain.CONFIG.config.defaultMode
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -86,7 +86,10 @@ class GimbalEditHudGui(private val parent: Screen, private val cfg: ClientConfig
|
||||||
verticalAnchor = anchor.second,
|
verticalAnchor = anchor.second,
|
||||||
hudOptions = oldConf.guiSettings.hudOptions
|
hudOptions = oldConf.guiSettings.hudOptions
|
||||||
),
|
),
|
||||||
toastSettings = oldConf.toastSettings
|
toastSettings = oldConf.toastSettings,
|
||||||
|
playerFlySpeed = oldConf.playerFlySpeed,
|
||||||
|
shouldEscResetMode = oldConf.shouldEscResetMode,
|
||||||
|
defaultMode = oldConf.defaultMode
|
||||||
)
|
)
|
||||||
|
|
||||||
cfg.updateConfig(newConf)
|
cfg.updateConfig(newConf)
|
||||||
|
|
|
@ -29,17 +29,24 @@ import net.moonleay.gimbal.client.config.GimbalClientConfig
|
||||||
import net.moonleay.gimbal.client.config.GimbalGuiSettings
|
import net.moonleay.gimbal.client.config.GimbalGuiSettings
|
||||||
import net.moonleay.gimbal.client.config.enums.HudOptions
|
import net.moonleay.gimbal.client.config.enums.HudOptions
|
||||||
import net.moonleay.gimbal.client.config.enums.ToastSettings
|
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.constants.TranslationKeys
|
||||||
|
import net.moonleay.gimbal.editor.state.mode.Mode
|
||||||
|
|
||||||
class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfigHolder) :
|
class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfigHolder) :
|
||||||
Screen(Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)) {
|
Screen(Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)) {
|
||||||
|
|
||||||
private var hudOptions: HudOptions
|
private var hudOptions: HudOptions
|
||||||
private var toastSettings: ToastSettings
|
private var toastSettings: ToastSettings
|
||||||
|
private var playerFlySpeed: Int
|
||||||
|
private var defaultMode: Mode
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.hudOptions = cfg.config.guiSettings.hudOptions
|
this.hudOptions = cfg.config.guiSettings.hudOptions
|
||||||
this.toastSettings = cfg.config.toastSettings
|
this.toastSettings = cfg.config.toastSettings
|
||||||
|
this.playerFlySpeed = cfg.config.playerFlySpeed
|
||||||
|
this.defaultMode = cfg.config.defaultMode
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
|
@ -65,7 +72,10 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
||||||
)
|
)
|
||||||
val newConf = GimbalClientConfig(
|
val newConf = GimbalClientConfig(
|
||||||
guiSettings = newGui,
|
guiSettings = newGui,
|
||||||
toastSettings = cfg.config.toastSettings
|
toastSettings = cfg.config.toastSettings,
|
||||||
|
playerFlySpeed = cfg.config.playerFlySpeed,
|
||||||
|
shouldEscResetMode = cfg.config.shouldEscResetMode,
|
||||||
|
defaultMode = cfg.config.defaultMode
|
||||||
)
|
)
|
||||||
cfg.updateConfig(newConf)
|
cfg.updateConfig(newConf)
|
||||||
})
|
})
|
||||||
|
@ -123,7 +133,10 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
||||||
offset = oldGuiConfig.offset,
|
offset = oldGuiConfig.offset,
|
||||||
hudOptions = this.hudOptions
|
hudOptions = this.hudOptions
|
||||||
),
|
),
|
||||||
toastSettings = oldConfig.toastSettings
|
toastSettings = oldConfig.toastSettings,
|
||||||
|
playerFlySpeed = oldConfig.playerFlySpeed,
|
||||||
|
shouldEscResetMode = oldConfig.shouldEscResetMode,
|
||||||
|
defaultMode = oldConfig.defaultMode
|
||||||
)
|
)
|
||||||
cfg.updateConfig(newConfig)
|
cfg.updateConfig(newConfig)
|
||||||
}
|
}
|
||||||
|
@ -166,15 +179,99 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
||||||
val oldConfig = cfg.config
|
val oldConfig = cfg.config
|
||||||
val newConfig = GimbalClientConfig(
|
val newConfig = GimbalClientConfig(
|
||||||
guiSettings = oldConfig.guiSettings,
|
guiSettings = oldConfig.guiSettings,
|
||||||
toastSettings = this.toastSettings
|
toastSettings = this.toastSettings,
|
||||||
|
playerFlySpeed = oldConfig.playerFlySpeed,
|
||||||
|
shouldEscResetMode = oldConfig.shouldEscResetMode,
|
||||||
|
defaultMode = oldConfig.defaultMode
|
||||||
)
|
)
|
||||||
cfg.updateConfig(newConfig)
|
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
|
// Done button
|
||||||
this.addDrawableChild(ButtonWidget(
|
this.addDrawableChild(ButtonWidget(
|
||||||
this.width / 2 - 100, this.height / 6 + 168, 200, 20, ScreenTexts.DONE
|
this.width / 2 - 100, this.height / 6 + 168, 200, 20, ScreenTexts.DONE
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
44
src/main/java/net/moonleay/gimbal/client/util/NumberUtil.kt
Normal file
44
src/main/java/net/moonleay/gimbal/client/util/NumberUtil.kt
Normal 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.")
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,10 @@ object TranslationKeys {
|
||||||
const val GENERIC_ENABLED = "${BASE}enabled"
|
const val GENERIC_ENABLED = "${BASE}enabled"
|
||||||
const val GENERIC_DISABLED = "${BASE}disabled"
|
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 {
|
object Hud {
|
||||||
const val BASE = "${TranslationKeys.Gui.Config.BASE}hud."
|
const val BASE = "${TranslationKeys.Gui.Config.BASE}hud."
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,6 @@ internal class DataGenerator : DataGeneratorEntrypoint {
|
||||||
|
|
||||||
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
|
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
|
||||||
LOGGER.info("Starting Data Generation")
|
LOGGER.info("Starting Data Generation")
|
||||||
fabricDataGenerator.addProvider(En_us_GimbalLanguageProvider(fabricDataGenerator))
|
fabricDataGenerator.addProvider(EnUsLanguageProvider(fabricDataGenerator))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
|
||||||
import net.moonleay.gimbal.constants.TranslationKeys
|
import net.moonleay.gimbal.constants.TranslationKeys
|
||||||
|
|
||||||
class En_us_GimbalLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
class EnUsLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
||||||
FabricLanguageProvider(dataGenerator, "en_us") {
|
FabricLanguageProvider(dataGenerator, "en_us") {
|
||||||
|
|
||||||
override fun generateTranslations(translationBuilder: TranslationBuilder?) {
|
override fun generateTranslations(translationBuilder: TranslationBuilder?) {
|
||||||
|
@ -50,10 +50,15 @@ class En_us_GimbalLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
||||||
//Gimbal Toasts
|
//Gimbal Toasts
|
||||||
translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_TOASTS, "Show 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_ALL, "All")
|
||||||
translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_TOGGLE, "Only toggle")
|
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_SYSTEM, "Only System")
|
||||||
translationBuilder.add(TranslationKeys.Gui.Config.Toasts.SHOW_NONE, "None")
|
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
|
// Gimbal Generic Gui
|
||||||
translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_ENABLED, "Enabled")
|
translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_ENABLED, "Enabled")
|
||||||
translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_DISABLED, "Disabled")
|
translationBuilder.add(TranslationKeys.Gui.Config.GENERIC_DISABLED, "Disabled")
|
|
@ -32,7 +32,7 @@ object ServerEditorManager {
|
||||||
|
|
||||||
fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
|
fun updateEditorState(playerUUID: UUID, editorState: EditorState) {
|
||||||
STATEMAP[playerUUID] = editorState
|
STATEMAP[playerUUID] = editorState
|
||||||
LOGGER.info("$playerUUID: ${editorState.editorMode} with ${editorState.editorModifier}")
|
LOGGER.debug("{}: {} with {}", playerUUID, editorState.editorMode, editorState.editorModifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,11 @@
|
||||||
|
|
||||||
package net.moonleay.gimbal.editor.state.mode
|
package net.moonleay.gimbal.editor.state.mode
|
||||||
|
|
||||||
enum class Mode(val displayName: String, val color: Int, val incompatibleModifiers: List<ModeModifier>){
|
enum class Mode(val displayName: String, val color: Int, val hidden: Boolean, val incompatibleModifiers: List<ModeModifier>){
|
||||||
UNKNOWN("UNKNOWN", 0x000000, listOf()), // Unknown mode. This mode cannot be entered
|
UNKNOWN("UNKNOWN", 0x000000, true, listOf()), // Unknown mode. This mode cannot be entered
|
||||||
NORMAL("NORMAL", 0x90a959, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
|
NORMAL("NORMAL", 0x90a959, false, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
|
||||||
INSERT("INSERT", 0xf4bf75, listOf()), // Place and break blocks
|
INSERT("INSERT", 0xf4bf75, false, listOf()), // Place and break blocks
|
||||||
REPLACE("REPLACE", 0xac4242, listOf(ModeModifier.NO_UPDATES)), // Replace blocks
|
REPLACE("REPLACE", 0xac4242, false, listOf(ModeModifier.NO_UPDATES)), // Replace blocks
|
||||||
VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
|
// Add hidden modes after this comment
|
||||||
|
VISUAL("VISUAL", 0x6a9fb5, true, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,13 @@ package net.moonleay.gimbal.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
import net.moonleay.gimbal.client.editor.ClientEditor;
|
import net.moonleay.gimbal.client.editor.ClientEditor;
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
@ -32,30 +36,49 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Mixin(MinecraftClient.class)
|
|
||||||
public abstract class BulldozerMixin {
|
public abstract class BulldozerMixin {
|
||||||
|
|
||||||
@Shadow protected int attackCooldown;
|
@Mixin(MinecraftClient.class)
|
||||||
|
public static abstract class MinecraftClientMixin {
|
||||||
|
@Shadow
|
||||||
|
@Nullable
|
||||||
|
public ClientPlayerEntity player;
|
||||||
|
@Shadow
|
||||||
|
protected int attackCooldown;
|
||||||
|
|
||||||
@Shadow
|
@Inject(method = "doAttack", at = @At(value = "HEAD"))
|
||||||
@Nullable
|
private void func(CallbackInfoReturnable<Boolean> cir) {
|
||||||
public ClientPlayerEntity player;
|
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
|
||||||
|
return;
|
||||||
@Inject(method = "doAttack", at = @At(value = "HEAD"))
|
}
|
||||||
private void func(CallbackInfoReturnable<Boolean> cir) {
|
this.attackCooldown = 0;
|
||||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.player).isCreative()) {
|
}
|
||||||
return;
|
|
||||||
|
@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;
|
||||||
}
|
}
|
||||||
this.attackCooldown = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
|
@Mixin(ClientPlayerInteractionManager.class)
|
||||||
private void func2(boolean breaking, CallbackInfo ci) {
|
public static abstract class ClientPlayerInteractionManagerMixin {
|
||||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking || !Objects.requireNonNull(this.player).isCreative()) {
|
|
||||||
return;
|
@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;
|
||||||
}
|
}
|
||||||
this.attackCooldown = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Gimbal
|
|
||||||
* Copyright (C) 2024 moonleay
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.moonleay.gimbal.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.render.Camera;
|
|
||||||
import net.moonleay.gimbal.client.editor.ClientEditor;
|
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(Camera.class)
|
|
||||||
public class NoClipCameraFixMixin {
|
|
||||||
|
|
||||||
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<Double> cir) {
|
|
||||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cir.setReturnValue(desiredCameraDistance);
|
|
||||||
cir.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,12 +19,15 @@
|
||||||
package net.moonleay.gimbal.mixin;
|
package net.moonleay.gimbal.mixin;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.entity.EntityPose;
|
import net.minecraft.entity.EntityPose;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerAbilities;
|
import net.minecraft.entity.player.PlayerAbilities;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.moonleay.gimbal.client.editor.ClientEditor;
|
||||||
import net.moonleay.gimbal.editor.ServerEditorManager;
|
import net.moonleay.gimbal.editor.ServerEditorManager;
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
@ -32,51 +35,72 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Mixin(PlayerEntity.class)
|
public abstract class NoClipMixin {
|
||||||
public abstract class NoClipMixin extends LivingEntity {
|
|
||||||
@Shadow public abstract GameProfile getGameProfile();
|
|
||||||
|
|
||||||
@Shadow public abstract PlayerAbilities getAbilities();
|
@Mixin(PlayerEntity.class) // Serverside, allows clipping
|
||||||
|
public static abstract class PlayerEntityMixin extends LivingEntity {
|
||||||
@Shadow
|
protected PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
|
||||||
public abstract boolean isCreative();
|
super(entityType, world);
|
||||||
|
|
||||||
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;
|
@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);
|
||||||
}
|
}
|
||||||
// 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))
|
@Mixin(Camera.class) // Clientside, fixes camera
|
||||||
return; // NoClip is not enabled
|
public static abstract class CameraMixin {
|
||||||
if (!this.getAbilities().flying)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Force standing pose in NoClip mode
|
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<Double> cir) {
|
||||||
this.setPose(EntityPose.STANDING);
|
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cir.setReturnValue(desiredCameraDistance);
|
||||||
|
cir.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ package net.moonleay.gimbal.mixin;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
import net.minecraft.client.option.GameOptions;
|
import net.minecraft.client.option.GameOptions;
|
||||||
|
import net.moonleay.gimbal.client.ClientMain;
|
||||||
import net.moonleay.gimbal.client.editor.ClientEditor;
|
import net.moonleay.gimbal.client.editor.ClientEditor;
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||||
import net.moonleay.gimbal.editor.state.mode.Mode;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
@ -43,12 +43,12 @@ public class NormalModeMixin {
|
||||||
public ClientPlayerEntity player;
|
public ClientPlayerEntity player;
|
||||||
|
|
||||||
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
|
||||||
private void 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,34 +19,27 @@
|
||||||
package net.moonleay.gimbal.mixin;
|
package net.moonleay.gimbal.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.moonleay.gimbal.client.ClientMain;
|
||||||
import net.moonleay.gimbal.client.editor.ClientEditor;
|
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import java.util.Objects;
|
@Mixin(ClientPlayNetworkHandler.class)
|
||||||
|
public abstract class PlayerFlySpeedMixin {
|
||||||
@Mixin(ClientPlayerInteractionManager.class)
|
|
||||||
public class BulldozerMixin2 {
|
|
||||||
|
|
||||||
@Shadow private int blockBreakingCooldown;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private MinecraftClient client;
|
private MinecraftClient client;
|
||||||
|
|
||||||
@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
|
@Inject(method = "onPlayerAbilities", at = @At(value = "RETURN"))
|
||||||
private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
|
private void func(PlayerAbilitiesS2CPacket packet, CallbackInfo ci) {
|
||||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !Objects.requireNonNull(this.client.player).isCreative()) {
|
this.client.player.getAbilities().setFlySpeed((ClientMain.CONFIG.getConfig().getPlayerFlySpeed() / 100) * 0.05f);
|
||||||
return;
|
//client!!.player!!.abilities.flySpeed = (this.playerFlySpeed / 100) * 0.05f
|
||||||
}
|
|
||||||
this.blockBreakingCooldown = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,50 +18,87 @@
|
||||||
|
|
||||||
package net.moonleay.gimbal.mixin;
|
package net.moonleay.gimbal.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.*;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.state.property.Property;
|
||||||
import net.minecraft.item.ItemUsageContext;
|
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.hit.BlockHitResult;
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.moonleay.gimbal.editor.ServerEditorManager;
|
import net.moonleay.gimbal.editor.ServerEditorManager;
|
||||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.*;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Mixin(ItemPlacementContext.class)
|
public abstract class ReplaceModeMixin {
|
||||||
public abstract class ReplaceModeMixin extends ItemUsageContext {
|
|
||||||
|
|
||||||
@Shadow
|
@Mixin(ItemPlacementContext.class)
|
||||||
protected boolean canReplaceExisting;
|
public static abstract class ItemPlacementContextMixin extends ItemUsageContext {
|
||||||
|
@Shadow
|
||||||
|
protected boolean canReplaceExisting;
|
||||||
|
|
||||||
@Mutable
|
@Mutable
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private BlockPos placementPos;
|
private BlockPos placementPos;
|
||||||
|
|
||||||
public ReplaceModeMixin(PlayerEntity player, Hand hand, BlockHitResult hit) {
|
public ItemPlacementContextMixin(PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
super(player, hand, 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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"))
|
@Mixin(BlockItem.class)
|
||||||
private void func(World world, PlayerEntity playerEntity, Hand hand, ItemStack itemStack, BlockHitResult blockHitResult, CallbackInfo ci) {
|
public static abstract class BlockItemMixin extends Item {
|
||||||
if (playerEntity == null)
|
|
||||||
return;
|
|
||||||
UUID id = playerEntity.getGameProfile().getId();
|
|
||||||
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.canReplaceExisting = true;
|
public BlockItemMixin(Settings settings) {
|
||||||
this.placementPos = blockHitResult.getBlockPos();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Gimbal
|
|
||||||
* Copyright (C) 2024 moonleay
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.moonleay.gimbal.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.item.BlockItem;
|
|
||||||
import net.minecraft.item.Item;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.state.property.Property;
|
|
||||||
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.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Mixin(BlockItem.class)
|
|
||||||
public abstract class ReplaceStateUpdaterMixin extends Item {
|
|
||||||
|
|
||||||
public ReplaceStateUpdaterMixin(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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,6 +20,7 @@ package net.moonleay.gimbal.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.gui.screen.GameMenuScreen;
|
import net.minecraft.client.gui.screen.GameMenuScreen;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.screen.TitleScreen;
|
||||||
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
@ -33,35 +34,71 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(GameMenuScreen.class)
|
|
||||||
// What is my purpose?
|
// What is my purpose?
|
||||||
public class YouInjectButtonMixin extends Screen {
|
public class YouInjectButtonMixin {
|
||||||
// Go my god.
|
// Go my god.
|
||||||
|
|
||||||
@Unique
|
@Mixin(TitleScreen.class)
|
||||||
private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
|
public static abstract class TitleScreenMixin extends Screen {
|
||||||
|
|
||||||
protected YouInjectButtonMixin(Text title) {
|
@Unique
|
||||||
super(title);
|
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)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "initWidgets", at = @At(value = "RETURN"))
|
|
||||||
private void func(CallbackInfo ci) {
|
@Mixin(GameMenuScreen.class)
|
||||||
this.addDrawableChild(
|
public static abstract class GameMenuScreenMixin extends Screen {
|
||||||
new TexturedButtonWidget(
|
@Unique
|
||||||
this.width / 2 - 124,
|
private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
|
||||||
this.height / 4 + 96 + -16,
|
|
||||||
20,
|
protected GameMenuScreenMixin(Text title) {
|
||||||
20,
|
super(title);
|
||||||
0,
|
}
|
||||||
0,
|
|
||||||
20,
|
@Inject(method = "initWidgets", at = @At(value = "RETURN"))
|
||||||
GIMBAL_TEXTURE,
|
private void func(CallbackInfo ci) {
|
||||||
20,
|
this.addDrawableChild(
|
||||||
40,
|
new TexturedButtonWidget(
|
||||||
button -> this.client.setScreen(new GimbalSettingsGui(this, ClientMain.CONFIG)),
|
this.width / 2 - 124,
|
||||||
Text.translatable(TranslationKeys.Gui.Config.SCREEN_NAME)
|
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)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Gimbal
|
|
||||||
* Copyright (C) 2024 moonleay
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.moonleay.gimbal.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.screen.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;
|
|
||||||
|
|
||||||
@Mixin(TitleScreen.class)
|
|
||||||
public class YouInjectButtonMixin2 extends Screen {
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
|
|
||||||
|
|
||||||
protected YouInjectButtonMixin2(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)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,18 +6,19 @@
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"ForcePlaceMixin",
|
"ForcePlaceMixin",
|
||||||
"NoBlockUpdatesMixin",
|
"NoBlockUpdatesMixin",
|
||||||
"NoClipMixin",
|
"NoClipMixin$PlayerEntityMixin",
|
||||||
"ReplaceModeMixin",
|
"ReplaceModeMixin$BlockItemMixin",
|
||||||
"ReplaceStateUpdaterMixin"
|
"ReplaceModeMixin$ItemPlacementContextMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"BulldozerMixin",
|
"BulldozerMixin$ClientPlayerInteractionManagerMixin",
|
||||||
"BulldozerMixin2",
|
"BulldozerMixin$MinecraftClientMixin",
|
||||||
"HudMixin",
|
"HudMixin",
|
||||||
"NoClipCameraFixMixin",
|
"NoClipMixin$CameraMixin",
|
||||||
"NormalModeMixin",
|
"NormalModeMixin",
|
||||||
"YouInjectButtonMixin",
|
"PlayerFlySpeedMixin",
|
||||||
"YouInjectButtonMixin2"
|
"YouInjectButtonMixin$GameMenuScreenMixin",
|
||||||
|
"YouInjectButtonMixin$TitleScreenMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
Loading…
Add table
Reference in a new issue