diff --git a/build.gradle.kts b/build.gradle.kts index 60a443d..ef5bc1f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,6 +34,13 @@ val mavenVersion = System.getenv("CI_COMMIT_TAG") ?: System.getenv("CI_COMMIT_SH val modId: String by project val modName: String by project +/* +* Gimbal version stuff +* */ + +val gimbalProtocolVersion = 2 + + val mavenGroup: String by project val mavenArtifact: String by project @@ -50,6 +57,9 @@ group = mavenGroup project.base.archivesName.set(mavenArtifact) repositories { + maven { // Dependency api + url = uri("https://oss.sonatype.org/content/repositories/snapshots") + } } fabricApi { @@ -66,6 +76,10 @@ dependencies { modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion") modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") + modApi("me.lucko:fabric-permissions-api:0.2-SNAPSHOT") + { + exclude(group = "net.fabricmc") + } } val targetJavaVersion = 17 @@ -76,6 +90,7 @@ val templateProps = mapOf( "modVersion" to project.version as String, "modId" to modId, "modName" to modName, + "protocolVersion" to gimbalProtocolVersion, "minecraftVersion" to minecraftVersion, "fabricLoaderVersion" to fabricLoaderVersion, "fabricKotlinVersion" to fabricKotlinVersion, diff --git a/gradle.properties b/gradle.properties index df0fe30..aa5c709 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ #Generated by fabric-mod-template #Sun Apr 21 19:29:15 CEST 2024 -fabric.loom.version=1.4.6 +fabric.loom.version=1.6-SNAPSHOT kotlin.version=1.9.22 fabric.api.version=0.77.0+1.19.2 yarn.version=1.19.2+build.28 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ab05b50..ea3fa1d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -18,7 +18,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/net/moonleay/gimbal/Main.kt b/src/main/java/net/moonleay/gimbal/Main.kt index b9fb433..903d100 100644 --- a/src/main/java/net/moonleay/gimbal/Main.kt +++ b/src/main/java/net/moonleay/gimbal/Main.kt @@ -19,6 +19,7 @@ package net.moonleay.gimbal import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.networking.GimbalServer import org.apache.logging.log4j.LogManager @@ -31,6 +32,11 @@ internal object Main : ModInitializer { LOGGER.info("Registering packets...") GimbalServer.registerPacketHandler() LOGGER.info("Packets have been registered.") + LOGGER.info("Registering events...") + ServerPlayConnectionEvents.INIT.register(ServerPlayConnectionEvents.Init { handler, server -> + GimbalServer.notifyPlayerOfPolicy(handler.player) + }) + LOGGER.info("Events have been registered.") LOGGER.info("Gimbal has been initialized on the common side.") LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay") } diff --git a/src/main/java/net/moonleay/gimbal/client/ClientMain.kt b/src/main/java/net/moonleay/gimbal/client/ClientMain.kt index 0d81303..0f6f156 100644 --- a/src/main/java/net/moonleay/gimbal/client/ClientMain.kt +++ b/src/main/java/net/moonleay/gimbal/client/ClientMain.kt @@ -20,7 +20,9 @@ package net.moonleay.gimbal.client import net.fabricmc.api.ClientModInitializer import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents import net.moonleay.gimbal.build.BuildConstants +import net.moonleay.gimbal.client.editor.ClientEditor import net.moonleay.gimbal.client.keybindings.KeybindingManager import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar import net.moonleay.gimbal.networking.GimbalClient @@ -33,7 +35,7 @@ internal object ClientMain : ClientModInitializer { override fun onInitializeClient() { LOGGER.info("Initializing Gimbal on the client side...") KeybindingRegistrar.registerKeybindings() - registerEvents() + this.registerEvents() LOGGER.info("Registering packets...") GimbalClient.registerPacketHandlers() LOGGER.info("Packets have been registered.") @@ -45,6 +47,10 @@ internal object ClientMain : ClientModInitializer { ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client -> KeybindingManager.onClientTick(client) }) + + ClientLoginConnectionEvents.INIT.register(ClientLoginConnectionEvents.Init { _, _ -> + ClientEditor.onConnectedToNewWorld() // Client is connecting to a new server, reset the editor + }) LOGGER.info("Client events have been registered.") } diff --git a/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt b/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt index 2a732bb..e64b4e4 100644 --- a/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt +++ b/src/main/java/net/moonleay/gimbal/client/editor/ClientEditor.kt @@ -24,11 +24,11 @@ import net.moonleay.gimbal.client.util.ChatUtil import net.moonleay.gimbal.editor.ServerEditorManager import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.GimbalPolicyType +import net.moonleay.gimbal.editor.state.GimbalServerState import net.moonleay.gimbal.editor.state.mode.Capability import net.moonleay.gimbal.editor.state.mode.Mode import net.moonleay.gimbal.editor.state.mode.ModeModifier import net.moonleay.gimbal.editor.util.EditorUtil -import net.moonleay.gimbal.editor.util.GimbalPolicy import net.moonleay.gimbal.networking.GimbalClient object ClientEditor { @@ -45,12 +45,6 @@ object ClientEditor { fun onConnectedToNewWorld() { POLICY = GimbalPolicyType.NOT_PRESENT - GimbalClient.checkIfServerHasGimble( - EditorState( - CURRENT_MODE, - CURRENT_MODE_MODIFIER - ) - ) if (TEMP_DISABLED_MODE == Mode.UNKNOWN) { TEMP_DISABLED_MODE = CURRENT_MODE @@ -62,9 +56,9 @@ object ClientEditor { CURRENT_MODE_MODIFIER.clear() } - fun onAllowedCheck(data: GimbalPolicy) { - POLICY = data.policy - if (data.policy == GimbalPolicyType.ALLOWED) { + fun onPolicyReceived(data: GimbalServerState, shouldUpdateServer: Boolean = true) { + POLICY = data.policyType + if (data.policyType == GimbalPolicyType.ALLOWED) { if (TEMP_DISABLED_MODE != Mode.UNKNOWN) { CURRENT_MODE = TEMP_DISABLED_MODE @@ -74,7 +68,13 @@ object ClientEditor { DISABLED_MODIFIERS_STORAGE ) DISABLED_MODIFIERS_STORAGE.clear() - onUpdated() + onUpdated(shouldUpdateServer) + + if (!shouldUpdateServer) + ServerEditorManager.updateEditorState( + MinecraftClient.getInstance().player!!.uuid, + this.getClientState() + ) } } @@ -99,11 +99,8 @@ object ClientEditor { * Send an updated player state to the server * */ private fun updateServerState() { - val state = EditorState( - CURRENT_MODE, - CURRENT_MODE_MODIFIER - ) - GimbalClient.sendEditorState(state) + val state = this.getClientState() + GimbalClient.sendStatePacket(state) ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state) } @@ -150,17 +147,17 @@ object ClientEditor { onUpdated() } - private fun onUpdated() { + private fun onUpdated(shouldUpdateServer: Boolean = true) { CURRENT_MODE_MODIFIER.sortBy { it.displayName } - checkForIncompatibleModeModifiers() + checkForIncompatibleModeModifiers(shouldUpdateServer) } /** * This runs on Mode updated */ - private fun checkForIncompatibleModeModifiers() { + private fun checkForIncompatibleModeModifiers(shouldUpdateServer: Boolean = true) { if (TEMP_DISABLED_MODIFIERS.size > 0) { CURRENT_MODE_MODIFIER.addAll( TEMP_DISABLED_MODIFIERS @@ -185,7 +182,8 @@ object ClientEditor { } // Update State - updateServerState() + if (shouldUpdateServer) + updateServerState() if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) { ChatUtil.showToastToSelf( @@ -230,4 +228,8 @@ object ClientEditor { fun getCurrentColor(): Int { return CURRENT_MODE.color } + + fun getClientState(): EditorState { + return EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER) + } } diff --git a/src/main/java/net/moonleay/gimbal/networking/PacketIDs.kt b/src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt similarity index 80% rename from src/main/java/net/moonleay/gimbal/networking/PacketIDs.kt rename to src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt index cae6037..500ff74 100644 --- a/src/main/java/net/moonleay/gimbal/networking/PacketIDs.kt +++ b/src/main/java/net/moonleay/gimbal/constants/PacketIDs.kt @@ -16,14 +16,13 @@ * along with this program. If not, see . */ -package net.moonleay.gimbal.networking +package net.moonleay.gimbal.constants import net.minecraft.util.Identifier import net.moonleay.gimbal.build.BuildConstants object PacketIDs { val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state") - val GIMBLE_PRERENCE_CHECK_ID = Identifier(BuildConstants.modId, "gimble_preference_check") - val TRANSFER_GIMBLE_POLICY_ID = Identifier(BuildConstants.modId, "gimble_is_present") + val GIMBAL_POLICY_PACKET_ID = Identifier(BuildConstants.modId, "gimble_policy") } diff --git a/src/main/java/net/moonleay/gimbal/mixin/GimbalPolicyCheckMixin.java b/src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt similarity index 50% rename from src/main/java/net/moonleay/gimbal/mixin/GimbalPolicyCheckMixin.java rename to src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt index 637f13d..7263609 100644 --- a/src/main/java/net/moonleay/gimbal/mixin/GimbalPolicyCheckMixin.java +++ b/src/main/java/net/moonleay/gimbal/constants/PermissionIDs.kt @@ -16,21 +16,8 @@ * along with this program. If not, see . */ -package net.moonleay.gimbal.mixin; +package net.moonleay.gimbal.constants -import net.minecraft.client.gui.screen.DownloadingTerrainScreen; -import net.moonleay.gimbal.client.editor.ClientEditor; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(DownloadingTerrainScreen.class) -public class GimbalPolicyCheckMixin { - - - @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(); - } +object PermissionIDs { + const val GIMBAL_USAGE_PERMISSION = "gimbal.use" } diff --git a/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt b/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt index cf045be..37c7341 100644 --- a/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt +++ b/src/main/java/net/moonleay/gimbal/editor/state/GimbalPolicyType.kt @@ -18,8 +18,11 @@ package net.moonleay.gimbal.editor.state +import kotlinx.serialization.Serializable + +@Serializable enum class GimbalPolicyType { ALLOWED, DENIED, - NOT_PRESENT + NOT_PRESENT, } diff --git a/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt b/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt new file mode 100644 index 0000000..7dffedc --- /dev/null +++ b/src/main/java/net/moonleay/gimbal/editor/state/GimbalServerState.kt @@ -0,0 +1,27 @@ +/* + * Gimbal + * Copyright (C) 2024 moonleay + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.moonleay.gimbal.editor.state + +import kotlinx.serialization.Serializable + +@Serializable +data class GimbalServerState( + val protocolVersion: Int, + val policyType: GimbalPolicyType, +) diff --git a/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt b/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt index c2b154a..fa179df 100644 --- a/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt +++ b/src/main/java/net/moonleay/gimbal/networking/GimbalClient.kt @@ -25,38 +25,46 @@ import kotlinx.serialization.encodeToByteArray import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking import net.fabricmc.fabric.api.networking.v1.PacketByteBufs import net.minecraft.network.PacketByteBuf +import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.client.editor.ClientEditor +import net.moonleay.gimbal.constants.PacketIDs import net.moonleay.gimbal.editor.state.EditorState -import net.moonleay.gimbal.editor.util.GimbalPolicy +import net.moonleay.gimbal.editor.state.GimbalPolicyType +import net.moonleay.gimbal.editor.state.GimbalServerState object GimbalClient { fun registerPacketHandlers() { - ClientPlayNetworking.registerGlobalReceiver(PacketIDs.TRANSFER_GIMBLE_POLICY_ID) { _, _, buf, _ -> - onAllowedCheck(buf) + ClientPlayNetworking.registerGlobalReceiver(PacketIDs.GIMBAL_POLICY_PACKET_ID) { _, _, buf, handler -> + val state = this.getServerState(buf) + val isUsable = this.isGimbalUsable(state) + if (isUsable) { + val buf = PacketByteBufs.create() + buf.writeByteArray(Cbor.encodeToByteArray(ClientEditor.getClientState())) + handler.sendPacket(PacketIDs.UPDATE_EDITOR_STATE_ID, buf) + } + ClientEditor.onPolicyReceived(state, false) } } @OptIn(ExperimentalSerializationApi::class) - private fun onAllowedCheck(buf: PacketByteBuf) { - val policy = Cbor.decodeFromByteArray(buf.readByteArray()) - ClientEditor.onAllowedCheck(policy) // Update the client's policy + private fun getServerState(buf: PacketByteBuf): GimbalServerState { + val serverState = Cbor.decodeFromByteArray(buf.readByteArray()) + return serverState } - /** - * Sends the given [EditorState] to the server. - */ - @OptIn(ExperimentalSerializationApi::class) - fun sendEditorState(state: EditorState) { - val buf = PacketByteBufs.create() - buf.writeByteArray(Cbor.encodeToByteArray(state)) - ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, buf) + private fun isGimbalUsable(state: GimbalServerState): Boolean { + return state.policyType == GimbalPolicyType.ALLOWED && state.protocolVersion.toString() == BuildConstants.protocolVersion } @OptIn(ExperimentalSerializationApi::class) - fun checkIfServerHasGimble(state: EditorState) { + private fun createStatePacket(state: EditorState): PacketByteBuf { val buf = PacketByteBufs.create() buf.writeByteArray(Cbor.encodeToByteArray(state)) - ClientPlayNetworking.send(PacketIDs.GIMBLE_PRERENCE_CHECK_ID, buf) + return buf + } + + fun sendStatePacket(state: EditorState) { + ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, createStatePacket(state)) } } diff --git a/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt b/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt index 7ba0d38..82f8968 100644 --- a/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt +++ b/src/main/java/net/moonleay/gimbal/networking/GimbalServer.kt @@ -21,28 +21,41 @@ package net.moonleay.gimbal.networking import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.decodeFromByteArray import kotlinx.serialization.encodeToByteArray +import me.lucko.fabric.api.permissions.v0.Permissions import net.fabricmc.fabric.api.networking.v1.PacketByteBufs import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.minecraft.network.PacketByteBuf import net.minecraft.server.network.ServerPlayerEntity +import net.moonleay.gimbal.build.BuildConstants +import net.moonleay.gimbal.constants.PacketIDs +import net.moonleay.gimbal.constants.PermissionIDs import net.moonleay.gimbal.editor.ServerEditorManager import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.GimbalPolicyType -import net.moonleay.gimbal.editor.util.GimbalPolicy +import net.moonleay.gimbal.editor.state.GimbalServerState object GimbalServer { fun registerPacketHandler() { ServerPlayNetworking .registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID) - { server, player, handler, buf, responseSender -> + { _, player, _, buf, _ -> handleStateUpdate(player, buf) } - ServerPlayNetworking - .registerGlobalReceiver(PacketIDs.GIMBLE_PRERENCE_CHECK_ID) - { server, player, handler, buf, responseSender -> - handlePresenceCheck(player, buf) - } + } + + fun notifyPlayerOfPolicy(player: ServerPlayerEntity) { + println("Sending policy packet to player ${player.name.string}...") + val buf = PacketByteBufs.create() + buf.writeByteArray( + Cbor.encodeToByteArray( + GimbalServerState( + BuildConstants.protocolVersion.toInt(), + if (this.isPlayerAllowedToUseGimbal(player)) GimbalPolicyType.ALLOWED else GimbalPolicyType.DENIED + ) + ) + ) + ServerPlayNetworking.send(player, PacketIDs.GIMBAL_POLICY_PACKET_ID, buf) } private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){ @@ -51,12 +64,7 @@ object GimbalServer { // player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}")) } - private fun handlePresenceCheck(player: ServerPlayerEntity, buf: PacketByteBuf) { - val state = Cbor.decodeFromByteArray(buf.readByteArray()) - ServerEditorManager.updateEditorState(player.uuid, state) - - val buffer = PacketByteBufs.create() - buffer.writeByteArray(Cbor.encodeToByteArray(GimbalPolicy(GimbalPolicyType.ALLOWED))) - ServerPlayNetworking.send(player, PacketIDs.TRANSFER_GIMBLE_POLICY_ID, buffer) + private fun isPlayerAllowedToUseGimbal(player: ServerPlayerEntity): Boolean { + return player.hasPermissionLevel(2) || Permissions.check(player, PermissionIDs.GIMBAL_USAGE_PERMISSION) } } diff --git a/src/main/resources/gimbal.mixins.json b/src/main/resources/gimbal.mixins.json index 2b67f6d..1b47528 100644 --- a/src/main/resources/gimbal.mixins.json +++ b/src/main/resources/gimbal.mixins.json @@ -11,7 +11,6 @@ "client": [ "BulldozerMixin", "BulldozerMixin2", - "GimbalPolicyCheckMixin", "HudMixin", "NoClipCameraFixMixin", "NormalModeMixin", diff --git a/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt b/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt index 5b12b57..d90f0ff 100644 --- a/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt +++ b/src/main/templates/net/moonleay/gimbal/build/BuildConstants.kt @@ -22,4 +22,6 @@ internal object BuildConstants { const val modId = "${modId}" const val modName = "${modName}" const val modVersion = "${modVersion}" + const val protocolVersion = "${protocolVersion}" } +