mirror of
https://codeberg.org/moonleay/Gimbal.git
synced 2025-04-04 11:44:13 +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")
|
||||
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.")
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ 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.*
|
||||
|
||||
|
@ -36,6 +37,7 @@ class ClientConfigHolder(private val path: Path) {
|
|||
fun updateConfig(new: GimbalClientConfig) {
|
||||
this.config = new
|
||||
this.save(config)
|
||||
ClientEditor.applyConfig(config)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
|
|
|
@ -20,9 +20,13 @@ 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
|
||||
)
|
||||
|
|
|
@ -22,6 +22,6 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Serializable
|
||||
data class ScaledRes(
|
||||
val scaledX: Double,
|
||||
val scaledY: Double,
|
||||
val scaledX: Double, // offsetX
|
||||
val scaledY: Double, // offsetY
|
||||
)
|
||||
|
|
|
@ -40,17 +40,25 @@ import org.apache.logging.log4j.LogManager
|
|||
object ClientEditor {
|
||||
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 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
|
||||
|
@ -107,7 +115,7 @@ object ClientEditor {
|
|||
}
|
||||
|
||||
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,
|
||||
hudOptions = oldConf.guiSettings.hudOptions
|
||||
),
|
||||
toastSettings = oldConf.toastSettings
|
||||
toastSettings = oldConf.toastSettings,
|
||||
playerFlySpeed = oldConf.playerFlySpeed,
|
||||
shouldEscResetMode = oldConf.shouldEscResetMode,
|
||||
defaultMode = oldConf.defaultMode
|
||||
)
|
||||
|
||||
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.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() {
|
||||
|
@ -65,7 +72,10 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
|||
)
|
||||
val newConf = GimbalClientConfig(
|
||||
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)
|
||||
})
|
||||
|
@ -123,7 +133,10 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
|||
offset = oldGuiConfig.offset,
|
||||
hudOptions = this.hudOptions
|
||||
),
|
||||
toastSettings = oldConfig.toastSettings
|
||||
toastSettings = oldConfig.toastSettings,
|
||||
playerFlySpeed = oldConfig.playerFlySpeed,
|
||||
shouldEscResetMode = oldConfig.shouldEscResetMode,
|
||||
defaultMode = oldConfig.defaultMode
|
||||
)
|
||||
cfg.updateConfig(newConfig)
|
||||
}
|
||||
|
@ -166,15 +179,99 @@ class GimbalSettingsGui(private val parent: Screen, private val cfg: ClientConfi
|
|||
val oldConfig = cfg.config
|
||||
val newConfig = GimbalClientConfig(
|
||||
guiSettings = oldConfig.guiSettings,
|
||||
toastSettings = this.toastSettings
|
||||
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
|
||||
|
|
|
@ -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_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."
|
||||
|
||||
|
|
|
@ -28,6 +28,6 @@ internal class DataGenerator : DataGeneratorEntrypoint {
|
|||
|
||||
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
|
||||
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.moonleay.gimbal.constants.TranslationKeys
|
||||
|
||||
class En_us_GimbalLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
||||
class EnUsLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
||||
FabricLanguageProvider(dataGenerator, "en_us") {
|
||||
|
||||
override fun generateTranslations(translationBuilder: TranslationBuilder?) {
|
||||
|
@ -50,10 +50,15 @@ class En_us_GimbalLanguageProvider(dataGenerator: FabricDataGenerator?) :
|
|||
//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_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")
|
|
@ -32,7 +32,7 @@ object ServerEditorManager {
|
|||
|
||||
fun updateEditorState(playerUUID: UUID, editorState: 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
|
||||
|
||||
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(ModeModifier.NO_UPDATES)), // Replace blocks
|
||||
VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
|
||||
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
|
||||
}
|
||||
|
|
|
@ -20,9 +20,13 @@ 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;
|
||||
|
@ -32,30 +36,49 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
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
|
||||
@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;
|
||||
@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;
|
||||
}
|
||||
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;
|
||||
@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;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
|
@ -32,51 +35,72 @@ 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;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class NoClipMixin extends LivingEntity {
|
||||
@Shadow public abstract GameProfile getGameProfile();
|
||||
public abstract class NoClipMixin {
|
||||
|
||||
@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
|
||||
@Mixin(PlayerEntity.class) // Serverside, allows clipping
|
||||
public static abstract class PlayerEntityMixin extends LivingEntity {
|
||||
protected PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
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))
|
||||
return; // NoClip is not enabled
|
||||
if (!this.getAbilities().flying)
|
||||
return;
|
||||
@Mixin(Camera.class) // Clientside, fixes camera
|
||||
public static abstract class CameraMixin {
|
||||
|
||||
// Force standing pose in NoClip mode
|
||||
|
||||
this.setPose(EntityPose.STANDING);
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ package net.moonleay.gimbal.mixin;
|
|||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.option.GameOptions;
|
||||
import net.moonleay.gimbal.client.ClientMain;
|
||||
import net.moonleay.gimbal.client.editor.ClientEditor;
|
||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||
import net.moonleay.gimbal.editor.state.mode.Mode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
@ -43,12 +43,12 @@ public class NormalModeMixin {
|
|||
public ClientPlayerEntity player;
|
||||
|
||||
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
|
||||
private void setNormalMode(boolean pause, CallbackInfo ci) {
|
||||
if (ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
|
||||
private void setDefaultMode(boolean pause, CallbackInfo ci) {
|
||||
if (ClientMain.CONFIG.getConfig().getShouldEscResetMode() && ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
|
||||
assert this.player != null;
|
||||
if (this.player.isCreative()) {
|
||||
// Set the editor mode to normal
|
||||
ClientEditor.INSTANCE.setMode(Mode.NORMAL);
|
||||
ClientEditor.INSTANCE.setMode(ClientMain.CONFIG.getConfig().getDefaultMode());
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,34 +19,27 @@
|
|||
package net.moonleay.gimbal.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.gimbal.client.editor.ClientEditor;
|
||||
import net.moonleay.gimbal.editor.state.mode.Capability;
|
||||
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.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(ClientPlayerInteractionManager.class)
|
||||
public class BulldozerMixin2 {
|
||||
|
||||
@Shadow private int blockBreakingCooldown;
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public abstract class PlayerFlySpeedMixin {
|
||||
|
||||
@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;
|
||||
@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
|
||||
}
|
||||
|
||||
}
|
|
@ -18,50 +18,87 @@
|
|||
|
||||
package net.moonleay.gimbal.mixin;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
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.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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;
|
||||
|
||||
@Mixin(ItemPlacementContext.class)
|
||||
public abstract class ReplaceModeMixin extends ItemUsageContext {
|
||||
public abstract class ReplaceModeMixin {
|
||||
|
||||
@Shadow
|
||||
protected boolean canReplaceExisting;
|
||||
@Mixin(ItemPlacementContext.class)
|
||||
public static abstract class ItemPlacementContextMixin extends ItemUsageContext {
|
||||
@Shadow
|
||||
protected boolean canReplaceExisting;
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private BlockPos placementPos;
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private BlockPos placementPos;
|
||||
|
||||
public ReplaceModeMixin(PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||
super(player, hand, hit);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
@Mixin(BlockItem.class)
|
||||
public static abstract class BlockItemMixin extends Item {
|
||||
|
||||
this.canReplaceExisting = true;
|
||||
this.placementPos = blockHitResult.getBlockPos();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.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;
|
||||
|
@ -33,35 +34,71 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameMenuScreen.class)
|
||||
// What is my purpose?
|
||||
public class YouInjectButtonMixin extends Screen {
|
||||
public class YouInjectButtonMixin {
|
||||
// Go my god.
|
||||
|
||||
@Unique
|
||||
private static final Identifier GIMBAL_TEXTURE = new Identifier(BuildConstants.modId, "textures/gimbal_options_texture_button.png");
|
||||
@Mixin(TitleScreen.class)
|
||||
public static abstract class TitleScreenMixin extends Screen {
|
||||
|
||||
protected YouInjectButtonMixin(Text title) {
|
||||
super(title);
|
||||
@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)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@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)
|
||||
)
|
||||
);
|
||||
|
||||
@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)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
"ForcePlaceMixin",
|
||||
"NoBlockUpdatesMixin",
|
||||
"NoClipMixin",
|
||||
"ReplaceModeMixin",
|
||||
"ReplaceStateUpdaterMixin"
|
||||
"NoClipMixin$PlayerEntityMixin",
|
||||
"ReplaceModeMixin$BlockItemMixin",
|
||||
"ReplaceModeMixin$ItemPlacementContextMixin"
|
||||
],
|
||||
"client": [
|
||||
"BulldozerMixin",
|
||||
"BulldozerMixin2",
|
||||
"BulldozerMixin$ClientPlayerInteractionManagerMixin",
|
||||
"BulldozerMixin$MinecraftClientMixin",
|
||||
"HudMixin",
|
||||
"NoClipCameraFixMixin",
|
||||
"NoClipMixin$CameraMixin",
|
||||
"NormalModeMixin",
|
||||
"YouInjectButtonMixin",
|
||||
"YouInjectButtonMixin2"
|
||||
"PlayerFlySpeedMixin",
|
||||
"YouInjectButtonMixin$GameMenuScreenMixin",
|
||||
"YouInjectButtonMixin$TitleScreenMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
Loading…
Add table
Reference in a new issue