Finally! Better inventory protection.

This commit is contained in:
samo_lego 2020-03-28 20:11:38 +01:00
parent 1f274c3034
commit 0112004457
12 changed files with 106 additions and 178 deletions

View File

@ -2,12 +2,12 @@
org.gradle.jvmargs=-Xmx1G
# Fabric properties
minecraft_version=20w11a
yarn_mappings=20w11a+build.6
loader_version=0.7.8+build.187
minecraft_version=20w13a
yarn_mappings=20w13a+build.5
loader_version=0.7.8+build.189
#Fabric api
fabric_version=0.5.3+build.308-1.16
fabric_version=0.5.6+build.313-1.16
# Mod Properties
mod_version = 1.2.0

View File

@ -19,6 +19,7 @@ import org.samo_lego.simpleauth.event.entity.player.ChatCallback;
import org.samo_lego.simpleauth.event.entity.player.PlayerJoinServerCallback;
import org.samo_lego.simpleauth.event.entity.player.PlayerMoveCallback;
import org.samo_lego.simpleauth.event.item.DropItemCallback;
import org.samo_lego.simpleauth.event.item.TakeItemCallback;
import org.samo_lego.simpleauth.utils.AuthConfig;
import java.io.File;
@ -73,6 +74,7 @@ public class SimpleAuth implements DedicatedServerModInitializer {
// Registering the events
PlayerJoinServerCallback.EVENT.register(AuthEventHandler::onPlayerJoin);
DropItemCallback.EVENT.register(AuthEventHandler::onDropItem);
TakeItemCallback.EVENT.register(AuthEventHandler::onTakeItem);
ChatCallback.EVENT.register(AuthEventHandler::onPlayerChat);
PlayerMoveCallback.EVENT.register(AuthEventHandler::onPlayerMove);
// From Fabric API

View File

@ -42,9 +42,10 @@ public class LoginCommand {
player.sendMessage(alreadyAuthenticated);
return 0;
}
else if(SimpleAuth.deauthenticatedUsers.get(player) >= maxLoginTries && maxLoginTries != -1)
else if(SimpleAuth.deauthenticatedUsers.get(player) >= maxLoginTries && maxLoginTries != -1) {
player.networkHandler.disconnect(loginTriesExceeded);
return 0;
}
else if(SimpleAuth.config.main.enableGlobalPassword) {
if (AuthHelper.checkPass("globalPass", pass.toCharArray())) {
SimpleAuth.authenticatePlayer(player, successfullyAuthenticated);
@ -55,11 +56,19 @@ public class LoginCommand {
SimpleAuth.authenticatePlayer(player, successfullyAuthenticated);
return 1;
}
else if(maxLoginTries == 1)
// Kicking the player out
else if(maxLoginTries == 1) {
player.networkHandler.disconnect(wrongPassword);
return 0;
}
// Sending wrong pass message
player.sendMessage(wrongPassword);
SimpleAuth.deauthenticatedUsers.replace(player, SimpleAuth.deauthenticatedUsers.get(player) + 1);
// ++ the login tries
SimpleAuth.deauthenticatedUsers.replace(
player,
SimpleAuth.deauthenticatedUsers.getOrDefault(player, 0) + 1
);
return 0;
}

View File

@ -31,10 +31,7 @@ public class AuthEventHandler {
public static void onPlayerJoin(ServerPlayerEntity player) {
// Marking player as not authenticated, (re)setting login tries to zero
SimpleAuth.deauthenticatedUsers.put(player, 0);
/*CompoundTag loginTries = new CompoundTag();
loginTries.putInt("loginTries", 0);
player.saveToTag(loginTries);
player.writeCustomDataToTag(loginTries);*/
// Player not authenticated
// If clause actually not needed, since we add player to deauthenticated hashset above
if (!SimpleAuth.isAuthenticated(player)) {
@ -68,6 +65,7 @@ public class AuthEventHandler {
}
return ActionResult.PASS;
}
// Player movement
public static ActionResult onPlayerMove(PlayerEntity player) {
if(!SimpleAuth.isAuthenticated((ServerPlayerEntity) player) && !SimpleAuth.config.main.allowMovement) {
@ -111,6 +109,15 @@ public class AuthEventHandler {
}
return ActionResult.PASS;
}
// Changing inventory (item moving etc.)
public static ActionResult onTakeItem(PlayerEntity player) {
if(!SimpleAuth.isAuthenticated((ServerPlayerEntity) player) && !SimpleAuth.config.main.allowItemMoving) {
player.sendMessage(notAuthenticated());
return ActionResult.FAIL;
}
return ActionResult.PASS;
}
// Attacking an entity
public static ActionResult onAttackEntity(PlayerEntity player) {
if(!SimpleAuth.isAuthenticated((ServerPlayerEntity) player) && !SimpleAuth.config.main.allowEntityPunch) {

View File

@ -0,0 +1,20 @@
package org.samo_lego.simpleauth.event.item;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
public interface TakeItemCallback {
Event<TakeItemCallback> EVENT = EventFactory.createArrayBacked(TakeItemCallback.class, listeners -> (player) -> {
for (TakeItemCallback event : listeners) {
ActionResult result = event.onTakeItem(player);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult onTakeItem(PlayerEntity player);
}

View File

@ -1,61 +1,20 @@
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("HEAD"), cancellable = true)
private void dropItem(ItemStack stack, boolean throwRandomly, boolean retainOwnership, CallbackInfoReturnable<ItemEntity> 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<Boolean> cir) {
//Testing purposes - todo - doesn't delete armor, but allows mouse dropping
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player);
@ -71,18 +30,4 @@ public abstract class MixinPlayerEntity {
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();
}
}
}

View File

@ -1,67 +0,0 @@
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<ItemStack> cir, List<ItemStack> 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);
}
}
}

View File

@ -4,7 +4,6 @@ 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;
@ -34,5 +33,23 @@ public abstract class MixinServerPlayNetworkHandler {
ci.cancel();
}
}
// onClickWindow, onPickFromInventory todo*/
// onClickWindow, onPickFromInventory todo
@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();
}
}
}

View File

@ -1,40 +0,0 @@
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();
}
}
}

View File

@ -0,0 +1,34 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
import net.minecraft.screen.slot.Slot;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
import org.samo_lego.simpleauth.event.item.TakeItemCallback;
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.CallbackInfoReturnable;
@Mixin(Slot.class)
public abstract class MixinSlot {
// Denying item moving etc.
@Inject(method = "canTakeItems(Lnet/minecraft/entity/player/PlayerEntity;)Z", at = @At(value = "HEAD"), cancellable = true)
private void canTakeItems(PlayerEntity playerEntity, CallbackInfoReturnable<Boolean> cir) {
ServerPlayerEntity player = (ServerPlayerEntity) playerEntity;
ActionResult result = TakeItemCallback.EVENT.invoker().onTakeItem(player);
if (result == ActionResult.FAIL) {
// Canceling the item taking
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);
}
}
}

View File

@ -40,6 +40,8 @@ public class AuthConfig {
public boolean allowBlockPunch = false;
// Allows dropping items from inventory
public boolean allowItemDrop = false;
// Allows moving item through inventory
public boolean allowItemMoving = false;
// Allows item "use" - right click function (e.g. using a bow)
public boolean allowItemUse = false;
// Allows attacking mobs

View File

@ -8,8 +8,7 @@
"MixinServerPlayNetworkHandler",
"MixinPlayerManager",
"MixinPlayerEntity",
"MixinServerPlayerEntity",
"MixinPlayerInventory"
"MixinSlot"
],
"injectors": {
"defaultRequire": 1