feat!: added Gimble Server side check, reworked mode & modifier checks

Signed-off-by: moonleay <contact@moonleay.net>
moonleay 2024-04-28 02:38:52 +02:00
parent 724618a052
commit acd318c5f1
Signed by: moonleay
GPG key ID: 82667543CCD715FB
26 changed files with 305 additions and 116 deletions

@ -1,10 +1,11 @@
package net.moonleay.gimble.client
import net.moonleay.gimble.build.BuildConstants
import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import net.moonleay.gimble.build.BuildConstants
import net.moonleay.gimble.client.keybindings.KeybindingManager
import net.moonleay.gimble.client.keybindings.KeybindingRegistrar
import net.moonleay.gimble.networking.GimbleClient
import org.apache.logging.log4j.LogManager
internal object ClientMain : ClientModInitializer {
@ -15,6 +16,9 @@ internal object ClientMain : ClientModInitializer {
LOGGER.info("Initializing Gimble on the client side...")
KeybindingRegistrar.registerKeybindings()
registerEvents()
LOGGER.info("Registering packets...")
GimbleClient.registerPacketHandlers()
LOGGER.info("Packets have been registered.")
LOGGER.info("Gimble has been initialized on the client side.")
}

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

@ -5,7 +5,6 @@ import net.minecraft.client.util.InputUtil
import net.moonleay.gimble.build.BuildConstants
import net.moonleay.gimble.client.keybindings.impl.editormode.EnableInsertModeShortcut
import net.moonleay.gimble.client.keybindings.impl.editormode.EnableReplaceModeShortcut
import net.moonleay.gimble.client.keybindings.impl.editormode.EnableVisualModeShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut
import net.moonleay.gimble.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut
@ -32,25 +31,25 @@ object KeybindingRegistrar {
val toggleBulldozerModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.bulldozer",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_B,
GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier"
)
val toggleForcePlaceModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.forceplace",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_F,
GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier"
)
val toggleNoUpdatesModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noupdates",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_N,
GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier"
)
val toggleNoClipModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noclip",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_C,
GLFW.GLFW_KEY_UNKNOWN,
"gimble.category.editormodifier"
)
@ -73,15 +72,15 @@ object KeybindingRegistrar {
GLFW.GLFW_KEY_R,
"gimble.category.editormode"
)
val visualKeyBinding = KeyBinding(
"gimble.key.editor.mode.visual",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_V,
"gimble.category.editormode"
)
// val visualKeyBinding = KeyBinding(
// "gimble.key.editor.mode.visual",
// InputUtil.Type.KEYSYM,
// GLFW.GLFW_KEY_V,
// "gimble.category.editormode"
// )
KeybindingManager.registerShortcut(EnableInsertModeShortcut(insertKeyBinding))
KeybindingManager.registerShortcut(EnableReplaceModeShortcut(replaceKeyBinding))
KeybindingManager.registerShortcut(EnableVisualModeShortcut(visualKeyBinding))
// KeybindingManager.registerShortcut(EnableVisualModeShortcut(visualKeyBinding))
}
private fun registerSetGameModeKeybindings() {

@ -9,8 +9,6 @@ import net.moonleay.gimble.editor.state.mode.Mode
class EnableInsertModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.CURRENT_MODE = Mode.INSERT
ClientEditor.checkForIncompatibleModeModifiers()
ClientEditor.setMode(Mode.INSERT)
}
}

@ -9,8 +9,6 @@ import net.moonleay.gimble.editor.state.mode.Mode
class EnableReplaceModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.CURRENT_MODE = Mode.REPLACE
ClientEditor.checkForIncompatibleModeModifiers()
ClientEditor.setMode(Mode.REPLACE)
}
}

@ -9,8 +9,6 @@ import net.moonleay.gimble.editor.state.mode.Mode
class EnableVisualModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ClientEditor.CURRENT_MODE = Mode.VISUAL
ClientEditor.checkForIncompatibleModeModifiers()
ClientEditor.setMode(Mode.VISUAL)
}
}

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

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

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

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

