9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-06 15:52:03 +00:00

Custom Fuel

This commit is contained in:
XiaoMoMi
2025-02-15 23:44:01 +08:00
parent 7631adf448
commit 213a03446a
8 changed files with 331 additions and 6 deletions

View File

@@ -151,6 +151,8 @@ items:
default:palm_log:
material: paper
custom-model-data: 1000
settings:
fuel-time: 300
tags:
- "default:palm_logs"
- "minecraft:logs"
@@ -168,6 +170,8 @@ items:
default:stripped_palm_log:
material: paper
custom-model-data: 1001
settings:
fuel-time: 300
tags:
- "default:palm_logs"
- "minecraft:logs"
@@ -185,6 +189,8 @@ items:
default:palm_wood:
material: paper
custom-model-data: 1002
settings:
fuel-time: 300
tags:
- "default:palm_logs"
- "minecraft:logs"
@@ -202,6 +208,8 @@ items:
default:stripped_palm_wood:
material: paper
custom-model-data: 1003
settings:
fuel-time: 300
tags:
- "default:palm_logs"
- "minecraft:logs"
@@ -219,6 +227,8 @@ items:
default:palm_planks:
material: paper
custom-model-data: 1004
settings:
fuel-time: 300
tags:
- "minecraft:planks"
- "minecraft:wooden_tool_materials"
@@ -235,6 +245,8 @@ items:
default:palm_sapling:
material: paper
custom-model-data: 1005
settings:
fuel-time: 100
data:
display-name: "<!i>Palm Sapling"
model:

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.util.MaterialUtils;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemSettings;
import net.momirealms.craftengine.core.item.behavior.EmptyItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.modifier.ItemModifier;
@@ -22,13 +23,15 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
private final Material material;
private final List<ItemModifier<ItemStack>> modifiers;
private final ItemBehavior behavior;
private final ItemSettings settings;
public BukkitCustomItem(Key id, Key materialKey, Material material, List<ItemModifier<ItemStack>> modifiers, ItemBehavior behavior) {
public BukkitCustomItem(Key id, Key materialKey, Material material, List<ItemModifier<ItemStack>> modifiers, ItemBehavior behavior, ItemSettings settings) {
this.id = id;
this.material = material;
this.modifiers = modifiers;
this.behavior = behavior;
this.materialKey = materialKey;
this.settings = settings;
}
@Override
@@ -60,6 +63,11 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
return wrapped.load();
}
@Override
public ItemSettings settings() {
return settings;
}
@Override
public Item<ItemStack> buildItem(Player player) {
ItemStack item = new ItemStack(material);
@@ -84,6 +92,7 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
private Material material;
private Key materialKey;
private ItemBehavior behavior = EmptyItemBehavior.INSTANCE;
private ItemSettings settings = ItemSettings.of();
private final List<ItemModifier<ItemStack>> modifiers = new ArrayList<>();
@Override
@@ -117,9 +126,15 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
return this;
}
@Override
public Builder<ItemStack> settings(ItemSettings settings) {
this.settings = settings;
return this;
}
@Override
public CustomItem<ItemStack> build() {
return new BukkitCustomItem(id, materialKey, material, modifiers, behavior);
return new BukkitCustomItem(id, materialKey, material, modifiers, behavior, settings);
}
}
}

View File

@@ -112,6 +112,18 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return this.customItemTags.getOrDefault(tag, List.of());
}
@Override
public int fuelTime(ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return 0;
Optional<CustomItem<ItemStack>> customItem = wrap(itemStack).getCustomItem();
return customItem.map(it -> it.settings().fuelTime()).orElse(0);
}
@Override
public int fuelTime(Key id) {
return getCustomItem(id).map(it -> it.settings().fuelTime()).orElse(0);
}
@Override
public void load() {
super.load();
@@ -255,6 +267,12 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
}, () -> plugin.logger().warn(path, dataEntry.getKey() + " is not a valid data type"));
}
}
if (section.containsKey("settings")) {
Map<String, Object> settings = MiscUtils.castToMap(section.get("settings"), false);
itemBuilder.settings(ItemSettings.fromMap(settings));
}
this.customItems.put(id, itemBuilder.build());
List<String> tags = MiscUtils.getAsStringList(section.get("tags"));

View File

