feat: added permission checks to server, reworked login process, upgraded gradle, upgraded loom

Signed-off-by: moonleay <contact@moonleay.net>
This commit is contained in:
moonleay 2024-05-01 18:42:50 +02:00
parent 8203d74b90
commit 8b7e576d3d
Signed by: moonleay
GPG key ID: 82667543CCD715FB
14 changed files with 136 additions and 74 deletions

View file

@ -34,6 +34,13 @@ val mavenVersion = System.getenv("CI_COMMIT_TAG") ?: System.getenv("CI_COMMIT_SH
val modId: String by project val modId: String by project
val modName: String by project val modName: String by project
/*
* Gimbal version stuff
* */
val gimbalProtocolVersion = 2
val mavenGroup: String by project val mavenGroup: String by project
val mavenArtifact: String by project val mavenArtifact: String by project
@ -50,6 +57,9 @@ group = mavenGroup
project.base.archivesName.set(mavenArtifact) project.base.archivesName.set(mavenArtifact)
repositories { repositories {
maven { // Dependency api
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
} }
fabricApi { fabricApi {
@ -66,6 +76,10 @@ dependencies {
modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion") modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion")
modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") modImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
modApi("me.lucko:fabric-permissions-api:0.2-SNAPSHOT")
{
exclude(group = "net.fabricmc")
}
} }
val targetJavaVersion = 17 val targetJavaVersion = 17
@ -76,6 +90,7 @@ val templateProps = mapOf(
"modVersion" to project.version as String, "modVersion" to project.version as String,
"modId" to modId, "modId" to modId,
"modName" to modName, "modName" to modName,
"protocolVersion" to gimbalProtocolVersion,
"minecraftVersion" to minecraftVersion, "minecraftVersion" to minecraftVersion,
"fabricLoaderVersion" to fabricLoaderVersion, "fabricLoaderVersion" to fabricLoaderVersion,
"fabricKotlinVersion" to fabricKotlinVersion, "fabricKotlinVersion" to fabricKotlinVersion,

View file

@ -18,7 +18,7 @@
#Generated by fabric-mod-template #Generated by fabric-mod-template
#Sun Apr 21 19:29:15 CEST 2024 #Sun Apr 21 19:29:15 CEST 2024
fabric.loom.version=1.4.6 fabric.loom.version=1.6-SNAPSHOT
kotlin.version=1.9.22 kotlin.version=1.9.22
fabric.api.version=0.77.0+1.19.2 fabric.api.version=0.77.0+1.19.2
yarn.version=1.19.2+build.28 yarn.version=1.19.2+build.28

View file

@ -18,7 +18,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View file

@ -19,6 +19,7 @@
package net.moonleay.gimbal package net.moonleay.gimbal
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.networking.GimbalServer import net.moonleay.gimbal.networking.GimbalServer
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
@ -31,6 +32,11 @@ internal object Main : ModInitializer {
LOGGER.info("Registering packets...") LOGGER.info("Registering packets...")
GimbalServer.registerPacketHandler() GimbalServer.registerPacketHandler()
LOGGER.info("Packets have been registered.") 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("Gimbal has been initialized on the common side.")
LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay") LOGGER.info("${BuildConstants.modName} (${BuildConstants.modId}) v.${BuildConstants.modVersion} by moonleay")
} }

View file

@ -20,7 +20,9 @@ package net.moonleay.gimbal.client
import net.fabricmc.api.ClientModInitializer import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents 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.build.BuildConstants
import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.client.keybindings.KeybindingManager import net.moonleay.gimbal.client.keybindings.KeybindingManager
import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar import net.moonleay.gimbal.client.keybindings.KeybindingRegistrar
import net.moonleay.gimbal.networking.GimbalClient import net.moonleay.gimbal.networking.GimbalClient
@ -33,7 +35,7 @@ internal object ClientMain : ClientModInitializer {
override fun onInitializeClient() { override fun onInitializeClient() {
LOGGER.info("Initializing Gimbal on the client side...") LOGGER.info("Initializing Gimbal on the client side...")
KeybindingRegistrar.registerKeybindings() KeybindingRegistrar.registerKeybindings()
registerEvents() this.registerEvents()
LOGGER.info("Registering packets...") LOGGER.info("Registering packets...")
GimbalClient.registerPacketHandlers() GimbalClient.registerPacketHandlers()
LOGGER.info("Packets have been registered.") LOGGER.info("Packets have been registered.")
@ -45,6 +47,10 @@ internal object ClientMain : ClientModInitializer {
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client -> ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client ->
KeybindingManager.onClientTick(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.") LOGGER.info("Client events have been registered.")
} }

View file

@ -24,11 +24,11 @@ import net.moonleay.gimbal.client.util.ChatUtil
import net.moonleay.gimbal.editor.ServerEditorManager import net.moonleay.gimbal.editor.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType 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.Capability
import net.moonleay.gimbal.editor.state.mode.Mode import net.moonleay.gimbal.editor.state.mode.Mode
import net.moonleay.gimbal.editor.state.mode.ModeModifier import net.moonleay.gimbal.editor.state.mode.ModeModifier
import net.moonleay.gimbal.editor.util.EditorUtil import net.moonleay.gimbal.editor.util.EditorUtil
import net.moonleay.gimbal.editor.util.GimbalPolicy
import net.moonleay.gimbal.networking.GimbalClient import net.moonleay.gimbal.networking.GimbalClient
object ClientEditor { object ClientEditor {
@ -45,12 +45,6 @@ object ClientEditor {
fun onConnectedToNewWorld() { fun onConnectedToNewWorld() {
POLICY = GimbalPolicyType.NOT_PRESENT POLICY = GimbalPolicyType.NOT_PRESENT
GimbalClient.checkIfServerHasGimble(
EditorState(
CURRENT_MODE,
CURRENT_MODE_MODIFIER
)
)
if (TEMP_DISABLED_MODE == Mode.UNKNOWN) { if (TEMP_DISABLED_MODE == Mode.UNKNOWN) {
TEMP_DISABLED_MODE = TEMP_DISABLED_MODE =
CURRENT_MODE CURRENT_MODE
@ -62,9 +56,9 @@ object ClientEditor {
CURRENT_MODE_MODIFIER.clear() CURRENT_MODE_MODIFIER.clear()
} }
fun onAllowedCheck(data: GimbalPolicy) { fun onPolicyReceived(data: GimbalServerState, shouldUpdateServer: Boolean = true) {
POLICY = data.policy POLICY = data.policyType
if (data.policy == GimbalPolicyType.ALLOWED) { if (data.policyType == GimbalPolicyType.ALLOWED) {
if (TEMP_DISABLED_MODE != Mode.UNKNOWN) { if (TEMP_DISABLED_MODE != Mode.UNKNOWN) {
CURRENT_MODE = CURRENT_MODE =
TEMP_DISABLED_MODE TEMP_DISABLED_MODE
@ -74,7 +68,13 @@ object ClientEditor {
DISABLED_MODIFIERS_STORAGE DISABLED_MODIFIERS_STORAGE
) )
DISABLED_MODIFIERS_STORAGE.clear() 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 * Send an updated player state to the server
* */ * */
private fun updateServerState() { private fun updateServerState() {
val state = EditorState( val state = this.getClientState()
CURRENT_MODE, GimbalClient.sendStatePacket(state)
CURRENT_MODE_MODIFIER
)
GimbalClient.sendEditorState(state)
ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state) ServerEditorManager.updateEditorState(MinecraftClient.getInstance().player!!.uuid, state)
} }
@ -150,17 +147,17 @@ object ClientEditor {
onUpdated() onUpdated()
} }
private fun onUpdated() { private fun onUpdated(shouldUpdateServer: Boolean = true) {
CURRENT_MODE_MODIFIER.sortBy { CURRENT_MODE_MODIFIER.sortBy {
it.displayName it.displayName
} }
checkForIncompatibleModeModifiers() checkForIncompatibleModeModifiers(shouldUpdateServer)
} }
/** /**
* This runs on Mode updated * This runs on Mode updated
*/ */
private fun checkForIncompatibleModeModifiers() { private fun checkForIncompatibleModeModifiers(shouldUpdateServer: Boolean = true) {
if (TEMP_DISABLED_MODIFIERS.size > 0) { if (TEMP_DISABLED_MODIFIERS.size > 0) {
CURRENT_MODE_MODIFIER.addAll( CURRENT_MODE_MODIFIER.addAll(
TEMP_DISABLED_MODIFIERS TEMP_DISABLED_MODIFIERS
@ -185,6 +182,7 @@ object ClientEditor {
} }
// Update State // Update State
if (shouldUpdateServer)
updateServerState() updateServerState()
if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) { if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
@ -230,4 +228,8 @@ object ClientEditor {
fun getCurrentColor(): Int { fun getCurrentColor(): Int {
return CURRENT_MODE.color return CURRENT_MODE.color
} }
fun getClientState(): EditorState {
return EditorState(CURRENT_MODE, CURRENT_MODE_MODIFIER)
}
} }

View file

@ -16,14 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package net.moonleay.gimbal.networking package net.moonleay.gimbal.constants
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.moonleay.gimbal.build.BuildConstants import net.moonleay.gimbal.build.BuildConstants
object PacketIDs { object PacketIDs {
val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state") val UPDATE_EDITOR_STATE_ID = Identifier(BuildConstants.modId, "update_editor_state")
val GIMBLE_PRERENCE_CHECK_ID = Identifier(BuildConstants.modId, "gimble_preference_check") val GIMBAL_POLICY_PACKET_ID = Identifier(BuildConstants.modId, "gimble_policy")
val TRANSFER_GIMBLE_POLICY_ID = Identifier(BuildConstants.modId, "gimble_is_present")
} }

View file

@ -16,21 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package net.moonleay.gimbal.mixin; package net.moonleay.gimbal.constants
import net.minecraft.client.gui.screen.DownloadingTerrainScreen; object PermissionIDs {
import net.moonleay.gimbal.client.editor.ClientEditor; const val GIMBAL_USAGE_PERMISSION = "gimbal.use"
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();
}
} }

View file

@ -18,8 +18,11 @@
package net.moonleay.gimbal.editor.state package net.moonleay.gimbal.editor.state
import kotlinx.serialization.Serializable
@Serializable
enum class GimbalPolicyType { enum class GimbalPolicyType {
ALLOWED, ALLOWED,
DENIED, DENIED,
NOT_PRESENT NOT_PRESENT,
} }

View file

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

View file

@ -25,38 +25,46 @@ import kotlinx.serialization.encodeToByteArray
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.minecraft.network.PacketByteBuf import net.minecraft.network.PacketByteBuf
import net.moonleay.gimbal.build.BuildConstants
import net.moonleay.gimbal.client.editor.ClientEditor import net.moonleay.gimbal.client.editor.ClientEditor
import net.moonleay.gimbal.constants.PacketIDs
import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.util.GimbalPolicy import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.state.GimbalServerState
object GimbalClient { object GimbalClient {
fun registerPacketHandlers() { fun registerPacketHandlers() {
ClientPlayNetworking.registerGlobalReceiver(PacketIDs.TRANSFER_GIMBLE_POLICY_ID) { _, _, buf, _ -> ClientPlayNetworking.registerGlobalReceiver(PacketIDs.GIMBAL_POLICY_PACKET_ID) { _, _, buf, handler ->
onAllowedCheck(buf) 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) @OptIn(ExperimentalSerializationApi::class)
private fun onAllowedCheck(buf: PacketByteBuf) { private fun getServerState(buf: PacketByteBuf): GimbalServerState {
val policy = Cbor.decodeFromByteArray<GimbalPolicy>(buf.readByteArray()) val serverState = Cbor.decodeFromByteArray<GimbalServerState>(buf.readByteArray())
ClientEditor.onAllowedCheck(policy) // Update the client's policy return serverState
}
private fun isGimbalUsable(state: GimbalServerState): Boolean {
return state.policyType == GimbalPolicyType.ALLOWED && state.protocolVersion.toString() == BuildConstants.protocolVersion
} }
/**
* Sends the given [EditorState] to the server.
*/
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
fun sendEditorState(state: EditorState) { private fun createStatePacket(state: EditorState): PacketByteBuf {
val buf = PacketByteBufs.create() val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state)) buf.writeByteArray(Cbor.encodeToByteArray(state))
ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, buf) return buf
} }
@OptIn(ExperimentalSerializationApi::class) fun sendStatePacket(state: EditorState) {
fun checkIfServerHasGimble(state: EditorState) { ClientPlayNetworking.send(PacketIDs.UPDATE_EDITOR_STATE_ID, createStatePacket(state))
val buf = PacketByteBufs.create()
buf.writeByteArray(Cbor.encodeToByteArray(state))
ClientPlayNetworking.send(PacketIDs.GIMBLE_PRERENCE_CHECK_ID, buf)
} }
} }

View file

@ -21,28 +21,41 @@ package net.moonleay.gimbal.networking
import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray 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.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.network.PacketByteBuf import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity 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.ServerEditorManager
import net.moonleay.gimbal.editor.state.EditorState import net.moonleay.gimbal.editor.state.EditorState
import net.moonleay.gimbal.editor.state.GimbalPolicyType import net.moonleay.gimbal.editor.state.GimbalPolicyType
import net.moonleay.gimbal.editor.util.GimbalPolicy import net.moonleay.gimbal.editor.state.GimbalServerState
object GimbalServer { object GimbalServer {
fun registerPacketHandler() { fun registerPacketHandler() {
ServerPlayNetworking ServerPlayNetworking
.registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID) .registerGlobalReceiver(PacketIDs.UPDATE_EDITOR_STATE_ID)
{ server, player, handler, buf, responseSender -> { _, player, _, buf, _ ->
handleStateUpdate(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){ private fun handleStateUpdate(player: ServerPlayerEntity, buf: PacketByteBuf){
@ -51,12 +64,7 @@ object GimbalServer {
// player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}")) // player.sendMessage(Text.of("Mode: ${state.editorMode} with ${state.editorModifier}"))
} }
private fun handlePresenceCheck(player: ServerPlayerEntity, buf: PacketByteBuf) { private fun isPlayerAllowedToUseGimbal(player: ServerPlayerEntity): Boolean {
val state = Cbor.decodeFromByteArray<EditorState>(buf.readByteArray()) return player.hasPermissionLevel(2) || Permissions.check(player, PermissionIDs.GIMBAL_USAGE_PERMISSION)
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)
} }
} }

View file

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

View file

@ -22,4 +22,6 @@ internal object BuildConstants {
const val modId = "${modId}" const val modId = "${modId}"
const val modName = "${modName}" const val modName = "${modName}"
const val modVersion = "${modVersion}" const val modVersion = "${modVersion}"
const val protocolVersion = "${protocolVersion}"
} }