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.Item;
|
||||
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.context.BlockPlaceContext;
|
||||
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.EntityPickupItemEvent;
|
||||
import org.bukkit.event.entity.FoodLevelChangeEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.inventory.EnchantingInventory;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class ItemEventListener implements Listener {
|
||||
private final BukkitCraftEngine plugin;
|
||||
@@ -630,4 +627,114 @@ public class ItemEventListener implements Listener {
|
||||
}
|
||||
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 boolean featureFlag$keepOnDeathChance = false;
|
||||
protected boolean featureFlag$destroyOnDeathChance = false;
|
||||
|
||||
protected AbstractItemManager(CraftEngine plugin) {
|
||||
super(plugin);
|
||||
this.itemParser = new ItemParser();
|
||||
@@ -133,6 +136,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
@Override
|
||||
public void unload() {
|
||||
super.clearModelsToGenerate();
|
||||
this.clearFeatureFlags();
|
||||
this.customItemsById.clear();
|
||||
this.customItemsByPath.clear();
|
||||
this.cachedCustomItemSuggestions.clear();
|
||||
@@ -147,6 +151,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
this.ingredientSubstitutes.clear();
|
||||
}
|
||||
|
||||
private void clearFeatureFlags() {
|
||||
this.featureFlag$keepOnDeathChance = false;
|
||||
this.featureFlag$destroyOnDeathChance = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, Equipment> 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()));
|
||||
}
|
||||
// tags
|
||||
Set<Key> tags = customItem.settings().tags();
|
||||
ItemSettings settings = customItem.settings();
|
||||
Set<Key> tags = settings.tags();
|
||||
for (Key tag : tags) {
|
||||
this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId());
|
||||
}
|
||||
// ingredient substitutes
|
||||
List<Key> substitutes = customItem.settings().ingredientSubstitutes();
|
||||
List<Key> substitutes = settings.ingredientSubstitutes();
|
||||
if (!substitutes.isEmpty()) {
|
||||
for (Key key : substitutes) {
|
||||
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;
|
||||
}
|
||||
@@ -317,6 +333,14 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
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 void registerArmorTrimPattern(Collection<Key> equipments);
|
||||
|
||||
@@ -47,6 +47,8 @@ public class ItemSettings {
|
||||
Color dyeColor;
|
||||
@Nullable
|
||||
Color fireworkColor;
|
||||
float keepOnDeathChance = 0f;
|
||||
float destroyOnDeathChance = 0f;
|
||||
Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4);
|
||||
|
||||
private ItemSettings() {}
|
||||
@@ -109,6 +111,8 @@ public class ItemSettings {
|
||||
newSettings.dyeColor = settings.dyeColor;
|
||||
newSettings.fireworkColor = settings.fireworkColor;
|
||||
newSettings.ingredientSubstitutes = settings.ingredientSubstitutes;
|
||||
newSettings.keepOnDeathChance = settings.keepOnDeathChance;
|
||||
newSettings.destroyOnDeathChance = settings.destroyOnDeathChance;
|
||||
newSettings.customData = new IdentityHashMap<>(settings.customData);
|
||||
return newSettings;
|
||||
}
|
||||
@@ -231,6 +235,14 @@ public class ItemSettings {
|
||||
return this.compostProbability;
|
||||
}
|
||||
|
||||
public float keepOnDeathChance() {
|
||||
return this.keepOnDeathChance;
|
||||
}
|
||||
|
||||
public float destroyOnDeathChance() {
|
||||
return this.destroyOnDeathChance;
|
||||
}
|
||||
|
||||
public ItemSettings fireworkColor(Color color) {
|
||||
this.fireworkColor = color;
|
||||
return this;
|
||||
@@ -331,6 +343,16 @@ public class ItemSettings {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemSettings keepOnDeathChance(float keepChance) {
|
||||
this.keepOnDeathChance = keepChance;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemSettings destroyOnDeathChance(float destroyChance) {
|
||||
this.destroyOnDeathChance = destroyChance;
|
||||
return this;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Modifier {
|
||||
|
||||
@@ -361,6 +383,14 @@ public class ItemSettings {
|
||||
boolean bool = ResourceConfigUtils.getAsBoolean(value, "enchantable");
|
||||
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 -> {
|
||||
boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable");
|
||||
return settings -> settings.renameable(bool);
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ComponentsModifier<I> implements ItemDataModifier<I> {
|
||||
}
|
||||
|
||||
public List<Pair<Key, Tag>> components() {
|
||||
return arguments;
|
||||
return this.arguments;
|
||||
}
|
||||
|
||||
private Tag parseValue(Object value) {
|
||||
|
||||
@@ -38,7 +38,7 @@ zstd_version=1.5.7-6
|
||||
commons_io_version=2.21.0
|
||||
commons_lang3_version=3.20.0
|
||||
sparrow_nbt_version=0.10.6
|
||||
sparrow_util_version=0.67
|
||||
sparrow_util_version=0.68
|
||||
fastutil_version=8.5.18
|
||||
netty_version=4.1.128.Final
|
||||
joml_version=1.10.8
|
||||
|
||||
Reference in New Issue
Block a user