diff --git a/build.gradle b/build.gradle index dce3048..849b5cb 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,19 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + // jBCrypt library for password hashing implementation "org.mindrot:jbcrypt:0.4" + implementation 'org.jetbrains:annotations:15.0' + + // TextileLib by NerdHubMC for events + /*repositories { + maven { + name = "NerdHub Maven" + url = "https://maven.abusedmaster.xyz" + } + } + modCompile "com.github.NerdHubMC:TextileLib:${textilelib_version}"*/ // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. diff --git a/gradle.properties b/gradle.properties index 5efb473..036a950 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,5 @@ org.gradle.jvmargs=-Xmx1G # Dependencies # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api fabric_version=0.3.2+build.218-1.14 + # textilelib textilelib_version=1.0.0-SNAPSHOT diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index e5eabd0..097f088 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -2,10 +2,18 @@ package org.samo_lego.simpleauth; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.registry.CommandRegistry; +import net.minecraft.server.network.ServerPlayerEntity; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.samo_lego.simpleauth.commands.LoginCommand; import org.samo_lego.simpleauth.commands.RegisterCommand; +import org.samo_lego.simpleauth.event.AuthEventHandler; +import org.samo_lego.simpleauth.event.entity.player.BreakBlockCallback; +import org.samo_lego.simpleauth.event.entity.player.InteractBlockCallback; +import org.samo_lego.simpleauth.event.entity.player.InteractItemCallback; +import org.samo_lego.simpleauth.event.entity.player.PlayerJoinWorldCallback; + +import java.util.HashSet; public class SimpleAuth implements DedicatedServerModInitializer { private static final Logger LOGGER = LogManager.getLogger(); @@ -14,11 +22,22 @@ public class SimpleAuth implements DedicatedServerModInitializer { public void onInitializeServer() { // Info I guess :D LOGGER.info("SimpleAuth mod by samo_lego."); + LOGGER.info("This mod wouldn't exist without the awesome Fabric Community. TYSM guys!"); // Registering the commands CommandRegistry.INSTANCE.register(false, dispatcher -> { RegisterCommand.register(dispatcher); LoginCommand.register(dispatcher); }); + + // Registering the events + InteractBlockCallback.EVENT.register(AuthEventHandler::onInteractBlock); + InteractItemCallback.EVENT.register(AuthEventHandler::onInteractItem); + PlayerJoinWorldCallback.EVENT.register((world, player) -> AuthEventHandler.onPlayerJoin(player)); + BreakBlockCallback.EVENT.register((world, pos, state, player) -> AuthEventHandler.onBlockBroken(player)); } + public static HashSet authenticatedUsers = new HashSet<>(); + + public static boolean isAuthenticated(ServerPlayerEntity player) { return authenticatedUsers.contains(player); } + } diff --git a/src/main/java/org/samo_lego/simpleauth/commands/LoginCommand.java b/src/main/java/org/samo_lego/simpleauth/commands/LoginCommand.java index ccbc74d..d7c2930 100644 --- a/src/main/java/org/samo_lego/simpleauth/commands/LoginCommand.java +++ b/src/main/java/org/samo_lego/simpleauth/commands/LoginCommand.java @@ -1,10 +1,13 @@ package org.samo_lego.simpleauth.commands; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import org.mindrot.jbcrypt.BCrypt; +import org.samo_lego.simpleauth.SimpleAuth; import static com.mojang.brigadier.arguments.StringArgumentType.getString; import static com.mojang.brigadier.arguments.StringArgumentType.word; @@ -24,13 +27,18 @@ public class LoginCommand { })); } // Method called for checking the password - private static int login(ServerCommandSource source, String pass) { + private static int login(ServerCommandSource source, String pass) throws CommandSyntaxException { String savedHashed = "judf"; // Hashed password provided upon registration + // Getting the player who send the command + ServerPlayerEntity player = source.getPlayer(); + // Comparing hashed password with one from the file - if(BCrypt.checkpw(pass, savedHashed)){ //From database + if(true/*BCrypt.checkpw(pass, savedHashed)*/){ //From database Text text = new LiteralText(source.getName() + ", you have entered login command"); source.getMinecraftServer().getPlayerManager().broadcastChatMessage(text, false); + SimpleAuth.authenticatedUsers.add(player); + System.out.println(SimpleAuth.authenticatedUsers); } return 1; // Success } diff --git a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java new file mode 100644 index 0000000..febfd16 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java @@ -0,0 +1,39 @@ +package org.samo_lego.simpleauth.event; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import org.samo_lego.simpleauth.SimpleAuth; + +public class AuthEventHandler { + public static void onPlayerJoin(ServerPlayerEntity player) { + // Player not authenticated + if (!SimpleAuth.isAuthenticated(player)) + System.out.println("Not authenticated!"); + } + + // Breaking block + public static boolean onBlockBroken(PlayerEntity player) { + // Player not authenticated + if (!SimpleAuth.isAuthenticated((ServerPlayerEntity) player)) + { + System.out.println("Not authenticated!"); + return true; + } + return false; + } + + // Interacting with block + public static ActionResult onInteractBlock(ServerPlayerEntity player) { + if(!SimpleAuth.authenticatedUsers.contains(player)) + return ActionResult.FAIL; + return ActionResult.PASS; + } + // Interacting with item + public static ActionResult onInteractItem(ServerPlayerEntity player) { + System.out.println("Called"); + if(!SimpleAuth.authenticatedUsers.contains(player)) + return ActionResult.FAIL; + return ActionResult.PASS; + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/block/BlockDropsCallback.java b/src/main/java/org/samo_lego/simpleauth/event/block/BlockDropsCallback.java new file mode 100644 index 0000000..eb7426c --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/block/BlockDropsCallback.java @@ -0,0 +1,31 @@ +package org.samo_lego.simpleauth.event.block; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public interface BlockDropsCallback { + + Event EVENT = EventFactory.createArrayBacked(BlockDropsCallback.class, listeners -> (world, pos, state, drops, harvester, tool) -> { + for(BlockDropsCallback callback : listeners) { + if(callback.onDrop(world, pos, state, drops, harvester, tool)) { + return true; + } + } + return false; + }); + + /** + * fired when a block is about to drop it's items + * + * @return {@code true} to cancel all drops + */ + boolean onDrop(World world, BlockPos pos, BlockState state, List drops, @Nullable PlayerEntity harvester, ItemStack tool); +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/entity/EntitySpawnCallback.java b/src/main/java/org/samo_lego/simpleauth/event/entity/EntitySpawnCallback.java new file mode 100644 index 0000000..6607dd6 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/entity/EntitySpawnCallback.java @@ -0,0 +1,24 @@ +package org.samo_lego.simpleauth.event.entity; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.Entity; + +public interface EntitySpawnCallback { + + Event EVENT = EventFactory.createArrayBacked(EntitySpawnCallback.class, listeners -> entity -> { + for(EntitySpawnCallback callback : listeners) { + if(callback.spawnEntity(entity)) { + return true; + } + } + return false; + }); + + /** + * fired when an entity is spawned + * + * @return {@code true} to stop the entity from spawning + */ + boolean spawnEntity(Entity entity); +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/entity/player/BreakBlockCallback.java b/src/main/java/org/samo_lego/simpleauth/event/entity/player/BreakBlockCallback.java new file mode 100644 index 0000000..5d03ff5 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/entity/player/BreakBlockCallback.java @@ -0,0 +1,28 @@ +package org.samo_lego.simpleauth.event.entity.player; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public interface BreakBlockCallback { + + Event EVENT = EventFactory.createArrayBacked(BreakBlockCallback.class, listeners -> (world, pos, state, player) -> { + for(BreakBlockCallback callback : listeners) { + if(callback.onBlockBroken(world, pos, state, player)) { + return true; + } + } + return false; + }); + + /** + * fired when a block is broken by a player + * + * @return {@code true} to cancel the event + */ + boolean onBlockBroken(World world, BlockPos pos, BlockState state, @Nullable PlayerEntity player); +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractBlockCallback.java b/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractBlockCallback.java new file mode 100644 index 0000000..11f9c1f --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractBlockCallback.java @@ -0,0 +1,20 @@ +package org.samo_lego.simpleauth.event.entity.player; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + +public interface InteractBlockCallback { + Event EVENT = EventFactory.createArrayBacked(InteractBlockCallback.class, + (listeners) -> (player) -> { + for (InteractBlockCallback event : listeners) { + ActionResult result = event.onInteractBlock(player); + if(result != ActionResult.PASS) { + return result; + } + } + return ActionResult.PASS; + }); + ActionResult onInteractBlock(ServerPlayerEntity player); +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractItemCallback.java b/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractItemCallback.java new file mode 100644 index 0000000..33acf6f --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/entity/player/InteractItemCallback.java @@ -0,0 +1,20 @@ +package org.samo_lego.simpleauth.event.entity.player; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + +public interface InteractItemCallback { + Event EVENT = EventFactory.createArrayBacked(InteractItemCallback.class, + (listeners) -> (player) -> { + for (InteractItemCallback event : listeners) { + ActionResult result = event.onInteractItem(player); + if(result != ActionResult.PASS) { + return result; + } + } + return ActionResult.PASS; + }); + ActionResult onInteractItem(ServerPlayerEntity player); +} diff --git a/src/main/java/org/samo_lego/simpleauth/event/entity/player/PlayerJoinWorldCallback.java b/src/main/java/org/samo_lego/simpleauth/event/entity/player/PlayerJoinWorldCallback.java new file mode 100644 index 0000000..28a9544 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/event/entity/player/PlayerJoinWorldCallback.java @@ -0,0 +1,20 @@ +package org.samo_lego.simpleauth.event.entity.player; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; + +public interface PlayerJoinWorldCallback { + + Event EVENT = EventFactory.createArrayBacked(PlayerJoinWorldCallback.class, listeners -> (world, player) -> { + for (PlayerJoinWorldCallback callback : listeners) { + callback.onPlayerJoin(world, player); + } + }); + + /** + * Fired when a player joins a world + */ + void onPlayerJoin(ServerWorld world, ServerPlayerEntity player); +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinBlockOld.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinBlockOld.java new file mode 100644 index 0000000..fef430f --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinBlockOld.java @@ -0,0 +1,29 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import org.samo_lego.simpleauth.event.block.BlockDropsCallback; +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; + + +//FIXME this needs a better implementation to catch all of a block's drops, not just those from getDroppedStacks +@Mixin(Block.class) +public abstract class MixinBlockOld { + + @Inject(method = "afterBreak", at = @At("HEAD"), cancellable = true) + private void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, CallbackInfo ci) { + if(!world.isClient && BlockDropsCallback.EVENT.invoker().onDrop(world, pos, state, Block.getDroppedStacks(state, (ServerWorld) world, pos, blockEntity), player, stack)) { + ci.cancel(); + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerInteractionManager.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerInteractionManager.java new file mode 100644 index 0000000..18eb303 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerInteractionManager.java @@ -0,0 +1,63 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.client.network.packet.BlockUpdateS2CPacket; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.samo_lego.simpleauth.SimpleAuth; +import org.samo_lego.simpleauth.event.entity.player.BreakBlockCallback; +import org.samo_lego.simpleauth.event.entity.player.InteractBlockCallback; +import org.samo_lego.simpleauth.event.entity.player.InteractItemCallback; +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; + +@Mixin(ServerPlayerInteractionManager.class) +public abstract class MixinServerPlayerInteractionManager { + + @Shadow public ServerWorld world; + + @Shadow public ServerPlayerEntity player; + + // We inject the following code to tryBreakBlock method, by TextileLib + @Inject(method = "tryBreakBlock", at = @At("HEAD"), cancellable = true) + private void tryBreakBlock(BlockPos pos, CallbackInfoReturnable info) { + // Triggering the event + if(BreakBlockCallback.EVENT.invoker().onBlockBroken(world, pos, world.getBlockState(pos), player)) { + /*// Update client as they will believe they have broken the block. + if(this.player != null) { + this.player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos)); + }*/ + info.setReturnValue(false); + } + } + + // Interacting with blocks + @Inject(method="interactBlock", at = @At("HEAD"), cancellable = true) + private void interactBlock(PlayerEntity playerEntity_1, World world_1, ItemStack itemStack_1, Hand hand_1, BlockHitResult blockHitResult_1, CallbackInfoReturnable info){ + // Callback + ActionResult result = InteractBlockCallback.EVENT.invoker().onInteractBlock((ServerPlayerEntity) playerEntity_1); + if(result == ActionResult.FAIL) { + info.cancel(); + } + } + + // Interacting with items + @Inject(method="interactItem", at = @At("HEAD"), cancellable = true) + private void interactItem(PlayerEntity playerEntity_1, World world_1, ItemStack itemStack_1, Hand hand_1, CallbackInfoReturnable info){ + // Callback + ActionResult result = InteractItemCallback.EVENT.invoker().onInteractItem((ServerPlayerEntity) playerEntity_1); + if(result == ActionResult.FAIL) { + info.cancel(); + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerWorld.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerWorld.java new file mode 100644 index 0000000..f3fa7ed --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerWorld.java @@ -0,0 +1,35 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.samo_lego.simpleauth.event.entity.EntitySpawnCallback; +import org.samo_lego.simpleauth.event.entity.player.PlayerJoinWorldCallback; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ServerWorld.class) +public abstract class MixinServerWorld { + + @Inject(method = "addPlayer", at = @At("RETURN")) + private void method_18771(ServerPlayerEntity serverPlayerEntity, CallbackInfo ci) { + PlayerJoinWorldCallback.EVENT.invoker().onPlayerJoin(serverPlayerEntity.getServerWorld(), serverPlayerEntity); + } + + @Inject(method = "spawnEntity", at = @At("HEAD"), cancellable = true) + private void spawnEntity(Entity entity, CallbackInfoReturnable cir) { + int chunkX = MathHelper.floor(entity.x / 16.0D); + int chunkZ = MathHelper.floor(entity.z / 16.0D); + if(entity.teleporting || entity instanceof PlayerEntity || ((World) (Object) this).isChunkLoaded(chunkX, chunkZ)) { + if(EntitySpawnCallback.EVENT.invoker().spawnEntity(entity)) { + cir.setReturnValue(false); + } + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/SimpleAuthMixin.java b/src/main/java/org/samo_lego/simpleauth/mixin/SimpleAuthMixin.java deleted file mode 100644 index 31cb8d3..0000000 --- a/src/main/java/org/samo_lego/simpleauth/mixin/SimpleAuthMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.samo_lego.simpleauth.mixin; - -import net.minecraft.server.MinecraftServer; -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(MinecraftServer.class) -public class SimpleAuthMixin { - @Inject(at = @At("HEAD"), method = "start()V") - private void init(CallbackInfo info) { - System.out.println("This line is printed by an example mod mixin!"); - } -} diff --git a/src/main/resources/simpleauth.mixins.json b/src/main/resources/simpleauth.mixins.json index b81cd64..801d8ea 100644 --- a/src/main/resources/simpleauth.mixins.json +++ b/src/main/resources/simpleauth.mixins.json @@ -5,7 +5,8 @@ "mixins": [ ], "server": [ - "SimpleAuthMixin" + "MixinServerPlayerInteractionManager", + "MixinServerWorld" ], "injectors": { "defaultRequire": 1