Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/ch/njol/skript/registrations/Feature.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public enum Feature implements Experiment {
CATCH_ERRORS("catch runtime errors", LifeCycle.EXPERIMENTAL, "error catching [section]"),
TYPE_HINTS("type hints", LifeCycle.EXPERIMENTAL, "[local variable] type hints"),
DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]"),
EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components")
EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components"),
FOOD_COMPONENTS("food components", LifeCycle.EXPERIMENTAL, "food components"),
;

private final String codeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.skriptlang.skript.addon.AddonModule;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableModule;
import org.skriptlang.skript.bukkit.itemcomponents.food.FoodModule;
import org.skriptlang.skript.bukkit.itemcomponents.generic.ExprItemCompCopy;

public class ItemComponentModule implements AddonModule {
Expand Down Expand Up @@ -47,7 +48,10 @@ public String toVariableNameString(ComponentWrapper wrapper) {

@Override
public void load(SkriptAddon addon) {
addon.loadModules(new EquippableModule());
addon.loadModules(
new EquippableModule(),
new FoodModule()
);

ExprItemCompCopy.register(addon.syntaxRegistry());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.skriptlang.skript.bukkit.itemcomponents.food;

import ch.njol.skript.lang.SyntaxElement;
import ch.njol.skript.registrations.Feature;
import org.skriptlang.skript.lang.experiment.ExperimentData;
import org.skriptlang.skript.lang.experiment.SimpleExperimentalSyntax;

/**
* Typed {@link SimpleExperimentalSyntax} for {@link SyntaxElement}s that require {@link Feature#FOOD_COMPONENTS}.
*/
public interface FoodExperimentalSyntax extends SimpleExperimentalSyntax {

ExperimentData EXPERIMENT_DATA = ExperimentData.createSingularData(Feature.FOOD_COMPONENTS);

@Override
default ExperimentData getExperimentData() {
return EXPERIMENT_DATA;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.skriptlang.skript.bukkit.itemcomponents.food;

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.classes.Parser;
import ch.njol.skript.expressions.base.EventValueExpression;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.util.ItemSource;
import ch.njol.skript.util.slot.Slot;
import io.papermc.paper.datacomponent.item.FoodProperties;
import org.bukkit.inventory.ItemStack;
import org.skriptlang.skript.addon.AddonModule;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.CondFoodCompAlwaysEat;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.EffFoodCompAlwaysEat;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.ExprFoodCompNutrition;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.ExprFoodCompSaturation;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.ExprFoodComponent;
import org.skriptlang.skript.bukkit.itemcomponents.food.elements.ExprSecBlankFoodComp;
import org.skriptlang.skript.lang.converter.Converter;
import org.skriptlang.skript.lang.converter.Converters;
import org.skriptlang.skript.registration.SyntaxRegistry;

import java.util.Arrays;
import java.util.function.Consumer;

public class FoodModule implements AddonModule {

@Override
public boolean canLoad(SkriptAddon addon) {
return Skript.classExists("io.papermc.paper.datacomponent.item.FoodProperties");
}

@Override
public void init(SkriptAddon addon) {
Classes.registerClass(new ClassInfo<>(FoodWrapper.class, "foodcomponent")
.user("food ?components?")
.name("Food Component")
.description("""
Represents a food component used for items.
NOTE: Food component elements are experimental. Thus, they are subject to change and may not work as intended.
""")
.requiredPlugins("Minecraft 1.21.3+")
.since("INSERT VERSION")
.defaultExpression(new EventValueExpression<>(FoodWrapper.class))
.parser(new Parser<>() {
@Override
public boolean canParse(ParseContext context) {
return false;
}

@Override
public String toString(FoodWrapper wrapper, int flags) {
return "food component";
}

@Override
public String toVariableNameString(FoodWrapper wrapper) {
return "food component#" + wrapper.hashCode();
}
})
.after("itemstack", "itemtype", "slot")
);

Converters.registerConverter(FoodProperties.class, FoodWrapper.class, FoodWrapper::new, Converter.NO_RIGHT_CHAINING);
Converters.registerConverter(ItemStack.class, FoodWrapper.class, FoodWrapper::new, Converter.NO_RIGHT_CHAINING);
Converters.registerConverter(ItemType.class, FoodWrapper.class, itemType -> new FoodWrapper(new ItemSource<>(itemType)), Converter.NO_RIGHT_CHAINING);
Converters.registerConverter(Slot.class, FoodWrapper.class, slot -> {
ItemSource<Slot> itemSource = ItemSource.fromSlot(slot);
if (itemSource == null)
return null;
return new FoodWrapper(itemSource);
}, Converter.NO_RIGHT_CHAINING);
}

@Override
public void load(SkriptAddon addon) {
register(addon.syntaxRegistry(),

CondFoodCompAlwaysEat::register,

EffFoodCompAlwaysEat::register,

ExprFoodCompNutrition::register,
ExprFoodComponent::register,
ExprFoodCompSaturation::register,

ExprSecBlankFoodComp::register
);
}

private void register(SyntaxRegistry registry, Consumer<SyntaxRegistry>... consumers) {
Arrays.stream(consumers).forEach(consumer -> consumer.accept(registry));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.skriptlang.skript.bukkit.itemcomponents.food;

import ch.njol.skript.util.ItemSource;
import io.papermc.paper.datacomponent.DataComponentType.Valued;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.FoodProperties;
import io.papermc.paper.datacomponent.item.FoodProperties.Builder;
import org.bukkit.inventory.ItemStack;
import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper;

/**
* A {@link ComponentWrapper} for getting and setting data on a {@link FoodProperties} component.
*/
@SuppressWarnings("UnstableApiUsage")
public class FoodWrapper extends ComponentWrapper<FoodProperties, Builder> {

public FoodWrapper(ItemStack itemStack) {
super(itemStack);
}

public FoodWrapper(ItemSource<?> itemSource) {
super(itemSource);
}

public FoodWrapper(FoodProperties component) {
super(component);
}

public FoodWrapper(Builder builder) {
super(builder);
}

@Override
public Valued<FoodProperties> getDataComponentType() {
return DataComponentTypes.FOOD;
}

@Override
protected FoodProperties getComponent(ItemStack itemStack) {
FoodProperties food = itemStack.getData(DataComponentTypes.FOOD);
if (food != null)
return food;
return FoodProperties.food().build();
}

@Override
protected Builder getBuilder(ItemStack itemStack) {
FoodProperties food = itemStack.getData(DataComponentTypes.FOOD);
if (food != null)
return food.toBuilder();
return FoodProperties.food();
}

@Override
protected void setComponent(ItemStack itemStack, FoodProperties component) {
itemStack.setData(DataComponentTypes.FOOD, component);
}

@Override
protected Builder getBuilder(FoodProperties component) {
return component.toBuilder();
}

@Override
public FoodWrapper clone() {
FoodProperties base = getComponent();
FoodWrapper clone = newWrapper();
clone.editBuilder(builder -> {
builder.canAlwaysEat(base.canAlwaysEat());
builder.nutrition(base.nutrition());
builder.saturation(base.saturation());
});
return clone;
}

@Override
public FoodProperties newComponent() {
return newBuilder().build();
}

@Override
public Builder newBuilder() {
return FoodProperties.food();
}

@Override
public FoodWrapper newWrapper() {
return newInstance();
}

public static FoodWrapper newInstance() {
return new FoodWrapper(FoodProperties.food().build());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.skriptlang.skript.bukkit.itemcomponents.food.elements;

import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Example;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.RequiredPlugins;
import ch.njol.skript.doc.Since;
import org.skriptlang.skript.bukkit.itemcomponents.food.FoodExperimentalSyntax;
import org.skriptlang.skript.bukkit.itemcomponents.food.FoodWrapper;
import org.skriptlang.skript.registration.SyntaxRegistry;

@Name("Food Component - Can Always Be Eaten")
@Description("""
Whether an item can be eaten when the player's hunger bar is full.
NOTE: Food component elements are experimental. Thus, they are subject to change and may not work as intended.
""")
@Example("""
if {_item} can not always be eaten:
allow {_item} to always be eaten
""")
@Example("""
set {_component} to the food component of {_item}
if {_component} can be eaten when full:
prevent {_component} from being eaten when full
""")
@RequiredPlugins("Minecraft 1.21.3+")
@Since("INSERT VERSION")
public class CondFoodCompAlwaysEat extends PropertyCondition<FoodWrapper> implements FoodExperimentalSyntax {

public static void register(SyntaxRegistry registry) {
registry.register(
SyntaxRegistry.CONDITION,
infoBuilder(
CondFoodCompAlwaysEat.class,
PropertyType.CAN,
"(always be eaten|be eaten when full)",
"foodcomponents"
)
.supplier(CondFoodCompAlwaysEat::new)
.build()
);
}

@Override
public boolean check(FoodWrapper wrapper) {
return wrapper.getComponent().canAlwaysEat();
}

@Override
protected String getPropertyName() {
return "always be eaten";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.skriptlang.skript.bukkit.itemcomponents.food.elements;

import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Example;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.RequiredPlugins;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.SyntaxStringBuilder;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.bukkit.itemcomponents.food.FoodExperimentalSyntax;
import org.skriptlang.skript.bukkit.itemcomponents.food.FoodWrapper;
import org.skriptlang.skript.registration.SyntaxInfo;
import org.skriptlang.skript.registration.SyntaxRegistry;

@Name("Food Component - Always Be Eaten")
@Description("""
Whether an item should be eaten when the player's hunger bar is full.
NOTE: Food component elements are experimental. Thus, they are subject to change and may not work as intended.
""")
@Example("""
if {_item} can not always be eaten:
allow {_item} to always be eaten
""")
@Example("""
set {_component} to the food component of {_item}
if {_component} can be eaten when full:
prevent {_component} from being eaten when full
""")
@RequiredPlugins("Minecraft 1.21.3+")
@Since("INSERT VERSION")
public class EffFoodCompAlwaysEat extends Effect implements FoodExperimentalSyntax {

public static void register(SyntaxRegistry registry) {
registry.register(
SyntaxRegistry.EFFECT,
SyntaxInfo.builder(EffFoodCompAlwaysEat.class)
.addPatterns(
"(allow|force) %foodcomponents% to (always be eaten|be eaten when full)",
"prevent %foodcomponents% from (always being eaten|being eaten when full)"
)
.supplier(EffFoodCompAlwaysEat::new)
.build()
);
}

private boolean alwaysEat;
private Expression<FoodWrapper> wrappers;

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
alwaysEat = matchedPattern == 0;
//noinspection unchecked
wrappers = (Expression<FoodWrapper>) exprs[0];
return true;
}

@Override
protected void execute(Event event) {
wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> {
builder.canAlwaysEat(alwaysEat);
}));
}

@Override
public String toString(@Nullable Event event, boolean debug) {
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);
if (alwaysEat) {
builder.append("allow", wrappers, "to always be eaten");
} else {
builder.append("prevent", wrappers, "from always being eaten");
}
return builder.toString();
}

}
Loading