+5
README.md
+5
README.md
+2
-2
src/main/java/net/radsteve/islanders/mixin/CraftingResultSlotMixin.java
+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
+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
+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
+1
-1
src/main/java/net/radsteve/islanders/mixin/LivingEntityMixin.java
+16
-4
src/main/java/net/radsteve/islanders/mixin/PlayerEntityMixin.java
+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
+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
+1
-1
src/main/java/net/radsteve/islanders/mixin/ServerPlayNetworkHandlerMixin.java
src/main/java/net/radsteve/islanders/mixin/BundleHandlerMixin.java
+12
-12
src/main/java/net/radsteve/islanders/mixin/SlotMixin.java
+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
+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
-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
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
+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
+1
src/main/kotlin/net/radsteve/islanders/MaceAnimation.kt
+185
src/main/kotlin/net/radsteve/islanders/SpecialItem.kt
+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
+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
-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
+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
+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
-2
src/main/kotlin/net/radsteve/islanders/rule/ItemRuleInstance.kt
+34
-29
src/main/kotlin/net/radsteve/islanders/rule/RuleHandlers.kt
+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
+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
+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": {