diff --git a/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java index 36a1423ee..27012b0e6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java @@ -12,7 +12,6 @@ import com.atsuishio.superbwarfare.item.gun.data.value.ReloadState; import com.atsuishio.superbwarfare.perk.AmmoPerk; import com.atsuishio.superbwarfare.perk.Perk; import com.atsuishio.superbwarfare.tools.AmmoType; -import com.atsuishio.superbwarfare.tools.GunsTool; import com.atsuishio.superbwarfare.tools.InventoryTool; import com.atsuishio.superbwarfare.tools.SoundTool; import net.minecraft.core.Holder; @@ -327,7 +326,7 @@ public class GunEventHandler { var ammoTypeInfo = data.ammoTypeInfo(); if (ammoTypeInfo.type() == GunData.AmmoConsumeType.PLAYER_AMMO) { - GunsTool.reload(player, stack, data, AmmoType.getType(ammoTypeInfo.value()), gunItem.hasBulletInBarrel(stack)); + data.reload(player, gunItem.hasBulletInBarrel(stack)); } } data.reload.setState(ReloadState.NOT_RELOADING); @@ -340,28 +339,8 @@ public class GunEventHandler { if (player.getInventory().hasAnyMatching(item -> item.is(ModItems.CREATIVE_AMMO_BOX.get()))) { data.ammo.set(data.magazine()); } else { - var ammoTypeInfo = data.ammoTypeInfo(); - switch (ammoTypeInfo.type()) { - case PLAYER_AMMO -> GunsTool.reload(player, stack, data, AmmoType.getType(ammoTypeInfo.value())); - case TAG -> { - data.ammo.set(1); - player.getInventory().clearOrCountMatchingItems( - p -> p.is(ItemTags.create(ResourceLocation.parse(ammoTypeInfo.value()))), - 1, - player.inventoryMenu.getCraftSlots() - ); - } - case ITEM -> { - data.ammo.set(1); - player.getInventory().clearOrCountMatchingItems( - p -> p.getItem().toString().equals(ammoTypeInfo.value()), - 1, - player.inventoryMenu.getCraftSlots() - ); - } - } + data.reload(player); } - data.reload.setState(ReloadState.NOT_RELOADING); NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); } diff --git a/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java index ca39d31ba..1824df177 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java @@ -9,7 +9,6 @@ import com.atsuishio.superbwarfare.item.gun.GunItem; import com.atsuishio.superbwarfare.item.gun.data.GunData; import com.atsuishio.superbwarfare.network.message.receive.SimulationDistanceMessage; import com.atsuishio.superbwarfare.tools.AmmoType; -import com.atsuishio.superbwarfare.tools.GunsTool; import com.atsuishio.superbwarfare.tools.InventoryTool; import com.atsuishio.superbwarfare.tools.NBTTool; import net.minecraft.resources.ResourceLocation; @@ -118,7 +117,7 @@ public class PlayerEventHandler { assert type != null; if (type.get(cap) == 0) { - GunsTool.reload(player, stack, data, type); + data.reload(player); } } case ITEM -> { diff --git a/src/main/java/com/atsuishio/superbwarfare/item/gun/data/GunData.java b/src/main/java/com/atsuishio/superbwarfare/item/gun/data/GunData.java index c4b02457b..1b5ebb64d 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/gun/data/GunData.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/gun/data/GunData.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.item.gun.data; +import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.gun.GunItem; import com.atsuishio.superbwarfare.item.gun.data.subdata.*; import com.atsuishio.superbwarfare.item.gun.data.value.*; @@ -10,7 +11,9 @@ import com.atsuishio.superbwarfare.tools.GunsTool; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; @@ -297,6 +300,74 @@ public class GunData { return new AmmoTypeInfo(AmmoConsumeType.ITEM, ammoType); } + public int countAmmo(Player player) { + var info = ammoTypeInfo(); + return switch (info.type()) { + case PLAYER_AMMO -> { + var type = AmmoType.getType(info.value()); + assert type != null; + + yield type.get(player); + } + case ITEM -> player.getInventory().clearOrCountMatchingItems( + p -> p.getItem().toString().equals(info.value()), + 0, + player.inventoryMenu.getCraftSlots() + ); + case TAG -> player.getInventory().clearOrCountMatchingItems( + p -> p.is(ItemTags.create(ResourceLocation.parse(info.value()))), + 0, + player.inventoryMenu.getCraftSlots() + ); + case INVALID -> 0; + }; + } + + public void consumeAmmo(Player player, int count) { + var info = ammoTypeInfo(); + switch (info.type()) { + case PLAYER_AMMO -> { + var type = AmmoType.getType(info.value()); + assert type != null; + + type.set(player, type.get(player) - count); + } + case ITEM -> player.getInventory().clearOrCountMatchingItems( + p -> p.getItem().toString().equals(info.value()), + count, + player.inventoryMenu.getCraftSlots() + ); + case TAG -> player.getInventory().clearOrCountMatchingItems( + p -> p.is(ItemTags.create(ResourceLocation.parse(info.value()))), + count, + player.inventoryMenu.getCraftSlots() + ); + } + } + + public void reload(Player player) { + reload(player, false); + } + + public void reload(Player player, boolean extraOne) { + int mag = magazine(); + int ammo = this.ammo.get(); + int ammoNeeded = mag - ammo + (extraOne ? 1 : 0); + + // 空仓换弹的栓动武器应该在换弹后取消待上膛标记 + if (ammo == 0 && defaultActionTime() > 0 && !stack.is(ModTags.Items.REVOLVER)) { + bolt.needed.set(false); + } + + var available = countAmmo(player); + var ammoToAdd = Math.min(ammoNeeded, available); + + consumeAmmo(player, ammoToAdd); + this.ammo.set(ammo + ammoToAdd); + + reload.setState(ReloadState.NOT_RELOADING); + } + // 可持久化属性开始 public final IntValue ammo; diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java index 96e44426a..c62dd40f3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java @@ -1,18 +1,12 @@ package com.atsuishio.superbwarfare.tools; import com.atsuishio.superbwarfare.Mod; -import com.atsuishio.superbwarfare.init.ModAttachments; -import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.gun.data.DefaultGunData; -import com.atsuishio.superbwarfare.item.gun.data.GunData; -import com.atsuishio.superbwarfare.item.gun.data.value.ReloadState; import com.atsuishio.superbwarfare.network.message.receive.GunsDataMessage; import com.google.gson.Gson; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.OnDatapackSyncEvent; @@ -68,35 +62,6 @@ public class GunsTool { event.getRelevantPlayers().forEach(player -> PacketDistributor.sendToPlayer(player, GunsDataMessage.create())); } - public static void reload(Player player, ItemStack stack, GunData gunData, AmmoType type) { - reload(player, stack, gunData, type, false); - } - - public static void reload(Player player, ItemStack stack, GunData data, AmmoType type, boolean extraOne) { - int mag = data.magazine(); - int ammo = data.ammo.get(); - int ammoToAdd = mag - ammo + (extraOne ? 1 : 0); - - // 空仓换弹的栓动武器应该在换弹后取消待上膛标记 - if (ammo == 0 && data.defaultActionTime() > 0 && !stack.is(ModTags.Items.REVOLVER)) { - data.bolt.needed.set(false); - } - - var capability = player.getData(ModAttachments.PLAYER_VARIABLE).watch(); - var playerAmmo = 0; - - playerAmmo = type.get(capability); - var newAmmoCount = Math.max(0, playerAmmo - ammoToAdd); - type.set(capability, newAmmoCount); - player.setData(ModAttachments.PLAYER_VARIABLE, capability); - capability.sync(player); - - int needToAdd = ammo + Math.min(ammoToAdd, playerAmmo); - - data.ammo.set(needToAdd); - data.reload.setState(ReloadState.NOT_RELOADING); - } - /* PerkData */ public static void setPerkIntTag(final CompoundTag rootTag, String name, int num) { CompoundTag tag = rootTag.getCompound("PerkData"); @@ -148,6 +113,7 @@ public class GunsTool { if (!data.contains(name)) return defaultValue; return data.getDouble(name); } + @Nullable public static UUID getGunUUID(final CompoundTag tag) { if (!tag.contains("GunData")) return null; diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/InventoryTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/InventoryTool.java index b6704c42c..49e2d0f05 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/InventoryTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/InventoryTool.java @@ -8,6 +8,8 @@ import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.joml.Math; +import java.util.function.Predicate; + public class InventoryTool { /** @@ -79,8 +81,13 @@ public class InventoryTool { * @return 成功消耗的物品数量 */ public static int consumeItem(NonNullList itemList, Item item, int count) { + return consumeItem(itemList, stack -> stack.is(item), count); + } + + + public static int consumeItem(NonNullList itemList, Predicate predicate, int count) { int initialCount = count; - var items = itemList.stream().filter(stack -> stack.is(item)).toList(); + var items = itemList.stream().filter(predicate).toList(); for (var stack : items) { var countToShrink = Math.min(stack.getCount(), count); stack.shrink(countToShrink);