@ -0,0 +1,44 @@
package net.moonleay.gimble.editor.util
import net.moonleay.gimble.editor.state.EditorState
import net.moonleay.gimble.editor.state.mode.Capability
import net.moonleay.gimble.editor.state.mode.Mode
import net.moonleay.gimble.editor.state.mode.ModeModifier
object EditorUtil {
/*
* Check if a player should be able to perform an action
* */
fun shouldPlayer(capability: Capability, state: EditorState): Boolean {
when (capability) {
Capability.INSERT -> {
return state.editorMode == Mode.INSERT
}
Capability.REPLACE -> {
return state.editorMode == Mode.REPLACE
}
Capability.CAN_INTERACT -> {
return state.editorMode != Mode.VISUAL && state.editorMode != Mode.NORMAL
}
Capability.NO_CLIP -> {
return state.editorModifier.contains(ModeModifier.NO_CLIP)
}
Capability.FORCE_PLACE -> {
return state.editorModifier.contains(ModeModifier.FORCE_PLACE)
}
Capability.NO_UPDATES -> {
return state.editorModifier.contains(ModeModifier.NO_UPDATES)
}
Capability.BULLDOZER -> {
return state.editorModifier.contains(ModeModifier.BULLDOZER)
}
}
}
}

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

@ -2,7 +2,7 @@ package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -17,7 +17,7 @@ public abstract class BulldozerMixin {
@Inject(method = "doAttack", at = @At(value = "HEAD"))
private void func(CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.containsModifier(ModeModifier.BULLDOZER)){
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER)) {
return;
}
this.attackCooldown = 0;
@ -25,7 +25,7 @@ public abstract class BulldozerMixin {
@Inject(method = "handleBlockBreaking", at = @At(value = "HEAD"))
private void func2(boolean breaking, CallbackInfo ci) {
if (!ClientEditor.INSTANCE.containsModifier(ModeModifier.BULLDOZER) || !breaking){
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER) || !breaking) {
return;
}
this.attackCooldown = 0;

@ -4,7 +4,7 @@ import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -18,7 +18,7 @@ public class BulldozerMixin2 {
@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"))
private void func(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
if (!ClientEditor.INSTANCE.containsModifier(ModeModifier.BULLDOZER)) {
if (!ClientEditor.INSTANCE.shouldClient(Capability.BULLDOZER)) {
return;
}
this.blockBreakingCooldown = 0;

@ -1,16 +1,17 @@
package net.moonleay.gimble.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.moonleay.gimble.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.UUID;
@Mixin(BlockItem.class)
public class ForcePlaceMixin {
@ -19,9 +20,9 @@ public class ForcePlaceMixin {
if (context.getPlayer() == null) {
return;
}
PlayerEntity player = context.getPlayer();
UUID id = context.getPlayer().getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.playerHasModifier(player.getGameProfile().getId(), ModeModifier.FORCE_PLACE)) {
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.FORCE_PLACE)) {
return;
}
cir.setReturnValue(true);

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

@ -4,21 +4,14 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Mode;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(InGameHud.class)
public class HudMixin {
@ -26,41 +19,10 @@ public class HudMixin {
@Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
private void render(MatrixStack matrices, CallbackInfo ci) {
Mode currentMode = ClientEditor.INSTANCE.getCurrentMode();
StringBuilder displayText = getStringBuilder(currentMode);
MinecraftClient mc = MinecraftClient.getInstance();
TextRenderer tr = mc.textRenderer;
// int screenWidth = mc.getWindow().getWidth();
// int screenHeight = mc.getWindow().getHeight();
// int scale = (mc.options.getGuiScale().getValue() == 0 ? 1 : mc.options.getGuiScale().getValue());
// int bottomY = screenHeight / scale - 4 - tr.fontHeight - 12;
TextRenderer tr = this.client.textRenderer;
tr.drawWithShadow(matrices,
Text.of(displayText.toString()),
ClientEditor.INSTANCE.getModeDisplayText(),
4, 4,
currentMode.getColor());
}
@Unique
private static @NotNull StringBuilder getStringBuilder(Mode currentMode) {
List<ModeModifier> currentModifier = ClientEditor.INSTANCE.getCurrentModifier();
StringBuilder displayText = new StringBuilder(currentMode.getDisplayName());
if (!currentModifier.isEmpty()) {
displayText.append(" [");
for (int i = 0; i < currentModifier.size(); i++) {
displayText.append(currentModifier.get(i).getDisplayName());
if (i != currentModifier.size() - 1) {
displayText.append(", ");
}
}
displayText.append("]");
}
return displayText;
}
@Unique
private int getXRight(String txt, int screenWidth) {
return screenWidth / (MinecraftClient.getInstance().options.getGuiScale().getValue() == 0 ? 1 : MinecraftClient.getInstance().options.getGuiScale().getValue()) - 4 - MinecraftClient.getInstance().textRenderer.getWidth(Text.of(txt));
ClientEditor.INSTANCE.getCurrentColor());
}
}

@ -2,16 +2,17 @@ package net.moonleay.gimble.mixin;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.moonleay.gimble.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.UUID;
@Mixin(BlockItem.class)
public class NoBlockUpdatesMixin {
@ -20,9 +21,9 @@ public class NoBlockUpdatesMixin {
if (context.getPlayer() == null) {
return;
}
PlayerEntity player = context.getPlayer();
UUID id = context.getPlayer().getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.playerHasModifier(player.getGameProfile().getId(), ModeModifier.NO_UPDATES)) {
if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.NO_UPDATES)) {
return;
}

@ -2,7 +2,7 @@ package net.moonleay.gimble.mixin;
import net.minecraft.client.render.Camera;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -13,9 +13,10 @@ public class NoClipCameraFixMixin {
@Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true)
private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable<Double> cir) {
if (ClientEditor.INSTANCE.containsModifier(ModeModifier.NO_CLIP)){
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP)) {
return;
}
cir.setReturnValue(desiredCameraDistance);
cir.cancel();
}
}
}

