diff --git a/build.gradle b/build.gradle index f668d81..98772bd 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ dependencies { //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" diff --git a/gradle.properties b/gradle.properties index 55147d4..6d32782 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,12 +2,12 @@ org.gradle.jvmargs=-Xmx1G # Fabric properties -minecraft_version=20w10a -yarn_mappings=20w10a+build.16 +minecraft_version=20w11a +yarn_mappings=20w11a+build.6 loader_version=0.7.8+build.187 #Fabric api -fabric_version=0.5.1+build.305-1.16 +fabric_version=0.5.3+build.308-1.16 # Mod Properties mod_version = 1.2.0 diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index 6fe88f5..5e8f9d9 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -4,7 +4,10 @@ import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.event.player.*; import net.fabricmc.fabric.api.event.server.ServerStopCallback; import net.fabricmc.fabric.api.registry.CommandRegistry; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import org.apache.logging.log4j.LogManager; @@ -19,16 +22,24 @@ import org.samo_lego.simpleauth.event.item.DropItemCallback; import org.samo_lego.simpleauth.utils.AuthConfig; import java.io.File; +import java.util.HashMap; import java.util.HashSet; public class SimpleAuth implements DedicatedServerModInitializer { private static final Logger LOGGER = LogManager.getLogger(); + public static SimpleAuthDatabase db = new SimpleAuthDatabase(); + // HashSet of players that are not authenticated // Rather than storing all the authenticated players, we just store ones that are not authenticated - public static HashSet deauthenticatedUsers = new HashSet<>(); + public static HashMap deauthenticatedUsers = new HashMap<>(); + // Boolean for easier checking if player is authenticated - public static boolean isAuthenticated(ServerPlayerEntity player) { return !deauthenticatedUsers.contains(player); } + public static boolean isAuthenticated(ServerPlayerEntity player) { + return !deauthenticatedUsers.containsKey(player); + } + // Getting game directory + public static final File gameDirectory = FabricLoader.getInstance().getGameDirectory(); // Mod config public static AuthConfig config; @@ -40,11 +51,11 @@ public class SimpleAuth implements DedicatedServerModInitializer { LOGGER.info("[SimpleAuth] This mod wouldn't exist without the awesome Fabric Community. TYSM guys!"); // Creating data directory (database and config files are stored there) - File file = new File("./mods/SimpleAuth"); + File file = new File(gameDirectory + "/mods/SimpleAuth"); if (!file.exists() && !file.mkdir()) LOGGER.error("[SimpleAuth] Error creating directory!"); // Loading config - config = AuthConfig.load(new File("./mods/SimpleAuth/config.json")); + config = AuthConfig.load(new File(gameDirectory + "/mods/SimpleAuth/config.json")); // Connecting to db db.openConnection(); // Making a table in the database @@ -77,7 +88,7 @@ public class SimpleAuth implements DedicatedServerModInitializer { db.close(); } public static void authenticatePlayer(ServerPlayerEntity player, Text msg) { - SimpleAuth.deauthenticatedUsers.remove(player); + deauthenticatedUsers.remove(player); // Player no longer needs to be invisible and invulnerable player.setInvulnerable(false); player.setInvisible(false); diff --git a/src/main/java/org/samo_lego/simpleauth/database/SimpleAuthDatabase.java b/src/main/java/org/samo_lego/simpleauth/database/SimpleAuthDatabase.java index d62520b..2c82070 100644 --- a/src/main/java/org/samo_lego/simpleauth/database/SimpleAuthDatabase.java +++ b/src/main/java/org/samo_lego/simpleauth/database/SimpleAuthDatabase.java @@ -2,6 +2,7 @@ package org.samo_lego.simpleauth.database; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.samo_lego.simpleauth.SimpleAuth; import java.sql.*; @@ -18,7 +19,7 @@ public class SimpleAuthDatabase { public void openConnection() { // SQLite connection string - String url = "jdbc:sqlite:mods/SimpleAuth/players.db"; + String url = "jdbc:sqlite:" + SimpleAuth.gameDirectory + "/mods/SimpleAuth/players.db"; try { conn = DriverManager.getConnection(url); } catch (SQLException e) { diff --git a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java index 502c6de..cfebee3 100644 --- a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java @@ -29,7 +29,7 @@ public class AuthEventHandler { // Player joining the server public static void onPlayerJoin(ServerPlayerEntity player) { - SimpleAuth.deauthenticatedUsers.add(player); + SimpleAuth.deauthenticatedUsers.put(player, 0); /*CompoundTag loginTries = new CompoundTag(); loginTries.putInt("loginTries", 0); player.saveToTag(loginTries); diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java index c571b28..7bce6d0 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java @@ -1,30 +1,88 @@ package org.samo_lego.simpleauth.mixin; +import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerSpawnPositionS2CPacket; +import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import org.samo_lego.simpleauth.event.entity.player.PlayerMoveCallback; import org.samo_lego.simpleauth.event.item.DropItemCallback; +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.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(PlayerEntity.class) public abstract class MixinPlayerEntity { // Thanks to PR https://github.com/FabricMC/fabric/pull/260 and AbusedLib https://github.com/abused/AbusedLib - @Inject(method = "dropItem(Lnet/minecraft/item/ItemStack;ZZ)Lnet/minecraft/entity/ItemEntity;", at = @At("INVOKE"), cancellable = true) - private void dropItem(ItemStack stack, boolean dropAtFeet, boolean saveThrower, CallbackInfoReturnable cir) { + @Inject(method = "dropItem(Lnet/minecraft/item/ItemStack;ZZ)Lnet/minecraft/entity/ItemEntity;", at = @At("HEAD"), cancellable = true) + private void dropItem(ItemStack stack, boolean throwRandomly, boolean retainOwnership, CallbackInfoReturnable cir) { + // Defining player + ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + + // Getting action result from auth event handler + ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player); + + if (result == ActionResult.FAIL) { + // Canceling the item drop, as well as giving the items back to player (and updating inv with packet) + player.inventory.insertStack(stack); + player.networkHandler.sendPacket( + new ScreenHandlerSlotUpdateS2CPacket( + -2, + player.inventory.selectedSlot, + player.inventory.getInvStack(player.inventory.selectedSlot)) + ); + // Packet for mouse-dropping inventory update + player.currentScreenHandler.sendContentUpdates(); + //player.networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(-1, -1, player.inventory.getCursorStack())); + cir.cancel(); + } + } + + // Player item dropping + @Inject(method = "dropSelectedItem(Z)Z", at = @At("HEAD"), cancellable = true) + private void dropSelectedItem(boolean dropEntireStack, CallbackInfoReturnable cir) { + //Testing purposes - todo - doesn't delete armor, but allows mouse dropping ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player); if (result == ActionResult.FAIL) { // Canceling the item drop, as well as giving the items back to player (and updating inv with packet) - player.giveItemStack(stack); - player.inventory.updateItems(); - cir.cancel(); + player.networkHandler.sendPacket( + new ScreenHandlerSlotUpdateS2CPacket( + -2, + player.inventory.selectedSlot, + player.inventory.getInvStack(player.inventory.selectedSlot)) + ); + player.networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(-1, -1, player.inventory.getCursorStack())); + cir.setReturnValue(false); + } + } + + // Player movement + @Inject(method = "travel(Lnet/minecraft/util/math/Vec3d;)V", at = @At("HEAD"), cancellable = true) + private void travel(Vec3d movementInput, CallbackInfo ci) { + ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + + ActionResult result = PlayerMoveCallback.EVENT.invoker().onPlayerMove(player); + + if (result == ActionResult.FAIL) { + // A bit ugly, I know. (we need to update player position) + player.teleport(player.getX(), player.getY(), player.getZ()); + ci.cancel(); } } } \ No newline at end of file diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerInventory.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerInventory.java new file mode 100644 index 0000000..4efb393 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerInventory.java @@ -0,0 +1,67 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventories; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import org.samo_lego.simpleauth.SimpleAuth; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.List; + +@Mixin(PlayerInventory.class) +public abstract class MixinPlayerInventory { + + @Final + @Shadow + public PlayerEntity player; + + @Inject(method="setInvStack(ILnet/minecraft/item/ItemStack;)V", at = @At(value = "HEAD"), cancellable = true) + private void setInvStack(int slot, ItemStack stack, CallbackInfo ci) { + /*ServerPlayerEntity player = (ServerPlayerEntity) this.player; + ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player); + + if (result == ActionResult.FAIL) { + player.inventory + player.networkHandler.sendPacket( + new ScreenHandlerSlotUpdateS2CPacket( + -2, + player.inventory.selectedSlot, + player.inventory.getInvStack(player.inventory.selectedSlot)) + ); + // Packet for mouse-dropping inventory update + player.currentScreenHandler.sendContentUpdates(); + ci.cancel(); + }*/ + System.out.println("Setting inv stack: " + slot + "(slot) " + stack.getCount()+ "(amount)" + stack.getItem().getTranslationKey() + "(item)"); + } + + // Thank you Giselbaer for the help provided! + @Inject(method = "takeInvStack(II)Lnet/minecraft/item/ItemStack;", at = @At(value = "RETURN"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) + private void takeInvStack(int slot, int amount, CallbackInfoReturnable cir, List list) { + + if(!SimpleAuth.isAuthenticated((ServerPlayerEntity) player)) { + // Getting back the default item count + int initialCount = player.inventory.getInvStack(slot).getCount() + amount; + // Getting itemstack that would be returned + ItemStack stack = list != null && !list.get(slot).isEmpty() ? Inventories.splitStack(list, slot, amount) : ItemStack.EMPTY; + System.out.println("takeInvStack: " + slot + "(slot) " + amount + "(amount)" + stack.getItem().getTranslationKey() + "(item)"); + + // Setting stack value back to default (before it was taken or dropped) + stack.setCount(initialCount); + + // Setting the stack back to inventory + player.inventory.setInvStack(slot, stack); + + cir.setReturnValue(stack); + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayNetworkHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayNetworkHandler.java index 5e2081c..f1f826f 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayNetworkHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayNetworkHandler.java @@ -1,10 +1,10 @@ package org.samo_lego.simpleauth.mixin; -import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; -import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.network.packet.c2s.play.*; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.ActionResult; +import org.samo_lego.simpleauth.SimpleAuth; import org.samo_lego.simpleauth.event.entity.player.ChatCallback; import org.samo_lego.simpleauth.event.entity.player.PlayerMoveCallback; import org.spongepowered.asm.mixin.Mixin; @@ -28,30 +28,11 @@ public abstract class MixinServerPlayNetworkHandler { ), cancellable = true ) - // todo: redirect packets to off-thread packet manager? private void onChatMessage(ChatMessageC2SPacket chatMessageC2SPacket_1, CallbackInfo ci) { ActionResult result = ChatCallback.EVENT.invoker().onPlayerChat(player, chatMessageC2SPacket_1); if (result == ActionResult.FAIL) { ci.cancel(); } } - - @Inject( - method="onPlayerMove(Lnet/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket;)V", - at = @At( - value = "INVOKE", - // Thanks to Liach for helping me out! - target = "net/minecraft/network/NetworkThreadUtils.forceMainThread(Lnet/minecraft/network/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/server/world/ServerWorld;)V", - shift = At.Shift.AFTER - ), - cancellable = true - ) - private void onPlayerMove(PlayerMoveC2SPacket playerMoveC2SPacket_1, CallbackInfo ci) { - ActionResult result = PlayerMoveCallback.EVENT.invoker().onPlayerMove(player); - if (result == ActionResult.FAIL) { - // A bit ugly, I know. (we need to update player position) - player.teleport(player.getX(), player.getY(), player.getZ()); - ci.cancel(); - } - } + // onClickWindow, onPickFromInventory todo*/ } diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java new file mode 100644 index 0000000..20e4279 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java @@ -0,0 +1,40 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import org.samo_lego.simpleauth.SimpleAuth; +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(ServerPlayerEntity.class) +public abstract class MixinServerPlayerEntity { + + @Inject(method = "onSlotUpdate(Lnet/minecraft/screen/ScreenHandler;ILnet/minecraft/item/ItemStack;)V", at = @At("HEAD"), cancellable = true) + private void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack, CallbackInfo ci) { + ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + + /*ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player); + + if (result == ActionResult.FAIL) { + // Canceling the item drop, as well as giving the items back to player (and updating inv with packet) + player.inventory.insertStack(stack); + player.networkHandler.sendPacket( + new ScreenHandlerSlotUpdateS2CPacket( + -2, + player.inventory.selectedSlot, + player.inventory.getInvStack(player.inventory.selectedSlot)) + ); + // Packet for mouse-dropping inventory update + player.currentScreenHandler.sendContentUpdates(); + }*/ + //player.networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(-1, -1, player.inventory.getCursorStack())); + if(!SimpleAuth.isAuthenticated(player)) { + System.out.println("onSlotUpdate: " + stack.getItem().getTranslationKey()); + //player.inventory.setInvStack(slotId, stack); + //ci.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index 90ef875..8d0e0ca 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -7,7 +7,9 @@ "server": [ "MixinServerPlayNetworkHandler", "MixinPlayerManager", - "MixinPlayerEntity" + "MixinPlayerEntity", + "MixinServerPlayerEntity", + "MixinPlayerInventory" ], "injectors": { "defaultRequire": 1