9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

添加死亡保留/损毁物品选项

This commit is contained in:
XiaoMoMi
2025-12-05 23:16:42 +08:00
parent 35b63b1630
commit 8c744dedf7
5 changed files with 173 additions and 12 deletions

View File

@@ -21,6 +21,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.ItemSettings;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -54,20 +55,16 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.EnchantingInventory; import org.bukkit.inventory.*;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.concurrent.ThreadLocalRandom;
import java.util.Objects;
import java.util.Optional;
public class ItemEventListener implements Listener { public class ItemEventListener implements Listener {
private final BukkitCraftEngine plugin; private final BukkitCraftEngine plugin;
@@ -630,4 +627,114 @@ public class ItemEventListener implements Listener {
} }
event.setCurrentItem((ItemStack) result.finalItem().getItem()); event.setCurrentItem((ItemStack) result.finalItem().getItem());
} }
@SuppressWarnings("DuplicatedCode")
@EventHandler(ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
BukkitItemManager instance = BukkitItemManager.instance();
// 处理损毁物品
if (event.getKeepInventory()) {
if (!instance.featureFlag$destroyOnDeathChance()) return;
Random random = ThreadLocalRandom.current();
PlayerInventory inventory = event.getPlayer().getInventory();
for (ItemStack item : inventory.getContents()) {
if (item == null) continue;
Optional<CustomItem<ItemStack>> optional = instance.wrap(item).getCustomItem();
if (optional.isEmpty()) continue;
CustomItem<ItemStack> customItem = optional.get();
ItemSettings settings = customItem.settings();
float destroyChance = settings.destroyOnDeathChance();
if (destroyChance <= 0f) continue;
int totalAmount = item.getAmount();
int destroyCount = 0;
for (int i = 0; i < totalAmount; i++) {
float rand = random.nextFloat();
// 判断是否损毁
if (destroyChance > 0f && rand < destroyChance) {
destroyCount++;
}
}
if (destroyCount != 0) {
item.setAmount(totalAmount - destroyCount);
}
}
}
// 处理保留 + 损毁物品
else {
if (!instance.featureFlag$keepOnDeathChance() && !instance.featureFlag$destroyOnDeathChance()) return;
Random random = ThreadLocalRandom.current();
List<ItemStack> itemsToKeep = event.getItemsToKeep();
List<ItemStack> itemsToDrop = event.getDrops();
Iterator<ItemStack> iterator = itemsToDrop.iterator();
while (iterator.hasNext()) {
ItemStack item = iterator.next();
Optional<CustomItem<ItemStack>> optional = instance.wrap(item).getCustomItem();
if (optional.isEmpty()) continue;
CustomItem<ItemStack> customItem = optional.get();
ItemSettings settings = customItem.settings();
float destroyChance = settings.destroyOnDeathChance();
float keepChance = settings.keepOnDeathChance();
// 如果没有效果,跳过
if (destroyChance <= 0f && keepChance <= 0f) continue;
int totalAmount = item.getAmount();
int keepCount = 0;
int destroyCount = 0;
int dropCount = 0;
for (int i = 0; i < totalAmount; i++) {
float rand = random.nextFloat();
// 先判断是否损毁
if (destroyChance > 0f && rand < destroyChance) {
destroyCount++;
}
// 然后判断是否保留(在未损毁的物品中)
else if (keepChance > 0f && rand < (destroyChance + keepChance)) {
keepCount++;
}
// 否则掉落
else {
dropCount++;
}
}
// 处理结果
if (destroyCount == totalAmount) {
iterator.remove();
continue;
}
if (keepCount == 0 && dropCount == 0) {
// 实际上不会发生这种情况
continue;
}
if (keepCount > 0) {
ItemStack keepItem = item.clone();
keepItem.setAmount(keepCount);
itemsToKeep.add(keepItem);
}
if (dropCount > 0) {
item.setAmount(dropCount);
} else {
iterator.remove();
}
}
}
}
} }

View File

