mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
添加死亡保留/损毁物品选项
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user