Adding events

Triggers, listeners etc.
This commit is contained in:
samo_lego 2019-10-31 14:11:03 +01:00
parent a9015b521e
commit b98f627875
16 changed files with 353 additions and 18 deletions

View File

@ -21,7 +21,19 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// jBCrypt library for password hashing
implementation "org.mindrot:jbcrypt:0.4" 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. // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them. // You may need to force-disable transitiveness on them.

View File

@ -15,4 +15,5 @@ org.gradle.jvmargs=-Xmx1G
# Dependencies # Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api # 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 fabric_version=0.3.2+build.218-1.14
# textilelib
textilelib_version=1.0.0-SNAPSHOT textilelib_version=1.0.0-SNAPSHOT

View File

@ -2,10 +2,18 @@ package org.samo_lego.simpleauth;
import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.fabric.api.registry.CommandRegistry; import net.fabricmc.fabric.api.registry.CommandRegistry;
import net.minecraft.server.network.ServerPlayerEntity;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.samo_lego.simpleauth.commands.LoginCommand; import org.samo_lego.simpleauth.commands.LoginCommand;
import org.samo_lego.simpleauth.commands.RegisterCommand; 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 { public class SimpleAuth implements DedicatedServerModInitializer {
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
@ -14,11 +22,22 @@ public class SimpleAuth implements DedicatedServerModInitializer {
public void onInitializeServer() { public void onInitializeServer() {
// Info I guess :D // Info I guess :D
LOGGER.info("SimpleAuth mod by samo_lego."); LOGGER.info("SimpleAuth mod by samo_lego.");
LOGGER.info("This mod wouldn't exist without the awesome Fabric Community. TYSM guys!");
// Registering the commands // Registering the commands
CommandRegistry.INSTANCE.register(false, dispatcher -> { CommandRegistry.INSTANCE.register(false, dispatcher -> {
RegisterCommand.register(dispatcher); RegisterCommand.register(dispatcher);
LoginCommand.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<ServerPlayerEntity> authenticatedUsers = new HashSet<>();
public static boolean isAuthenticated(ServerPlayerEntity player) { return authenticatedUsers.contains(player); }
} }

View File

@ -1,10 +1,13 @@
package org.samo_lego.simpleauth.commands; package org.samo_lego.simpleauth.commands;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import org.mindrot.jbcrypt.BCrypt; 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.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.word; import static com.mojang.brigadier.arguments.StringArgumentType.word;
@ -24,13 +27,18 @@ public class LoginCommand {
})); }));
} }
// Method called for checking the password // 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 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 // 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"); Text text = new LiteralText(source.getName() + ", you have entered login command");
source.getMinecraftServer().getPlayerManager().broadcastChatMessage(text, false); source.getMinecraftServer().getPlayerManager().broadcastChatMessage(text, false);
SimpleAuth.authenticatedUsers.add(player);
System.out.println(SimpleAuth.authenticatedUsers);
} }
return 1; // Success return 1; // Success
} }

View File

@ -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;
}
}

View File

@ -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<BlockDropsCallback> 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<ItemStack> drops, @Nullable PlayerEntity harvester, ItemStack tool);
}

View File

@ -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<EntitySpawnCallback> 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);
}

View File

@ -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<BreakBlockCallback> 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);
}

View File

@ -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<InteractBlockCallback> 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);
}

View File

@ -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<InteractItemCallback> 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);
}

View File

@ -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<PlayerJoinWorldCallback> 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);
}

View File

@ -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();
}
}
}

View File

@ -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<Boolean> 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<ActionResult> 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<ActionResult> info){
// Callback
ActionResult result = InteractItemCallback.EVENT.invoker().onInteractItem((ServerPlayerEntity) playerEntity_1);
if(result == ActionResult.FAIL) {
info.cancel();
}
}
}

View File

@ -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<Boolean> 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);
}
}
}
}

View File

@ -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!");
}
}

View File

@ -5,7 +5,8 @@
"mixins": [ "mixins": [
], ],
"server": [ "server": [
"SimpleAuthMixin" "MixinServerPlayerInteractionManager",
"MixinServerWorld"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1