@@ -67,6 +67,9 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
// 替代配方材料 // 替代配方材料
protected final Map<Key, List<UniqueKey>> ingredientSubstitutes = new HashMap<>(); protected final Map<Key, List<UniqueKey>> ingredientSubstitutes = new HashMap<>();
protected boolean featureFlag$keepOnDeathChance = false;
protected boolean featureFlag$destroyOnDeathChance = false;
protected AbstractItemManager(CraftEngine plugin) { protected AbstractItemManager(CraftEngine plugin) {
super(plugin); super(plugin);
this.itemParser = new ItemParser(); this.itemParser = new ItemParser();
@@ -133,6 +136,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
@Override @Override
public void unload() { public void unload() {
super.clearModelsToGenerate(); super.clearModelsToGenerate();
this.clearFeatureFlags();
this.customItemsById.clear(); this.customItemsById.clear();
this.customItemsByPath.clear(); this.customItemsByPath.clear();
this.cachedCustomItemSuggestions.clear(); this.cachedCustomItemSuggestions.clear();
@@ -147,6 +151,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
this.ingredientSubstitutes.clear(); this.ingredientSubstitutes.clear();
} }
private void clearFeatureFlags() {
this.featureFlag$keepOnDeathChance = false;
this.featureFlag$destroyOnDeathChance = false;
}
@Override @Override
public Map<Key, Equipment> equipments() { public Map<Key, Equipment> equipments() {
return Collections.unmodifiableMap(this.equipments); return Collections.unmodifiableMap(this.equipments);
@@ -205,12 +214,13 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString()));
} }
// tags // tags
Set<Key> tags = customItem.settings().tags(); ItemSettings settings = customItem.settings();
Set<Key> tags = settings.tags();
for (Key tag : tags) { for (Key tag : tags) {
this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId()); this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId());
} }
// ingredient substitutes // ingredient substitutes
List<Key> substitutes = customItem.settings().ingredientSubstitutes(); List<Key> substitutes = settings.ingredientSubstitutes();
if (!substitutes.isEmpty()) { if (!substitutes.isEmpty()) {
for (Key key : substitutes) { for (Key key : substitutes) {
if (VANILLA_ITEMS.contains(key)) { if (VANILLA_ITEMS.contains(key)) {
@@ -218,6 +228,12 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
} }
} }
} }
if (settings.keepOnDeathChance != 0) {
this.featureFlag$keepOnDeathChance = true;
}
if (settings.destroyOnDeathChance != 0) {
this.featureFlag$destroyOnDeathChance = true;
}
} }
return true; return true;
} }
@@ -317,6 +333,14 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
return VANILLA_ITEMS.contains(item); return VANILLA_ITEMS.contains(item);
} }
public boolean featureFlag$keepOnDeathChance() {
return featureFlag$keepOnDeathChance;
}
public boolean featureFlag$destroyOnDeathChance() {
return featureFlag$destroyOnDeathChance;
}
protected abstract CustomItem.Builder<I> createPlatformItemBuilder(UniqueKey id, Key material, Key clientBoundMaterial); protected abstract CustomItem.Builder<I> createPlatformItemBuilder(UniqueKey id, Key material, Key clientBoundMaterial);
protected abstract void registerArmorTrimPattern(Collection<Key> equipments); protected abstract void registerArmorTrimPattern(Collection<Key> equipments);

View File

@@ -47,6 +47,8 @@ public class ItemSettings {
Color dyeColor; Color dyeColor;
@Nullable @Nullable
Color fireworkColor; Color fireworkColor;
float keepOnDeathChance = 0f;
float destroyOnDeathChance = 0f;
Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4); Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4);
private ItemSettings() {} private ItemSettings() {}
@@ -109,6 +111,8 @@ public class ItemSettings {
newSettings.dyeColor = settings.dyeColor; newSettings.dyeColor = settings.dyeColor;
newSettings.fireworkColor = settings.fireworkColor; newSettings.fireworkColor = settings.fireworkColor;
newSettings.ingredientSubstitutes = settings.ingredientSubstitutes; newSettings.ingredientSubstitutes = settings.ingredientSubstitutes;
newSettings.keepOnDeathChance = settings.keepOnDeathChance;
newSettings.destroyOnDeathChance = settings.destroyOnDeathChance;
newSettings.customData = new IdentityHashMap<>(settings.customData); newSettings.customData = new IdentityHashMap<>(settings.customData);
return newSettings; return newSettings;
} }
@@ -231,6 +235,14 @@ public class ItemSettings {
return this.compostProbability; return this.compostProbability;
} }
public float keepOnDeathChance() {
return this.keepOnDeathChance;
}
public float destroyOnDeathChance() {
return this.destroyOnDeathChance;
}
public ItemSettings fireworkColor(Color color) { public ItemSettings fireworkColor(Color color) {
this.fireworkColor = color; this.fireworkColor = color;
return this; return this;
@@ -331,6 +343,16 @@ public class ItemSettings {
return this; return this;
} }
public ItemSettings keepOnDeathChance(float keepChance) {
this.keepOnDeathChance = keepChance;
return this;
}
public ItemSettings destroyOnDeathChance(float destroyChance) {
this.destroyOnDeathChance = destroyChance;
return this;
}
@FunctionalInterface @FunctionalInterface
public interface Modifier { public interface Modifier {
@@ -361,6 +383,14 @@ public class ItemSettings {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "enchantable"); boolean bool = ResourceConfigUtils.getAsBoolean(value, "enchantable");
return settings -> settings.canEnchant(bool); return settings -> settings.canEnchant(bool);
})); }));
registerFactory("keep-on-death-chance", (value -> {
float chance = ResourceConfigUtils.getAsFloat(value, "keep-on-death-chance");
return settings -> settings.keepOnDeathChance(MiscUtils.clamp(chance, 0, 1));
}));
registerFactory("destroy-on-death-chance", (value -> {
float chance = ResourceConfigUtils.getAsFloat(value, "destroy-on-death-chance");
return settings -> settings.destroyOnDeathChance(MiscUtils.clamp(chance, 0, 1));
}));
registerFactory("renameable", (value -> { registerFactory("renameable", (value -> {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable"); boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable");
return settings -> settings.renameable(bool); return settings -> settings.renameable(bool);

View File

@@ -31,7 +31,7 @@ public class ComponentsModifier<I> implements ItemDataModifier<I> {
} }
public List<Pair<Key, Tag>> components() { public List<Pair<Key, Tag>> components() {
return arguments; return this.arguments;
} }
private Tag parseValue(Object value) { private Tag parseValue(Object value) {

View File

@@ -38,7 +38,7 @@ zstd_version=1.5.7-6
commons_io_version=2.21.0 commons_io_version=2.21.0
commons_lang3_version=3.20.0 commons_lang3_version=3.20.0
sparrow_nbt_version=0.10.6 sparrow_nbt_version=0.10.6
sparrow_util_version=0.67 sparrow_util_version=0.68
fastutil_version=8.5.18 fastutil_version=8.5.18
netty_version=4.1.128.Final netty_version=4.1.128.Final
joml_version=1.10.8 joml_version=1.10.8