@ -8,7 +8,7 @@ import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World;
import net.moonleay.gimble.editor.ServerEditorManager;
import net.moonleay.gimble.editor.state.mode.ModeModifier;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -33,7 +33,7 @@ public abstract class NoClipMixin extends LivingEntity {
) private void enoClip(CallbackInfo ci) {
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.playerHasModifier(uuid, ModeModifier.NO_CLIP)) {
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) {
return; // NoClip is not enabled
}
if (!this.getAbilities().flying) {
@ -47,7 +47,7 @@ public abstract class NoClipMixin extends LivingEntity {
private void onUpdatePose(CallbackInfo ci) {
UUID uuid = this.getGameProfile().getId();
if (!ServerEditorManager.INSTANCE.playerHasModifier(uuid, ModeModifier.NO_CLIP))
if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP))
return; // NoClip is not enabled
if (!this.getAbilities().flying)
return;

@ -2,8 +2,9 @@ package net.moonleay.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.GameOptions;
import net.moonleay.gimble.editor.state.mode.Mode;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Capability;
import net.moonleay.gimble.editor.state.mode.Mode;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -20,17 +21,17 @@ public class NormalModeMixin {
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
private void setNormalMode(boolean pause, CallbackInfo ci) {
if (ClientEditor.INSTANCE.getCURRENT_MODE() != Mode.NORMAL){
if (ClientEditor.INSTANCE.isInNonDefaultMode() && ClientEditor.INSTANCE.isAllowed()) {
// Set the editor mode to normal
ClientEditor.INSTANCE.setCURRENT_MODE(Mode.NORMAL);
ClientEditor.INSTANCE.checkForIncompatibleModeModifiers();
ClientEditor.INSTANCE.setMode(Mode.NORMAL);
ci.cancel();
}
}
@Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z"), cancellable = true)
private void blockWorldManipulation(CallbackInfo ci) { // This could be replaced by net.minecraft.world.GameMode#isBlockBreakingRestricted
if (ClientEditor.INSTANCE.getCURRENT_MODE() == Mode.NORMAL || ClientEditor.INSTANCE.getCURRENT_MODE() == Mode.VISUAL) {
private void blockWorldManipulation(CallbackInfo ci) {
// This could be replaced by net.minecraft.world.GameMode#isBlockBreakingRestricted
if (!ClientEditor.INSTANCE.shouldClient(Capability.CAN_INTERACT)) {
while(this.options.attackKey.wasPressed()) {
}

@ -12,7 +12,7 @@ import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.gimble.client.editor.ClientEditor;
import net.moonleay.gimble.editor.state.mode.Mode;
import net.moonleay.gimble.editor.state.mode.Capability;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@ -38,7 +38,7 @@ public abstract class ReplaceModeMixin {
@Inject(method = "doItemUse", at = @At("HEAD"))
private void replaceBlock(CallbackInfo ci) {
// Check if should run
if (!ClientEditor.INSTANCE.getCURRENT_MODE().equals(Mode.REPLACE))
if (!ClientEditor.INSTANCE.shouldClient(Capability.REPLACE))
return; // Mode is not REPLACE, ignore
MinecraftClient client = MinecraftClient.getInstance();
assert this.interactionManager != null;

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

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

@ -5,4 +5,7 @@ import net.moonleay.gimble.build.BuildConstants
object PacketIDs {
val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
val GIMBLE_PRERENCE_CHECK_ID = Identifier(BuildConstants.modId, "gimble_preference_check")
val TRANSFER_GIMBLE_POLICY_ID = Identifier(BuildConstants.modId, "gimble_is_present")
}

@ -11,6 +11,7 @@
"client": [
"BulldozerMixin",
"BulldozerMixin2",
"GimblePolicyCheckMixin",
"HudMixin",
"NoClipCameraFixMixin",
"NormalModeMixin",