mod for the islanders smp

too much shit to remember what I did

+5
README.md
··· 1 + # Islanders SMP mod 2 + 3 + ## Links 4 + 5 + Islanders Crown recipe: https://misode.github.io/recipe/?share=Ui1jvLH0gi
+2 -2
src/main/java/net/radsteve/islanders/mixin/CraftingResultSlotMixin.java
··· 5 5 import net.minecraft.item.Items; 6 6 import net.minecraft.screen.slot.CraftingResultSlot; 7 7 import net.minecraft.server.network.ServerPlayerEntity; 8 - import net.radsteve.islanders.IslandersCrown; 8 + import net.radsteve.islanders.SpecialItem; 9 9 import org.spongepowered.asm.mixin.Final; 10 10 import org.spongepowered.asm.mixin.Mixin; 11 11 import org.spongepowered.asm.mixin.Shadow; ··· 22 22 @Inject(method = "onCrafted(Lnet/minecraft/item/ItemStack;)V", at = @At("HEAD")) 23 23 private void islanders$onCrafted(ItemStack stack, CallbackInfo ci) { 24 24 if (stack.getItem() == Items.POPPED_CHORUS_FRUIT) { 25 - IslandersCrown.INSTANCE.onCraft((ServerPlayerEntity) player); 25 + SpecialItem.Crown.obtained((ServerPlayerEntity) player); 26 26 } 27 27 } 28 28 }
+3 -3
src/main/java/net/radsteve/islanders/mixin/GrindstoneScreenHandlerMixin.java
··· 4 4 import net.minecraft.item.ItemStack; 5 5 import net.minecraft.item.Items; 6 6 import net.minecraft.screen.GrindstoneScreenHandler; 7 - import net.radsteve.islanders.IslandersCrown; 7 + import net.radsteve.islanders.SpecialItem; 8 8 import org.spongepowered.asm.mixin.Final; 9 9 import org.spongepowered.asm.mixin.Mixin; 10 10 import org.spongepowered.asm.mixin.Shadow; ··· 24 24 @Inject(method = "updateResult", at = @At("HEAD"), cancellable = true) 25 25 private void islanders$updateResult(CallbackInfo ci) { 26 26 final ItemStack output = getOutputStack(input.getStack(0), input.getStack(1)); 27 - if (output.getItem().equals(Items.MACE) || IslandersCrown.INSTANCE.check(output)) { 28 - ci.cancel(); 27 + if (SpecialItem.Companion.find(output) != null) { 28 + ci.cancel(); 29 29 } 30 30 } 31 31 }
+26
src/main/java/net/radsteve/islanders/mixin/ItemStackMixin.java
··· 1 + package net.radsteve.islanders.mixin; 2 + 3 + import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 4 + import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 5 + import net.minecraft.item.Item; 6 + import net.minecraft.item.ItemStack; 7 + import net.radsteve.islanders.rule.RuleManager; 8 + import org.spongepowered.asm.mixin.Mixin; 9 + import org.spongepowered.asm.mixin.Shadow; 10 + 11 + @Mixin(ItemStack.class) 12 + public abstract class ItemStackMixin { 13 + @Shadow 14 + public abstract Item getItem(); 15 + 16 + @WrapMethod(method = "getMaxCount") 17 + private int islanders$getMaxCount(Operation<Integer> original) { 18 + final Integer limit = RuleManager.INSTANCE.limitFor(getItem()); 19 + 20 + if (limit == null) { 21 + return original.call(); 22 + } else { 23 + return limit; 24 + } 25 + } 26 + }
+1 -1
src/main/java/net/radsteve/islanders/mixin/LivingEntityMixin.java
··· 18 18 return; 19 19 } 20 20 21 - ItemDropCallback.Companion.getEVENT().invoker().onDrop(stack, (ServerPlayerEntity) (Object) this); 21 + ItemDropCallback.Companion.getEVENT().invoker().onDrop(stack, player); 22 22 } 23 23 }
+16 -4
src/main/java/net/radsteve/islanders/mixin/PlayerEntityMixin.java
··· 6 6 import net.minecraft.entity.player.PlayerEntity; 7 7 import net.minecraft.entity.player.PlayerInventory; 8 8 import net.minecraft.item.ItemStack; 9 - import net.minecraft.item.Items; 9 + import net.minecraft.scoreboard.Scoreboard; 10 10 import net.minecraft.server.world.ServerWorld; 11 - import net.radsteve.islanders.IslandersCrown; 12 11 import net.radsteve.islanders.ItemEffects; 12 + import net.radsteve.islanders.SpecialItem; 13 13 import org.spongepowered.asm.mixin.Final; 14 14 import org.spongepowered.asm.mixin.Mixin; 15 15 import org.spongepowered.asm.mixin.Shadow; ··· 18 18 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 19 19 20 20 @Mixin(PlayerEntity.class) 21 - public class PlayerEntityMixin { 21 + public abstract class PlayerEntityMixin { 22 22 @Shadow 23 23 @Final 24 24 PlayerInventory inventory; 25 25 26 + @Shadow 27 + public abstract Scoreboard getScoreboard(); 28 + 29 + @Shadow 30 + public abstract String getNameForScoreboard(); 31 + 26 32 @Inject(method = "dropInventory", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;dropAll()V")) 27 33 private void islanders$dropInventory(ServerWorld world, CallbackInfo ci) { 28 34 final LivingEntity entity = (LivingEntity) (Object) this; ··· 42 48 43 49 for (int idx = 0; idx < this.inventory.size(); idx++) { 44 50 ItemStack stack = this.inventory.getStack(idx); 45 - if (IslandersCrown.INSTANCE.check(stack) || stack.getItem() == Items.MACE || stack.getItem() == Items.DRAGON_EGG) { 51 + if (SpecialItem.Companion.find(stack) != null) { 46 52 ItemEffects.INSTANCE.getItemsToRegive().add(new Pair<>(stack, entity.getUuid())); 47 53 inventory.removeStack(idx); 48 54 } 49 55 } 56 + 57 + SpecialItem.getEntries().forEach(item -> { 58 + if (item.getTeam().getPlayerList().contains(getNameForScoreboard())) { 59 + getScoreboard().removeScoreHolderFromTeam(getNameForScoreboard(), item.getTeam()); 60 + } 61 + }); 50 62 } 51 63 }
+126 -4
src/main/java/net/radsteve/islanders/mixin/ScreenHandlerMixin.java
··· 1 1 package net.radsteve.islanders.mixin; 2 2 3 3 import net.minecraft.entity.player.PlayerEntity; 4 + import net.minecraft.inventory.EnderChestInventory; 4 5 import net.minecraft.item.ItemStack; 6 + import net.minecraft.registry.tag.ItemTags; 7 + import net.minecraft.screen.GenericContainerScreenHandler; 8 + import net.minecraft.screen.PlayerScreenHandler; 5 9 import net.minecraft.screen.ScreenHandler; 6 10 import net.minecraft.screen.slot.Slot; 7 11 import net.minecraft.screen.slot.SlotActionType; 8 12 import net.minecraft.server.network.ServerPlayerEntity; 9 13 import net.minecraft.util.collection.DefaultedList; 10 - import net.radsteve.islanders.event.ItemClickCallback; 14 + import net.radsteve.islanders.SpecialItem; 15 + import net.radsteve.islanders.event.ItemTransferCallback; 11 16 import org.spongepowered.asm.mixin.Final; 12 17 import org.spongepowered.asm.mixin.Mixin; 13 18 import org.spongepowered.asm.mixin.Shadow; ··· 25 30 @Shadow 26 31 public abstract void setCursorStack(ItemStack stack); 27 32 33 + @Shadow public abstract Slot getSlot(int index); 34 + 35 + @Shadow public abstract ItemStack getCursorStack(); 36 + 28 37 @Unique 29 38 private void islanders$runHandlers(int slotIdx, PlayerEntity player, CallbackInfo ci) { 30 39 final Slot slot = slots.get(slotIdx); 31 40 final ItemStack stack = slot.getStack(); 32 41 33 - if (ItemClickCallback.Companion.getEVENT().invoker().canClick(stack, (ServerPlayerEntity) player)) { 42 + if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(stack, (ServerPlayerEntity) player)) { 34 43 return; 35 44 } 36 45 setCursorStack(ItemStack.EMPTY); ··· 40 49 41 50 @Inject(method = "internalOnSlotClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/slot/Slot;canTakeItems(Lnet/minecraft/entity/player/PlayerEntity;)Z"), cancellable = true) 42 51 private void islanders$internalOnSlotClick$canTakeItems(int slotIdx, int button, SlotActionType slotActionType, PlayerEntity player, CallbackInfo ci) { 43 - islanders$runHandlers(slotIdx, player, ci); 52 + // islanders$runHandlers(slotIdx, player, ci); 44 53 } 45 54 46 55 @Inject(method = "internalOnSlotClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/slot/Slot;onTakeItem(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;)V"), cancellable = true) 47 56 private void islanders$internalOnSlotClick$onTakeItem(int slotIdx, int button, SlotActionType slotActionType, PlayerEntity player, CallbackInfo ci) { 48 - islanders$runHandlers(slotIdx, player, ci); 57 + // islanders$runHandlers(slotIdx, player, ci); 58 + } 59 + 60 + @Inject(method = "internalOnSlotClick", at = @At("HEAD"), cancellable = true) 61 + private void islanders$internalOnSlotClick$limits(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { 62 + if ((ScreenHandler) (Object) this instanceof PlayerScreenHandler) { 63 + return; 64 + } 65 + 66 + if (actionType == SlotActionType.QUICK_MOVE) { 67 + final Slot slot = slots.get(slotIndex); 68 + if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(slot.getStack(), (ServerPlayerEntity) player)) { 69 + return; 70 + } 71 + 72 + ci.cancel(); 73 + 74 + return; 75 + } 76 + 77 + final int actualScreenSlots = slots.size() - player.playerScreenHandler.slots.size() + 9 /* hotbar */; 78 + 79 + if (actionType == SlotActionType.SWAP) { 80 + final ItemStack stack = getSlot(slotIndex).getStack(); 81 + if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(stack, (ServerPlayerEntity) player)) { 82 + return; 83 + } 84 + 85 + ci.cancel(); 86 + 87 + return; 88 + } 89 + 90 + if (slotIndex < 0 || slotIndex > actualScreenSlots) { 91 + return; 92 + } 93 + 94 + if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(getCursorStack(), (ServerPlayerEntity) player)) { 95 + ci.cancel(); 96 + } 97 + } 98 + 99 + @Inject(method = "internalOnSlotClick", at = @At("HEAD"), cancellable = true) 100 + private void islanders$internalOnSlotClick$shulkerBoxes(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { 101 + if (!((ScreenHandler) (Object) this instanceof GenericContainerScreenHandler handler)) { 102 + return; 103 + } 104 + 105 + if (!(handler.getInventory() instanceof EnderChestInventory)) { 106 + return; 107 + } 108 + 109 + if (actionType == SlotActionType.QUICK_MOVE) { 110 + final Slot slot = slots.get(slotIndex); 111 + if (slot.getStack().getRegistryEntry().isIn(ItemTags.SHULKER_BOXES)) { 112 + ci.cancel(); 113 + } 114 + 115 + return; 116 + } 117 + 118 + final int actualScreenSlots = slots.size() - player.playerScreenHandler.slots.size() + 9 /* hotbar */; 119 + 120 + if (actionType == SlotActionType.SWAP) { 121 + final ItemStack stack = player.getInventory().getStack(button); 122 + if (stack.getRegistryEntry().isIn(ItemTags.SHULKER_BOXES)) { 123 + ci.cancel(); 124 + } 125 + 126 + return; 127 + } 128 + 129 + if (slotIndex < 0 || slotIndex > actualScreenSlots) { 130 + return; 131 + } 132 + 133 + if (getCursorStack().getRegistryEntry().isIn(ItemTags.SHULKER_BOXES)) { 134 + ci.cancel(); 135 + } 136 + } 137 + 138 + @Inject(method = "internalOnSlotClick", at = @At("HEAD"), cancellable = true) 139 + private void islanders$internalOnSlotClick$specialItems(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { 140 + if ((Object) this instanceof PlayerScreenHandler) { 141 + return; 142 + } 143 + 144 + if (actionType == SlotActionType.QUICK_MOVE) { 145 + final Slot slot = slots.get(slotIndex); 146 + if (SpecialItem.Companion.find(slot.getStack()) != null) { 147 + ci.cancel(); 148 + } 149 + 150 + return; 151 + } 152 + 153 + final int actualScreenSlots = slots.size() - player.playerScreenHandler.slots.size() + 9 /* hotbar */; 154 + 155 + if (actionType == SlotActionType.SWAP) { 156 + final ItemStack stack = player.getInventory().getStack(button); 157 + if (SpecialItem.Companion.find(stack) != null) { 158 + ci.cancel(); 159 + } 160 + 161 + return; 162 + } 163 + 164 + if (slotIndex < 0 || slotIndex > actualScreenSlots) { 165 + return; 166 + } 167 + 168 + if (SpecialItem.Companion.find(getCursorStack()) != null) { 169 + ci.cancel(); 170 + } 49 171 } 50 172 }
+1 -1
src/main/java/net/radsteve/islanders/mixin/ServerPlayNetworkHandlerMixin.java src/main/java/net/radsteve/islanders/mixin/BundleHandlerMixin.java
··· 24 24 /// This prevents special items from being put into bundles. 25 25 /// Time counter: 5h 26 26 @Mixin(ServerPlayNetworkHandler.class) 27 - public class ServerPlayNetworkHandlerMixin { 27 + public class BundleHandlerMixin { 28 28 @Shadow 29 29 public ServerPlayerEntity player; 30 30
+12 -12
src/main/java/net/radsteve/islanders/mixin/SlotMixin.java
··· 4 4 import net.minecraft.item.ItemStack; 5 5 import net.minecraft.screen.slot.Slot; 6 6 import net.minecraft.server.network.ServerPlayerEntity; 7 - import net.radsteve.islanders.event.ItemClickCallback; 7 + import net.radsteve.islanders.event.ItemTransferCallback; 8 8 import org.spongepowered.asm.mixin.Mixin; 9 9 import org.spongepowered.asm.mixin.Shadow; 10 10 import org.spongepowered.asm.mixin.injection.At; ··· 21 21 22 22 @Inject(method = "tryTakeStackRange", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/slot/Slot;takeStack(I)Lnet/minecraft/item/ItemStack;"), cancellable = true) 23 23 private void islanders$tryTakeStackRange(int min, int max, PlayerEntity player, CallbackInfoReturnable<Optional<ItemStack>> cir) { 24 - final ItemStack stack = getStack(); 25 - 26 - if (ItemClickCallback.Companion.getEVENT().invoker().canClick(stack, (ServerPlayerEntity) player)) { 27 - return; 28 - } 29 - cir.setReturnValue(Optional.empty()); 24 + // final ItemStack stack = getStack(); 25 + // 26 + // if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(stack, (ServerPlayerEntity) player)) { 27 + // return; 28 + // } 29 + // cir.setReturnValue(Optional.empty()); 30 30 } 31 31 32 32 @Inject(method = "onTakeItem", at = @At("HEAD"), cancellable = true) 33 33 private void islanders$onTakeItem(PlayerEntity player, ItemStack stack, CallbackInfo ci) { 34 - if (ItemClickCallback.Companion.getEVENT().invoker().canClick(stack, (ServerPlayerEntity) player)) { 35 - return; 36 - } 37 - 38 - ci.cancel(); 34 + // if (ItemTransferCallback.Companion.getEVENT().invoker().canTransfer(stack, (ServerPlayerEntity) player)) { 35 + // return; 36 + // } 37 + // 38 + // ci.cancel(); 39 39 } 40 40 }
+2
src/main/kotlin/net/radsteve/islanders/Islanders.kt
··· 9 9 import net.minecraft.server.MinecraftServer 10 10 import net.radsteve.islanders.command.animacetionCommand 11 11 import net.radsteve.islanders.command.ruleCommand 12 + import net.radsteve.islanders.rule.DefaultRules 12 13 import net.radsteve.islanders.rule.RuleHandlers 13 14 import org.slf4j.LoggerFactory 14 15 ··· 35 36 MaceRewards 36 37 IslandersData 37 38 MaceAnimation 39 + DefaultRules 38 40 39 41 logger.info("Initialised!") 40 42 }
-35
src/main/kotlin/net/radsteve/islanders/IslandersCrown.kt
··· 1 - package net.radsteve.islanders 2 - 3 - import net.minecraft.component.DataComponentTypes 4 - import net.minecraft.item.ItemStack 5 - import net.minecraft.item.Items 6 - import net.minecraft.server.network.ServerPlayerEntity 7 - import net.minecraft.sound.SoundCategory 8 - import net.minecraft.sound.SoundEvents 9 - import net.minecraft.text.Text 10 - import net.minecraft.util.Formatting 11 - 12 - // https://misode.github.io/recipe/?share=Ui1jvLH0gi 13 - public object IslandersCrown { 14 - public fun check(stack: ItemStack): Boolean { 15 - return stack.item == Items.POPPED_CHORUS_FRUIT && stack.get(DataComponentTypes.CUSTOM_MODEL_DATA)?.strings?.contains("islanders") == true 16 - } 17 - 18 - public fun onCraft(player: ServerPlayerEntity) { 19 - player.server.playerManager.broadcast( 20 - player.displayName!!.copy() 21 - .formatted(Formatting.RESET) 22 - .append( 23 - Text.literal(" has completed the challenge ") 24 - .append( 25 - Text.literal("[Obtain ").formatted(Formatting.AQUA) 26 - .append(Text.literal("Islanders Crown").formatted(Formatting.BOLD)) 27 - .append(Text.literal("]")), 28 - ) 29 - ), 30 - false 31 - ) 32 - player.playSoundToPlayer(SoundEvents.UI_TOAST_CHALLENGE_COMPLETE, SoundCategory.MASTER, 0.5f, 1f) 33 - IslandersData.obtainCrown(player.uuid) 34 - } 35 - }
+15
src/main/kotlin/net/radsteve/islanders/IslandersData.kt
··· 15 15 dir.createDirectories() 16 16 } 17 17 18 + public fun obtainer(id: String): UUID? { 19 + return dir.resolve("${id}_obtained") 20 + .takeIf(Path::exists) 21 + ?.let(Path::readText) 22 + ?.let(UUID::fromString) 23 + } 24 + 25 + public fun obtained(id: String): Boolean { 26 + return obtainer(id) != null 27 + } 28 + 29 + public fun obtained(id: String, by: UUID) { 30 + dir.resolve("${id}_obtained").writeText(by.toString()) 31 + } 32 + 18 33 public fun maceObtainer(): UUID? { 19 34 return dir.resolve("mace_obtained") 20 35 .takeIf(Path::exists)
+4 -198
src/main/kotlin/net/radsteve/islanders/ItemEffects.kt
··· 1 1 package net.radsteve.islanders 2 2 3 - import com.google.common.collect.Multimaps 4 3 import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents 5 4 import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents 6 - import net.minecraft.component.DataComponentTypes 7 - import net.minecraft.enchantment.Enchantments 8 - import net.minecraft.entity.attribute.EntityAttributeModifier 9 - import net.minecraft.entity.attribute.EntityAttributes 10 - import net.minecraft.entity.effect.StatusEffectInstance 11 - import net.minecraft.entity.effect.StatusEffects 12 5 import net.minecraft.item.ItemStack 13 - import net.minecraft.item.Items 14 6 import net.minecraft.server.MinecraftServer 15 7 import net.minecraft.server.network.ServerPlayerEntity 16 - import net.minecraft.sound.SoundCategory 17 - import net.minecraft.sound.SoundEvents 18 - import net.minecraft.text.Text 19 8 import net.minecraft.util.Formatting 20 - import net.minecraft.util.Identifier 21 - import net.minecraft.util.Unit 22 9 import net.radsteve.islanders.event.ItemDropCallback 23 10 import net.radsteve.islanders.event.ItemPickupCallback 24 11 import java.util.UUID ··· 52 39 53 40 override fun onEndTick(server: MinecraftServer) { 54 41 server.playerManager.playerList.forEach { player -> 55 - val hasEgg = player.inventory.contains { stack -> stack.item === Items.DRAGON_EGG } 56 - val isDarkPurple = player.nameForScoreboard in darkPurpleTeam.playerList 57 - if (hasEgg && !isDarkPurple) { 58 - player.scoreboard.addScoreHolderToTeam(player.nameForScoreboard, darkPurpleTeam) 59 - } else if (!hasEgg && isDarkPurple) { 60 - player.scoreboard.removeScoreHolderFromTeam(player.nameForScoreboard, darkPurpleTeam) 61 - } 62 - if (hasEgg) { 63 - if (!player.hasStatusEffect(StatusEffects.GLOWING)) { 64 - player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 65 - } 66 - player.addStatusEffect(StatusEffectInstance(StatusEffects.SPEED, 20, 0, true, false, false)) 67 - player.addStatusEffect(StatusEffectInstance(StatusEffects.HASTE, 20, 0, true, false, false)) 68 - player.addStatusEffect(StatusEffectInstance(StatusEffects.RESISTANCE, 20, 0, true, false, false)) 69 - player.addStatusEffect(StatusEffectInstance(StatusEffects.JUMP_BOOST, 20, 0, true, false, false)) 70 - player.addStatusEffect(StatusEffectInstance(StatusEffects.STRENGTH, 20, 0, true, false, false)) 71 - player.addStatusEffect(StatusEffectInstance(StatusEffects.REGENERATION, 20, 0, true, false, false)) 72 - } 73 - val mace = player.inventory.find { stack -> stack.item === Items.MACE } 74 - val hasMace = mace != null 75 - val isGold = player.nameForScoreboard in goldTeam.playerList 76 - if (hasMace && !isGold) { 77 - player.scoreboard.addScoreHolderToTeam(player.nameForScoreboard, goldTeam) 78 - player.attributes.addTemporaryModifiers( 79 - Multimaps.forMap( 80 - mapOf( 81 - EntityAttributes.MAX_HEALTH to EntityAttributeModifier( 82 - Identifier.of("islanders", "mace_health_boost"), 83 - 10.0, 84 - EntityAttributeModifier.Operation.ADD_VALUE 85 - ) 86 - ) 87 - ) 88 - ) 89 - mace.set(DataComponentTypes.UNBREAKABLE, Unit.INSTANCE) 90 - mace.enchant(Enchantments.WIND_BURST, 3) 91 - mace.enchant(Enchantments.DENSITY, 5) 92 - mace.enchant(Enchantments.FIRE_ASPECT, 2) 93 - } else if (!hasMace && isGold) { 94 - player.scoreboard.removeScoreHolderFromTeam(player.nameForScoreboard, goldTeam) 95 - player.attributes.getCustomInstance(EntityAttributes.MAX_HEALTH)?.clearModifiers() 96 - } 97 - if (hasMace && !player.hasStatusEffect(StatusEffects.GLOWING)) { 98 - player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 99 - } 100 - val hasCrown = player.inventory.contains(IslandersCrown::check) 101 - val isAqua = player.nameForScoreboard in aquaTeam.playerList 102 - 103 - if (hasCrown) { 104 - player.hungerManager.foodLevel = 19 105 - 106 - if (!isAqua) { 107 - player.scoreboard.addScoreHolderToTeam(player.nameForScoreboard, aquaTeam) 108 - } 109 - 110 - if (!player.hasStatusEffect(StatusEffects.GLOWING)) { 111 - player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 112 - } 42 + SpecialItem.entries.forEach { item -> 43 + item.handleEffects(player, player.inventory.firstOrNull(item::check)) 113 44 } 114 45 } 115 46 } 116 47 117 48 override fun onDrop(item: ItemStack, player: ServerPlayerEntity) { 118 - if (item.item == Items.DRAGON_EGG) { 119 - player.server.playerManager.broadcast( 120 - player.displayName!!.copy() 121 - .formatted(Formatting.RESET) 122 - .append( 123 - Text.literal(" dropped the ") 124 - .append(Text.literal("Dragon Egg").formatted(Formatting.DARK_PURPLE, Formatting.BOLD)) 125 - ), 126 - false 127 - ) 128 - player.server.playerManager.playerList.forEach { player -> 129 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT, SoundCategory.MASTER, 0.5f, 1f) 130 - } 131 - } 132 - 133 - if (item.item == Items.MACE) { 134 - player.server.playerManager.broadcast( 135 - player.displayName!!.copy() 136 - .formatted(Formatting.RESET) 137 - .append( 138 - Text.literal(" dropped the ") 139 - .append(Text.literal("Mace").formatted(Formatting.GOLD, Formatting.BOLD)) 140 - ), 141 - false 142 - ) 143 - player.server.playerManager.playerList.forEach { player -> 144 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT, SoundCategory.MASTER, 0.5f, 1f) 145 - } 146 - } 147 - 148 - if (IslandersCrown.check(item)) { 149 - player.server.playerManager.broadcast( 150 - player.displayName!!.copy() 151 - .formatted(Formatting.RESET) 152 - .append( 153 - Text.literal(" dropped the ") 154 - .append(Text.literal("Islanders Crown").formatted(Formatting.AQUA, Formatting.BOLD)) 155 - ), 156 - false 157 - ) 158 - player.server.playerManager.playerList.forEach { player -> 159 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT, SoundCategory.MASTER, 0.5f, 1f) 160 - } 161 - } 49 + SpecialItem.find(item)?.dropped(player) 162 50 } 163 51 164 52 override fun canPickUp(item: ItemStack, player: ServerPlayerEntity): Boolean { 165 - if (item.item == Items.DRAGON_EGG) { 166 - if (IslandersData.hasEggBeenObtained()) { 167 - player.server.playerManager.broadcast( 168 - player.displayName!!.copy() 169 - .formatted(Formatting.RESET) 170 - .append( 171 - Text.literal(" picked up the ") 172 - .append(Text.literal("Dragon Egg").formatted(Formatting.DARK_PURPLE, Formatting.BOLD)) 173 - ), 174 - false 175 - ) 176 - player.server.playerManager.playerList.forEach { player -> 177 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT_PLAYER, SoundCategory.MASTER, 0.5f, 1f) 178 - } 179 - } else { 180 - IslandersData.obtainEgg(player.uuid) 181 - 182 - player.server.playerManager.broadcast( 183 - player.displayName!!.copy() 184 - .formatted(Formatting.RESET) 185 - .append( 186 - Text.literal(" has completed the challenge ") 187 - .append( 188 - Text.literal("[Obtain ").formatted(Formatting.DARK_PURPLE) 189 - .append(Text.literal("Dragon Egg").formatted(Formatting.BOLD)) 190 - .append(Text.literal("]")), 191 - ) 192 - ), 193 - false 194 - ) 195 - player.playSound(SoundEvents.UI_TOAST_CHALLENGE_COMPLETE) 196 - } 197 - } 198 - 199 - if (item.item == Items.MACE) { 200 - if (IslandersData.hasMaceBeenObtained()) { 201 - player.server.playerManager.broadcast( 202 - player.displayName!!.copy() 203 - .formatted(Formatting.RESET) 204 - .append( 205 - Text.literal(" picked up the ") 206 - .append(Text.literal("Mace").formatted(Formatting.GOLD, Formatting.BOLD)) 207 - ), 208 - false 209 - ) 210 - player.server.playerManager.playerList.forEach { player -> 211 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT_PLAYER, SoundCategory.MASTER, 0.5f, 1f) 212 - } 213 - } else { 214 - IslandersData.obtainMace(player.uuid) 215 - 216 - player.server.playerManager.broadcast( 217 - player.displayName!!.copy() 218 - .formatted(Formatting.RESET) 219 - .append( 220 - Text.literal(" has completed the challenge ") 221 - .append( 222 - Text.literal("[Obtain ").formatted(Formatting.GOLD) 223 - .append(Text.literal("Mace").formatted(Formatting.BOLD)) 224 - .append(Text.literal("]")), 225 - ) 226 - ), 227 - false 228 - ) 229 - 230 - player.playSound(SoundEvents.UI_TOAST_CHALLENGE_COMPLETE) 231 - } 232 - } 233 - 234 - if (IslandersCrown.check(item)) { 235 - player.server.playerManager.broadcast( 236 - player.displayName!!.copy() 237 - .formatted(Formatting.RESET) 238 - .append( 239 - Text.literal(" picked up the ") 240 - .append(Text.literal("Islanders Crown").formatted(Formatting.AQUA, Formatting.BOLD)) 241 - ), 242 - false 243 - ) 244 - player.server.playerManager.playerList.forEach { player -> 245 - player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT_PLAYER, SoundCategory.MASTER, 0.5f, 1f) 246 - } 247 - } 53 + SpecialItem.find(item)?.pickedUp(player) 248 54 249 55 return true 250 56 }
+1
src/main/kotlin/net/radsteve/islanders/MaceAnimation.kt
··· 17 17 18 18 public object MaceAnimation : ServerTickEvents.EndTick { 19 19 init { 20 + // play it at double speed for double swag 20 21 ServerTickEvents.END_SERVER_TICK.register(this) 21 22 ServerTickEvents.END_SERVER_TICK.register(this) 22 23 }
+185
src/main/kotlin/net/radsteve/islanders/SpecialItem.kt
··· 1 + package net.radsteve.islanders 2 + 3 + import com.google.common.collect.Multimaps 4 + import net.minecraft.component.DataComponentTypes 5 + import net.minecraft.enchantment.Enchantments 6 + import net.minecraft.entity.attribute.EntityAttributeModifier 7 + import net.minecraft.entity.attribute.EntityAttributes 8 + import net.minecraft.entity.effect.StatusEffectInstance 9 + import net.minecraft.entity.effect.StatusEffects 10 + import net.minecraft.item.ItemStack 11 + import net.minecraft.item.Items 12 + import net.minecraft.scoreboard.Team 13 + import net.minecraft.server.network.ServerPlayerEntity 14 + import net.minecraft.sound.SoundCategory 15 + import net.minecraft.sound.SoundEvents 16 + import net.minecraft.text.Text 17 + import net.minecraft.util.Formatting 18 + import net.minecraft.util.Identifier 19 + import net.minecraft.util.Unit 20 + 21 + public enum class SpecialItem( 22 + public val displayName: String, 23 + public val color: Formatting, 24 + public val id: String, 25 + ) { 26 + Mace("Mace", Formatting.GOLD, "mace") { 27 + override fun applyEffects(player: ServerPlayerEntity, stack: ItemStack) { 28 + if (!player.hasStatusEffect(StatusEffects.GLOWING)) { 29 + player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 30 + } 31 + 32 + player.attributes.addTemporaryModifiers( 33 + Multimaps.forMap( 34 + mapOf( 35 + EntityAttributes.MAX_HEALTH to EntityAttributeModifier( 36 + Identifier.of("islanders", "mace_health_boost"), 37 + 10.0, 38 + EntityAttributeModifier.Operation.ADD_VALUE 39 + ) 40 + ) 41 + ) 42 + ) 43 + stack.set(DataComponentTypes.UNBREAKABLE, Unit.INSTANCE) 44 + stack.enchant(Enchantments.WIND_BURST, 3) 45 + stack.enchant(Enchantments.DENSITY, 5) 46 + stack.enchant(Enchantments.FIRE_ASPECT, 2) 47 + } 48 + 49 + override fun check(stack: ItemStack): Boolean { 50 + return stack.item == Items.MACE 51 + } 52 + 53 + override fun deapplyEffects(player: ServerPlayerEntity) { 54 + player.attributes.getCustomInstance(EntityAttributes.MAX_HEALTH)?.clearModifiers() 55 + } 56 + }, 57 + DragonEgg("Dragon Egg", Formatting.DARK_PURPLE, "egg") { 58 + override fun applyEffects(player: ServerPlayerEntity, stack: ItemStack) { 59 + if (!player.hasStatusEffect(StatusEffects.GLOWING)) { 60 + player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 61 + } 62 + player.addStatusEffect(StatusEffectInstance(StatusEffects.SPEED, 20, 0, true, false, false)) 63 + player.addStatusEffect(StatusEffectInstance(StatusEffects.HASTE, 20, 0, true, false, false)) 64 + player.addStatusEffect(StatusEffectInstance(StatusEffects.RESISTANCE, 20, 0, true, false, false)) 65 + player.addStatusEffect(StatusEffectInstance(StatusEffects.JUMP_BOOST, 20, 0, true, false, false)) 66 + player.addStatusEffect(StatusEffectInstance(StatusEffects.STRENGTH, 20, 0, true, false, false)) 67 + player.addStatusEffect(StatusEffectInstance(StatusEffects.REGENERATION, 20, 0, true, false, false)) 68 + } 69 + 70 + override fun check(stack: ItemStack): Boolean { 71 + return stack.item == Items.DRAGON_EGG 72 + } 73 + }, 74 + Crown("Islanders Crown", Formatting.AQUA, "crown") { 75 + override fun applyEffects(player: ServerPlayerEntity, stack: ItemStack) { 76 + player.hungerManager.foodLevel = 19 77 + if (!player.hasStatusEffect(StatusEffects.GLOWING)) { 78 + player.addStatusEffect(StatusEffectInstance(StatusEffects.GLOWING, 200, 0, true, false, false)) 79 + } 80 + } 81 + 82 + override fun check(stack: ItemStack): Boolean { 83 + return stack.item == Items.POPPED_CHORUS_FRUIT && stack.get(DataComponentTypes.CUSTOM_MODEL_DATA)?.strings?.contains("islanders") == true 84 + } 85 + }, 86 + ; 87 + 88 + public val team: Team by lazy { 89 + val board = Islanders.server.scoreboard 90 + board.getTeam(id) ?: board.addTeam(id).apply { 91 + color = this@SpecialItem.color 92 + } 93 + } 94 + 95 + public open fun deapplyEffects(player: ServerPlayerEntity) {} 96 + public open fun applyEffects(player: ServerPlayerEntity, stack: ItemStack) {} 97 + public abstract fun check(stack: ItemStack): Boolean 98 + 99 + public fun handleEffects(player: ServerPlayerEntity, stack: ItemStack?) { 100 + val inTeam = player.nameForScoreboard in team.playerList 101 + if (stack != null) { 102 + if (!inTeam) { 103 + player.server.scoreboard.addScoreHolderToTeam(player.nameForScoreboard, team) 104 + } 105 + applyEffects(player, stack) 106 + } else if (inTeam) { 107 + player.scoreboard.removeScoreHolderFromTeam(player.nameForScoreboard, team) 108 + deapplyEffects(player) 109 + } 110 + } 111 + 112 + public fun obtained(player: ServerPlayerEntity) { 113 + player.server.playerManager.broadcast( 114 + player.displayName!!.copy() 115 + .formatted(Formatting.RESET) 116 + .append( 117 + Text.literal(" has completed the challenge ") 118 + .append( 119 + Text.literal("[Obtain ").formatted(color) 120 + .append(Text.literal(displayName).formatted(Formatting.BOLD)) 121 + .append(Text.literal("]")), 122 + ) 123 + ), 124 + false 125 + ) 126 + 127 + player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT_PLAYER, SoundCategory.MASTER, 0.5f, 1f) 128 + 129 + IslandersData.obtained(id, player.uuid) 130 + } 131 + 132 + public fun pickedUp(player: ServerPlayerEntity) { 133 + if (!IslandersData.obtained(id)) { 134 + obtained(player) 135 + return 136 + } 137 + 138 + player.server.playerManager.broadcast( 139 + player.displayName!!.copy() 140 + .formatted(color) 141 + .append( 142 + Text.literal(" picked up the ") 143 + .append(Text.literal(displayName).formatted(Formatting.BOLD)) 144 + ), 145 + false 146 + ) 147 + player.server.playerManager.playerList.forEach { player -> 148 + player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT_PLAYER, SoundCategory.MASTER, 0.5f, 1f) 149 + } 150 + } 151 + 152 + public fun dropped(player: ServerPlayerEntity) { 153 + player.server.playerManager.broadcast( 154 + player.displayName!!.copy() 155 + .formatted(color) 156 + .append( 157 + Text.literal(" dropped the ") 158 + .append(Text.literal(displayName).formatted(Formatting.BOLD)) 159 + ), 160 + false 161 + ) 162 + player.server.playerManager.playerList.forEach { player -> 163 + player.playSoundToPlayer(SoundEvents.ENTITY_ARROW_HIT, SoundCategory.MASTER, 0.5f, 1f) 164 + } 165 + 166 + deapplyEffects(player) 167 + } 168 + 169 + public companion object { 170 + public fun find(stack: ItemStack): SpecialItem? { 171 + return SpecialItem.entries.firstOrNull { item -> item.check(stack) } 172 + } 173 + 174 + public fun handleEffects(player: ServerPlayerEntity, stack: ItemStack) { 175 + entries.forEach { item -> 176 + if (item.check(stack)) { 177 + item.handleEffects(player, stack) 178 + } else if (player.nameForScoreboard in item.team.playerList) { 179 + player.scoreboard.removeScoreHolderFromTeam(player.nameForScoreboard, item.team) 180 + item.deapplyEffects(player) 181 + } 182 + } 183 + } 184 + } 185 + }
+18 -30
src/main/kotlin/net/radsteve/islanders/command/RuleCommand.kt
··· 4 4 import com.mojang.brigadier.CommandDispatcher 5 5 import com.mojang.brigadier.arguments.IntegerArgumentType.integer 6 6 import com.mojang.brigadier.builder.ArgumentBuilder 7 - import net.minecraft.command.argument.IdentifierArgumentType.identifier 8 7 import net.minecraft.command.argument.RegistryKeyArgumentType.registryKey 9 8 import net.minecraft.item.Item 10 9 import net.minecraft.registry.Registries ··· 13 12 import net.minecraft.server.command.CommandManager 14 13 import net.minecraft.server.command.ServerCommandSource 15 14 import net.minecraft.text.Text.literal 16 - import net.minecraft.util.Identifier 17 15 import net.radsteve.islanders.rule.ItemRule 18 16 import net.radsteve.islanders.rule.ItemRuleInstance 19 17 import net.radsteve.islanders.rule.RuleManager ··· 36 34 private fun ruleAddLimitedCommand(): ArgumentBuilder<ServerCommandSource, *> { 37 35 return CommandManager.literal("limited") 38 36 .then( 39 - CommandManager.argument("id", identifier()) 37 + CommandManager.argument("item", registryKey(RegistryKeys.ITEM)) 40 38 .then( 41 - CommandManager.argument("item", registryKey(RegistryKeys.ITEM)) 42 - .then( 43 - CommandManager.argument("limit", integer(0)) 44 - .executes { ctx -> 45 - val id = ctx.getArgument("id", Identifier::class.java) 46 - 47 - @Suppress("UNCHECKED_CAST") 48 - val item = ctx.getArgument("item", RegistryKey::class.java) as RegistryKey<Item> 49 - val limit = ctx.getArgument("limit", Int::class.java) 39 + CommandManager.argument("limit", integer(0)) 40 + .executes { ctx -> 41 + @Suppress("UNCHECKED_CAST") 42 + val item = ctx.getArgument("item", RegistryKey::class.java) as RegistryKey<Item> 43 + val limit = ctx.getArgument("limit", Int::class.java) 50 44 51 - RuleManager.add(ItemRuleInstance(id, Registries.ITEM.get(item)!!, listOf(ItemRule.Limit(limit)))) 45 + RuleManager.add(ItemRuleInstance(Registries.ITEM.get(item)!!, listOf(ItemRule.Limit(limit)))) 52 46 53 - ctx.source.sendMessage(literal("Added rule!")) 47 + ctx.source.sendMessage(literal("Added rule!")) 54 48 55 - Command.SINGLE_SUCCESS 56 - } 57 - ) 49 + Command.SINGLE_SUCCESS 50 + } 58 51 ) 59 52 ) 60 53 } ··· 62 55 private fun ruleAddUncontainableCommand(): ArgumentBuilder<ServerCommandSource, *> { 63 56 return CommandManager.literal("uncontainable") 64 57 .then( 65 - CommandManager.argument("id", identifier()) 66 - .then( 67 - CommandManager.argument("item", registryKey(RegistryKeys.ITEM)) 68 - .executes { ctx -> 69 - val id = ctx.getArgument("id", Identifier::class.java) 70 - 71 - @Suppress("UNCHECKED_CAST") 72 - val item = ctx.getArgument("item", RegistryKey::class.java) as RegistryKey<Item> 58 + CommandManager.argument("item", registryKey(RegistryKeys.ITEM)) 59 + .executes { ctx -> 60 + @Suppress("UNCHECKED_CAST") 61 + val item = ctx.getArgument("item", RegistryKey::class.java) as RegistryKey<Item> 73 62 74 - RuleManager.add(ItemRuleInstance(id, Registries.ITEM.get(item)!!, listOf(ItemRule.Uncontainable))) 63 + RuleManager.add(ItemRuleInstance(Registries.ITEM.get(item)!!, listOf(ItemRule.Uncontainable))) 75 64 76 - ctx.source.sendMessage(literal("Added rule!")) 65 + ctx.source.sendMessage(literal("Added rule!")) 77 66 78 - Command.SINGLE_SUCCESS 79 - } 80 - ) 67 + Command.SINGLE_SUCCESS 68 + } 81 69 ) 82 70 }
-27
src/main/kotlin/net/radsteve/islanders/event/ItemClickCallback.kt
··· 1 - package net.radsteve.islanders.event 2 - 3 - import net.fabricmc.fabric.api.event.Event 4 - import net.fabricmc.fabric.api.event.EventFactory 5 - import net.minecraft.item.ItemStack 6 - import net.minecraft.server.network.ServerPlayerEntity 7 - 8 - public fun interface ItemClickCallback { 9 - public companion object { 10 - public val EVENT: Event<ItemClickCallback> = EventFactory.createArrayBacked( 11 - ItemClickCallback::class.java, ItemClickCallback { _, _ -> true }) { callbacks -> 12 - ItemClickCallback { item, player -> 13 - var canClick = true 14 - 15 - callbacks.forEach { callback -> 16 - if (!callback.canClick(item, player)) { 17 - canClick = false 18 - } 19 - } 20 - 21 - canClick 22 - } 23 - } 24 - } 25 - 26 - public fun canClick(item: ItemStack, player: ServerPlayerEntity): Boolean 27 - }
+27
src/main/kotlin/net/radsteve/islanders/event/ItemTransferCallback.kt
··· 1 + package net.radsteve.islanders.event 2 + 3 + import net.fabricmc.fabric.api.event.Event 4 + import net.fabricmc.fabric.api.event.EventFactory 5 + import net.minecraft.item.ItemStack 6 + import net.minecraft.server.network.ServerPlayerEntity 7 + 8 + public fun interface ItemTransferCallback { 9 + public companion object { 10 + public val EVENT: Event<ItemTransferCallback> = EventFactory.createArrayBacked( 11 + ItemTransferCallback::class.java, ItemTransferCallback { _, _ -> true }) { callbacks -> 12 + ItemTransferCallback { item, player -> 13 + var canClick = true 14 + 15 + callbacks.forEach { callback -> 16 + if (!callback.canTransfer(item, player)) { 17 + canClick = false 18 + } 19 + } 20 + 21 + canClick 22 + } 23 + } 24 + } 25 + 26 + public fun canTransfer(item: ItemStack, player: ServerPlayerEntity): Boolean 27 + }
+20
src/main/kotlin/net/radsteve/islanders/rule/DefaultRules.kt
··· 1 + package net.radsteve.islanders.rule 2 + 3 + import net.minecraft.item.Items 4 + 5 + public object DefaultRules { 6 + init { 7 + val limits = mapOf( 8 + Items.EXPERIENCE_BOTTLE to 64, 9 + Items.COBWEB to 64, 10 + Items.ENDER_PEARL to 16, 11 + Items.GOLDEN_APPLE to 64, 12 + Items.TOTEM_OF_UNDYING to 1, 13 + Items.WIND_CHARGE to 64 14 + ) 15 + 16 + limits.forEach { (item, limit) -> 17 + RuleManager.add(ItemRuleInstance(item, listOf(ItemRule.Limit(limit)))) 18 + } 19 + } 20 + }
-2
src/main/kotlin/net/radsteve/islanders/rule/ItemRuleInstance.kt
··· 1 1 package net.radsteve.islanders.rule 2 2 3 3 import net.minecraft.item.Item 4 - import net.minecraft.util.Identifier 5 4 6 5 public data class ItemRuleInstance( 7 - public val id: Identifier, 8 6 public val item: Item, 9 7 public val entries: List<ItemRule>, 10 8 )
+34 -29
src/main/kotlin/net/radsteve/islanders/rule/RuleHandlers.kt
··· 3 3 import net.minecraft.entity.ItemEntity 4 4 import net.minecraft.item.ItemStack 5 5 import net.minecraft.server.network.ServerPlayerEntity 6 - import net.radsteve.islanders.event.ItemClickCallback 7 6 import net.radsteve.islanders.event.ItemPickupCallback 7 + import net.radsteve.islanders.event.ItemTransferCallback 8 8 import net.radsteve.islanders.event.ResizeItemEntityAndAddRemainingStackCallback 9 9 10 10 public object RuleHandlers { 11 11 init { 12 12 ItemPickupCallback.EVENT.register(Limits) 13 - ItemClickCallback.EVENT.register(Limits) 13 + ItemTransferCallback.EVENT.register(Limits) 14 14 ResizeItemEntityAndAddRemainingStackCallback.EVENT.register(Limits) 15 15 } 16 16 17 - public object Limits : ItemPickupCallback, ItemClickCallback, ResizeItemEntityAndAddRemainingStackCallback { 17 + public object Limits : ItemPickupCallback, ItemTransferCallback, ResizeItemEntityAndAddRemainingStackCallback { 18 18 private fun check(item: ItemStack, player: ServerPlayerEntity): Boolean { 19 - var cancelled = false 20 - 21 - RuleManager.ruled<ItemRule.Limit> { rule, limit -> 22 - if (rule.item === item.item && 23 - player.inventory.mainStacks 24 - .filter { stack -> stack.item === item.item } 25 - .sumOf(ItemStack::getCount) 26 - + item.count >= limit.maxAmount 27 - ) { 28 - cancelled = true 29 - } 30 - } 31 - 32 - return !cancelled 19 + // var cancelled = false 20 + // 21 + // RuleManager.ruled<ItemRule.Limit> { rule, limit -> 22 + // val itemsOnPlayer = player.inventory.mainStacks 23 + // .filter { item -> item.item === rule.item } 24 + // .sumOf(ItemStack::getCount) 25 + // 26 + // if (rule.item == item.item && item.count <= limit.maxAmount && itemsOnPlayer == 0) { 27 + // return@ruled 28 + // } 29 + // 30 + // if (itemsOnPlayer + item.count >= limit.maxAmount) { 31 + // cancelled = true 32 + // } 33 + // } 34 + // 35 + return true // FIXME - maybe? 33 36 } 34 37 35 38 override fun canPickUp(item: ItemStack, player: ServerPlayerEntity): Boolean { 36 39 return check(item, player) 37 40 } 38 41 39 - override fun canClick(item: ItemStack, player: ServerPlayerEntity): Boolean { 42 + override fun canTransfer(item: ItemStack, player: ServerPlayerEntity): Boolean { 40 43 return check(item, player) 41 44 } 42 45 43 46 override fun resize(entity: ItemEntity, player: ServerPlayerEntity) { 44 47 RuleManager.ruled<ItemRule.Limit> { rule, limit -> 45 - if (rule.item == entity.stack.item && 46 - player.inventory.mainStacks 47 - .filter { stack -> stack.item === entity.stack.item } 48 - .sumOf(ItemStack::getCount) 49 - + entity.stack.count >= limit.maxAmount 50 - ) { 51 - val newStack = entity.stack.copy() 52 - newStack.count = entity.stack.count - limit.maxAmount 53 - entity.stack = newStack 54 - newStack.count = limit.maxAmount 55 - player.inventory.insertStack(newStack) 48 + if (rule.item != entity.stack.item) return@ruled 49 + val itemsOnPlayer = player.inventory.mainStacks 50 + .filter { item -> item.item === rule.item } 51 + .sumOf(ItemStack::getCount) 52 + val maxInsert = limit.maxAmount - itemsOnPlayer 53 + if (maxInsert <= 0) return@ruled 54 + val entityStack = entity.stack 55 + val insertCount = minOf(entityStack.count, maxInsert) 56 + 57 + if (insertCount > 0) { 58 + val toInsert = ItemStack(entityStack.item, insertCount) 59 + player.inventory.insertStack(toInsert) 60 + entityStack.decrement(insertCount) 56 61 } 57 62 } 58 63 }
+9 -5
src/main/kotlin/net/radsteve/islanders/rule/RuleManager.kt
··· 1 1 package net.radsteve.islanders.rule 2 2 3 - import net.minecraft.util.Identifier 3 + import net.minecraft.item.Item 4 4 5 5 public object RuleManager { 6 6 private val rules: MutableList<ItemRuleInstance> = mutableListOf() ··· 9 9 rules.add(rule) 10 10 } 11 11 12 - public fun remove(id: Identifier) { 13 - rules.removeIf { rule -> rule.id == id } 14 - } 15 - 16 12 public fun forEach(block: (ItemRuleInstance) -> Unit) { 17 13 rules.forEach(block) 14 + } 15 + 16 + public fun limitFor(item: Item): Int? { 17 + return rules.find { instance -> instance.item == item } 18 + ?.entries 19 + ?.filterIsInstance<ItemRule.Limit>() 20 + ?.firstOrNull() 21 + ?.maxAmount 18 22 } 19 23 20 24 public inline fun <reified T : ItemRule> ruled(crossinline block: (ItemRuleInstance, T) -> Unit) {
+2 -1
src/main/resources/islanders.mixins.json
··· 4 4 "compatibilityLevel": "JAVA_21", 5 5 "mixins": [ 6 6 "AnvilScreenHandlerMixin", 7 + "BundleHandlerMixin", 7 8 "CraftingResultSlotMixin", 8 9 "CraftingScreenHandlerMixin", 9 10 "GrindstoneScreenHandlerMixin", 10 11 "ItemEntityMixin", 12 + "ItemStackMixin", 11 13 "LivingEntityAccessor", 12 14 "LivingEntityMixin", 13 15 "PlayerEntityMixin", 14 16 "ScreenHandlerMixin", 15 - "ServerPlayNetworkHandlerMixin", 16 17 "SlotMixin" 17 18 ], 18 19 "injectors": {