@@ -27,9 +27,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.*;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.inventory.*;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.*;
@@ -49,6 +47,207 @@ public class RecipeEventListener implements Listener {
this.plugin = plugin;
}
@EventHandler(ignoreCancelled = true)
public void onClickInventoryWithFuel(InventoryClickEvent event) {
Inventory inventory = event.getInventory();
if (!(inventory instanceof FurnaceInventory furnaceInventory)) return;
ItemStack fuelStack = furnaceInventory.getFuel();
Inventory clickedInventory = event.getClickedInventory();
Player player = (Player) event.getWhoClicked();
if (clickedInventory == player.getInventory()) {
if (event.getClick() == ClickType.SHIFT_LEFT || event.getClick() == ClickType.SHIFT_RIGHT) {
ItemStack item = event.getCurrentItem();
if (ItemUtils.isEmpty(item)) return;
if (fuelStack == null || fuelStack.getType() == Material.AIR) {
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(item);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) return;
CookingInput<ItemStack> input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), item));
Key recipeType;
if (furnaceInventory.getType() == InventoryType.FURNACE) {
recipeType = RecipeTypes.SMELTING;
} else if (furnaceInventory.getType() == InventoryType.BLAST_FURNACE) {
recipeType = RecipeTypes.BLASTING;
} else {
recipeType = RecipeTypes.SMOKING;
}
Recipe<ItemStack> ceRecipe = recipeManager.getRecipe(recipeType, input);
// The item is an ingredient, we should never consider it as fuel firstly
if (ceRecipe != null) return;
int fuelTime = this.itemManager.fuelTime(item);
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) {
event.setCancelled(true);
ItemStack smelting = furnaceInventory.getSmelting();
if (ItemUtils.isEmpty(smelting)) {
furnaceInventory.setSmelting(item.clone());
item.setAmount(0);
} else if (smelting.isSimilar(item)) {
int maxStackSize = smelting.getMaxStackSize();
int canGiveMaxCount = item.getAmount();
if (maxStackSize > smelting.getAmount()) {
if (canGiveMaxCount + smelting.getAmount() >= maxStackSize) {
int givenCount = maxStackSize - smelting.getAmount();
smelting.setAmount(maxStackSize);
item.setAmount(item.getAmount() - givenCount);
} else {
smelting.setAmount(smelting.getAmount() + canGiveMaxCount);
item.setAmount(0);
}
}
}
player.updateInventory();
}
return;
}
event.setCancelled(true);
furnaceInventory.setFuel(item.clone());
item.setAmount(0);
player.updateInventory();
} else {
if (fuelStack.isSimilar(item)) {
event.setCancelled(true);
int maxStackSize = fuelStack.getMaxStackSize();
int canGiveMaxCount = item.getAmount();
if (maxStackSize > fuelStack.getAmount()) {
if (canGiveMaxCount + fuelStack.getAmount() >= maxStackSize) {
int givenCount = maxStackSize - fuelStack.getAmount();
fuelStack.setAmount(maxStackSize);
item.setAmount(item.getAmount() - givenCount);
} else {
fuelStack.setAmount(fuelStack.getAmount() + canGiveMaxCount);
item.setAmount(0);
}
player.updateInventory();
}
}
}
}
} else {
// click the furnace inventory
int slot = event.getSlot();
// click the fuel slot
if (slot != 1) {
return;
}
ClickType clickType = event.getClick();
switch (clickType) {
case SWAP_OFFHAND, NUMBER_KEY -> {
ItemStack item;
int hotBarSlot = event.getHotbarButton();
if (clickType == ClickType.SWAP_OFFHAND) {
item = player.getInventory().getItemInOffHand();
} else {
item = player.getInventory().getItem(hotBarSlot);
}
if (item == null) return;
int fuelTime = this.plugin.itemManager().fuelTime(item);
// only handle custom items
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) {
event.setCancelled(true);
}
return;
}
event.setCancelled(true);
if (fuelStack == null || fuelStack.getType() == Material.AIR) {
furnaceInventory.setFuel(item.clone());
item.setAmount(0);
} else {
if (clickType == ClickType.SWAP_OFFHAND) {
player.getInventory().setItemInOffHand(fuelStack);
} else {
player.getInventory().setItem(hotBarSlot, fuelStack);
}
furnaceInventory.setFuel(item.clone());
}
player.updateInventory();
}
case LEFT, RIGHT -> {
ItemStack itemOnCursor = event.getCursor();
// pick item
if (ItemUtils.isEmpty(itemOnCursor)) return;
int fuelTime = this.plugin.itemManager().fuelTime(itemOnCursor);
// only handle custom items
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(itemOnCursor) && itemOnCursor.getType().isFuel()) {
event.setCancelled(true);
}
return;
}
event.setCancelled(true);
// The slot is empty
if (fuelStack == null || fuelStack.getType() == Material.AIR) {
if (clickType == ClickType.LEFT) {
furnaceInventory.setFuel(itemOnCursor.clone());
itemOnCursor.setAmount(0);
player.updateInventory();
} else {
ItemStack cloned = itemOnCursor.clone();
cloned.setAmount(1);
furnaceInventory.setFuel(cloned);
itemOnCursor.setAmount(itemOnCursor.getAmount() - 1);
player.updateInventory();
}
} else {
boolean isSimilar = itemOnCursor.isSimilar(fuelStack);
if (clickType == ClickType.LEFT) {
if (isSimilar) {
int maxStackSize = fuelStack.getMaxStackSize();
int canGiveMaxCount = itemOnCursor.getAmount();
if (maxStackSize > fuelStack.getAmount()) {
if (canGiveMaxCount + fuelStack.getAmount() >= maxStackSize) {
int givenCount = maxStackSize - fuelStack.getAmount();
fuelStack.setAmount(maxStackSize);
itemOnCursor.setAmount(itemOnCursor.getAmount() - givenCount);
} else {
fuelStack.setAmount(fuelStack.getAmount() + canGiveMaxCount);
itemOnCursor.setAmount(0);
}
player.updateInventory();
}
} else {
// swap item
event.setCursor(fuelStack);
furnaceInventory.setFuel(itemOnCursor.clone());
player.updateInventory();
}
} else {
if (isSimilar) {
int maxStackSize = fuelStack.getMaxStackSize();
if (maxStackSize > fuelStack.getAmount()) {
fuelStack.setAmount(fuelStack.getAmount() + 1);
itemOnCursor.setAmount(itemOnCursor.getAmount() - 1);
player.updateInventory();
}
} else {
// swap item
event.setCursor(fuelStack);
furnaceInventory.setFuel(itemOnCursor.clone());
player.updateInventory();
}
}
}
}
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onFurnaceBurn(FurnaceBurnEvent event) {
ItemStack fuel = event.getFuel();
int fuelTime = this.itemManager.fuelTime(fuel);
if (fuelTime != 0) {
event.setBurnTime(fuelTime);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onFurnaceInventoryOpen(InventoryOpenEvent event) {
if (!(event.getInventory() instanceof FurnaceInventory furnaceInventory)) {
@@ -59,7 +258,7 @@ public class RecipeEventListener implements Listener {
Object blockEntity = Reflections.field$CraftBlockEntityState$tileEntity.get(furnace);
BukkitInjector.injectCookingBlockEntity(blockEntity);
} catch (Exception e) {
plugin.logger().warn("Failed to inject cooking block entity", e);
this.plugin.logger().warn("Failed to inject cooking block entity", e);
}
}

View File

@@ -74,6 +74,7 @@ public class BlockSettings {
newSettings.isRedstoneConductor = settings.isRedstoneConductor;
newSettings.isSuffocating = settings.isSuffocating;
newSettings.isViewBlocking = settings.isViewBlocking;
newSettings.correctTools = settings.correctTools;
return newSettings;
}

View File

@@ -22,6 +22,8 @@ public interface CustomItem<I> extends BuildableItem<I> {
I buildItemStack(Player player, int count);
ItemSettings settings();
Item<I> buildItem(Player player);
@NotNull
@@ -38,6 +40,8 @@ public interface CustomItem<I> extends BuildableItem<I> {
Builder<I> behavior(ItemBehavior behavior);
Builder<I> settings(ItemSettings settings);
CustomItem<I> build();
}
}

View File

@@ -61,6 +61,10 @@ public interface ItemManager<T> extends Reloadable, ModelGenerator, ConfigSectio
List<Holder<Key>> tagToCustomItems(Key tag);
int fuelTime(T itemStack);
int fuelTime(Key id);
default int loadingSequence() {
return LoadingSequence.ITEM;
}

View File

@@ -0,0 +1,72 @@
package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.util.MiscUtils;
import java.util.HashMap;
import java.util.Map;
public class ItemSettings {
int fuelTime;
private ItemSettings() {}
public static ItemSettings of() {
return new ItemSettings();
}
public static ItemSettings fromMap(Map<String, Object> map) {
return applyModifiers(ItemSettings.of(), map);
}
public static ItemSettings ofFullCopy(ItemSettings settings) {
ItemSettings newSettings = of();
newSettings.fuelTime = settings.fuelTime;
return newSettings;
}
public static ItemSettings applyModifiers(ItemSettings settings, Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
ItemSettings.Modifier.Factory factory = ItemSettings.Modifiers.FACTORIES.get(entry.getKey());
if (factory != null) {
factory.createModifier(entry.getValue()).apply(settings);
} else {
throw new IllegalArgumentException("Unknown item settings key: " + entry.getKey());
}
}
return settings;
}
public int fuelTime() {
return fuelTime;
}
public ItemSettings fuelTime(int fuelTime) {
this.fuelTime = fuelTime;
return this;
}
public interface Modifier {
void apply(ItemSettings settings);
interface Factory {
ItemSettings.Modifier createModifier(Object value);
}
}
public static class Modifiers {
private static final Map<String, ItemSettings.Modifier.Factory> FACTORIES = new HashMap<>();
static {
registerFactory("fuel-time", (value -> {
int intValue = MiscUtils.getAsInt(value);
return settings -> settings.fuelTime(intValue);
}));
}
private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) {
FACTORIES.put(id, factory);
}
}
}