spellbook/focus recipes are now in JEI

This commit is contained in:
yrsegal@gmail.com 2022-05-01 13:38:58 -04:00
parent a36d86aae9
commit eaac65c47f
9 changed files with 224 additions and 107 deletions

View file

@ -1,8 +1,10 @@
package at.petrak.hexcasting.api.item;
import at.petrak.hexcasting.api.spell.SpellDatum;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.level.ServerLevel;
@ -13,6 +15,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface DataHolderItem {
String TAG_OVERRIDE_VISUALLY = "VisualOverride";
@Nullable CompoundTag readDatumTag(ItemStack stack);
@Nullable
@ -49,6 +53,12 @@ public interface DataHolderItem {
if (pIsAdvanced.isAdvanced()) {
pTooltipComponents.add(NbtUtils.toPrettyComponent(datumTag));
}
} else if (pStack.hasTag()) {
var tag = pStack.getTag();
if (tag != null && tag.contains(DataHolderItem.TAG_OVERRIDE_VISUALLY, Tag.TAG_STRING)) {
pTooltipComponents.add(new TranslatableComponent("hexcasting.spelldata.onitem",
new TranslatableComponent("hexcasting.spelldata.anything").withStyle(ChatFormatting.LIGHT_PURPLE)));
}
}
}
}

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType
import at.petrak.hexcasting.api.utils.HexUtils
import at.petrak.hexcasting.api.utils.HexUtils.serializeToNBT
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType
import net.minecraft.ChatFormatting
import net.minecraft.nbt.*
import net.minecraft.network.chat.Component
@ -259,6 +259,19 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
ValidTypes.any { clazz -> clazz.isAssignableFrom(checkee.javaClass) }
}
@JvmStatic
fun GetTagName(datumType: DatumType): String {
return when (datumType) {
DatumType.ENTITY -> TAG_ENTITY
DatumType.WIDGET -> TAG_WIDGET
DatumType.LIST -> TAG_LIST
DatumType.PATTERN -> TAG_PATTERN
DatumType.DOUBLE -> TAG_DOUBLE
DatumType.VEC -> TAG_VEC3
DatumType.OTHER, DatumType.EMPTY -> ""
}
}
}
}

View file

@ -29,6 +29,8 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderers;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextColor;
import net.minecraft.network.chat.TextComponent;
@ -251,19 +253,26 @@ public class RegisterClientStuff {
ItemProperties.register((Item) item, ItemFocus.DATATYPE_PRED,
(stack, level, holder, holderID) -> {
var datum = item.readDatumTag(stack);
String typename = null;
if (datum != null) {
var typename = datum.getAllKeys().iterator().next();
return switch (typename) {
case SpellDatum.TAG_ENTITY -> 1f;
case SpellDatum.TAG_DOUBLE -> 2f;
case SpellDatum.TAG_VEC3 -> 3f;
case SpellDatum.TAG_WIDGET -> 4f;
case SpellDatum.TAG_LIST -> 5f;
case SpellDatum.TAG_PATTERN -> 6f;
default -> 0f; // uh oh
};
typename = datum.getAllKeys().iterator().next();
} else if (stack.hasTag()) {
CompoundTag tag = stack.getTag();
if (tag != null && tag.contains(DataHolderItem.TAG_OVERRIDE_VISUALLY, Tag.TAG_STRING)) {
typename = tag.getString(DataHolderItem.TAG_OVERRIDE_VISUALLY);
}
}
return 0f;
return typename == null ? 0f : switch (typename) {
case SpellDatum.TAG_ENTITY -> 1f;
case SpellDatum.TAG_DOUBLE -> 2f;
case SpellDatum.TAG_VEC3 -> 3f;
case SpellDatum.TAG_WIDGET -> 4f;
case SpellDatum.TAG_LIST -> 5f;
case SpellDatum.TAG_PATTERN -> 6f;
default -> 0f; // uh oh
};
});
ItemProperties.register((Item) item, ItemFocus.SEALED_PRED,
(stack, level, holder, holderID) -> item.canWrite(stack, SpellDatum.make(Widget.NULL)) ? 0f : 1f);

View file

@ -58,11 +58,16 @@ public class ItemSpellbook extends Item implements DataHolderItem {
new TextComponent(String.valueOf(highest)).withStyle(ChatFormatting.WHITE))
.withStyle(ChatFormatting.GRAY));
} else {
if (sealed)
tooltip.add(new TranslatableComponent("hexcasting.tooltip.spellbook.empty.sealed",
new TranslatableComponent("hexcasting.tooltip.spellbook.sealed").withStyle(ChatFormatting.GOLD))
.withStyle(ChatFormatting.GRAY));
else
boolean overridden = tag.contains(DataHolderItem.TAG_OVERRIDE_VISUALLY, Tag.TAG_STRING);
if (sealed) {
if (overridden) {
tooltip.add(new TranslatableComponent("hexcasting.tooltip.spellbook.sealed").withStyle(ChatFormatting.GOLD));
} else {
tooltip.add(new TranslatableComponent("hexcasting.tooltip.spellbook.empty.sealed",
new TranslatableComponent("hexcasting.tooltip.spellbook.sealed").withStyle(ChatFormatting.GOLD))
.withStyle(ChatFormatting.GRAY));
}
} else if (!overridden)
tooltip.add(new TranslatableComponent("hexcasting.tooltip.spellbook.empty").withStyle(ChatFormatting.GRAY));
}
} else {
@ -208,6 +213,27 @@ public class ItemSpellbook extends Item implements DataHolderItem {
}
public static boolean HasDatum(ItemStack stack) {
if (!stack.hasTag()) {
return false;
}
var tag = stack.getTag();
int idx;
if (tag.contains(TAG_SELECTED_PAGE, Tag.TAG_ANY_NUMERIC)) {
idx = tag.getInt(TAG_SELECTED_PAGE);
} else {
idx = 0;
}
var key = String.valueOf(idx);
if (tag.contains(TAG_PAGES, Tag.TAG_COMPOUND)) {
var pagesTag = tag.getCompound(TAG_PAGES);
return pagesTag.contains(key);
} else {
return false;
}
}
public static boolean IsSealed(ItemStack stack) {
if (!stack.hasTag())
return false;

View file

@ -1,9 +1,12 @@
package at.petrak.hexcasting.common.recipe;
import at.petrak.hexcasting.HexMod;
import at.petrak.hexcasting.common.recipe.ingredient.UnsealedIngredient;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.registries.DeferredRegister;
@ -22,5 +25,7 @@ public class HexRecipeSerializers {
@SubscribeEvent
public static void registerTypes(RegistryEvent.Register<Item> evt) {
BRAINSWEEP_TYPE = RecipeType.register(HexMod.MOD_ID + ":brainsweep");
CraftingHelper.register(new ResourceLocation(HexMod.MOD_ID, "unsealed"), UnsealedIngredient.Serializer.INSTANCE);
}
}

View file

@ -2,60 +2,41 @@ package at.petrak.hexcasting.common.recipe;
import at.petrak.hexcasting.common.items.HexItems;
import at.petrak.hexcasting.common.items.ItemFocus;
import at.petrak.hexcasting.common.recipe.ingredient.UnsealedIngredient;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
public class SealFocusRecipe extends CustomRecipe {
public class SealFocusRecipe extends ShapelessRecipe {
public static final SimpleRecipeSerializer<SealFocusRecipe> SERIALIZER =
new SimpleRecipeSerializer<>(SealFocusRecipe::new);
private static ItemStack getSealedStack() {
ItemStack output = new ItemStack(HexItems.FOCUS::get);
output.getOrCreateTag().putBoolean(ItemFocus.TAG_SEALED, true);
return output;
}
private static NonNullList<Ingredient> createIngredients() {
NonNullList<Ingredient> ingredients = NonNullList.createWithCapacity(2);
ingredients.add(UnsealedIngredient.of(new ItemStack(HexItems.FOCUS::get)));
ingredients.add(Ingredient.of(Items.HONEYCOMB));
return ingredients;
}
public SealFocusRecipe(ResourceLocation id) {
super(id);
super(id, "", getSealedStack(), createIngredients());
}
@Override
public boolean matches(CraftingContainer inv, Level world) {
var foundWax = false;
var foundOkFocus = false;
for (int i = 0; i < inv.getContainerSize(); i++) {
var stack = inv.getItem(i);
if (!stack.isEmpty()) {
if (stack.is(HexItems.FOCUS.get())) {
if (foundOkFocus) {
return false;
}
if (stack.hasTag()
&& stack.getTag().contains(ItemFocus.TAG_DATA)
&& (!stack.getTag().contains(ItemFocus.TAG_SEALED)
|| !stack.getTag().getBoolean(ItemFocus.TAG_SEALED))) {
foundOkFocus = true;
} else {
return false;
}
} else if (stack.is(Items.HONEYCOMB)) {
if (foundWax) {
return false;
}
foundWax = true;
} else {
return false;
}
}
}
return foundWax && foundOkFocus;
}
@Override
public ItemStack assemble(CraftingContainer inv) {
public @NotNull ItemStack assemble(CraftingContainer inv) {
ItemStack out = ItemStack.EMPTY;
for (int i = 0; i < inv.getContainerSize(); i++) {
@ -75,12 +56,7 @@ public class SealFocusRecipe extends CustomRecipe {
}
@Override
public boolean canCraftInDimensions(int width, int height) {
return width * height >= 2;
}
@Override
public RecipeSerializer<?> getSerializer() {
public @NotNull RecipeSerializer<?> getSerializer() {
return SERIALIZER;
}
}

View file

@ -2,57 +2,41 @@ package at.petrak.hexcasting.common.recipe;
import at.petrak.hexcasting.common.items.HexItems;
import at.petrak.hexcasting.common.items.ItemSpellbook;
import at.petrak.hexcasting.common.recipe.ingredient.UnsealedIngredient;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
public class SealSpellbookRecipe extends CustomRecipe {
public class SealSpellbookRecipe extends ShapelessRecipe {
public static final SimpleRecipeSerializer<SealSpellbookRecipe> SERIALIZER =
new SimpleRecipeSerializer<>(SealSpellbookRecipe::new);
private static ItemStack getSealedStack() {
ItemStack output = new ItemStack(HexItems.SPELLBOOK::get);
ItemSpellbook.SetSealed(output, true);
return output;
}
private static NonNullList<Ingredient> createIngredients() {
NonNullList<Ingredient> ingredients = NonNullList.createWithCapacity(2);
ingredients.add(UnsealedIngredient.of(new ItemStack(HexItems.SPELLBOOK::get)));
ingredients.add(Ingredient.of(Items.HONEYCOMB));
return ingredients;
}
public SealSpellbookRecipe(ResourceLocation id) {
super(id);
super(id, "", getSealedStack(), createIngredients());
}
@Override
public boolean matches(CraftingContainer inv, Level world) {
var foundWax = false;
var foundOkSpellbook = false;
for (int i = 0; i < inv.getContainerSize(); i++) {
var stack = inv.getItem(i);
if (!stack.isEmpty()) {
if (stack.is(HexItems.SPELLBOOK.get())) {
if (foundOkSpellbook) {
return false;
}
if (!ItemSpellbook.IsSealed(stack)) {
foundOkSpellbook = true;
} else {
return false;
}
} else if (stack.is(Items.HONEYCOMB)) {
if (foundWax) {
return false;
}
foundWax = true;
} else {
return false;
}
}
}
return foundWax && foundOkSpellbook;
}
@Override
public ItemStack assemble(CraftingContainer inv) {
public @NotNull ItemStack assemble(CraftingContainer inv) {
ItemStack out = ItemStack.EMPTY;
for (int i = 0; i < inv.getContainerSize(); i++) {
@ -67,16 +51,12 @@ public class SealSpellbookRecipe extends CustomRecipe {
ItemSpellbook.SetSealed(out, true);
out.setCount(1);
}
return out;
}
@Override
public boolean canCraftInDimensions(int width, int height) {
return width * height >= 2;
}
@Override
public RecipeSerializer<?> getSerializer() {
public @NotNull RecipeSerializer<?> getSerializer() {
return SERIALIZER;
}
}

View file

@ -0,0 +1,97 @@
package at.petrak.hexcasting.common.recipe.ingredient;
import at.petrak.hexcasting.api.cap.DataHolder;
import at.petrak.hexcasting.api.cap.HexCapabilities;
import at.petrak.hexcasting.api.item.DataHolderItem;
import at.petrak.hexcasting.api.spell.DatumType;
import at.petrak.hexcasting.api.spell.SpellDatum;
import at.petrak.hexcasting.api.spell.Widget;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.common.crafting.AbstractIngredient;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.IIngredientSerializer;
import net.minecraftforge.common.crafting.NBTIngredient;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
public class UnsealedIngredient extends AbstractIngredient {
private final ItemStack stack;
protected UnsealedIngredient(ItemStack stack) {
super(Arrays.stream(DatumType.values())
.filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER)
.map((type) -> {
ItemStack newStack = stack.copy();
newStack.getOrCreateTag().putString(DataHolderItem.TAG_OVERRIDE_VISUALLY, SpellDatum.GetTagName(type));
return new Ingredient.ItemValue(newStack);
}));
this.stack = stack;
}
/**
* Creates a new ingredient matching the given stack
*/
public static UnsealedIngredient of(ItemStack stack) {
return new UnsealedIngredient(stack);
}
@Override
public boolean test(@Nullable ItemStack input) {
if (input == null)
return false;
if(this.stack.getItem() == input.getItem() && this.stack.getDamageValue() == input.getDamageValue()) {
Optional<DataHolder> holder = HexCapabilities.getCapability(input, HexCapabilities.DATUM);
if (holder.isPresent()) {
return holder.get().readRawDatum() != null && holder.get().writeDatum(SpellDatum.make(Widget.NULL), true);
}
}
return false;
}
@Override
public boolean isSimple() {
return false;
}
@Override
public @NotNull IIngredientSerializer<? extends Ingredient> getSerializer() {
return UnsealedIngredient.Serializer.INSTANCE;
}
@Override
public @NotNull JsonElement toJson() {
JsonObject json = new JsonObject();
json.addProperty("type", Objects.toString(CraftingHelper.getID(NBTIngredient.Serializer.INSTANCE)));
json.addProperty("item", Objects.toString(stack.getItem().getRegistryName()));
return json;
}
public static class Serializer implements IIngredientSerializer<UnsealedIngredient> {
public static final UnsealedIngredient.Serializer INSTANCE = new UnsealedIngredient.Serializer();
@Override
public @NotNull UnsealedIngredient parse(FriendlyByteBuf buffer) {
return new UnsealedIngredient(buffer.readItem());
}
@Override
public @NotNull UnsealedIngredient parse(@NotNull JsonObject json) {
return new UnsealedIngredient(CraftingHelper.getItemStack(json, true));
}
@Override
public void write(FriendlyByteBuf buffer, UnsealedIngredient ingredient) {
buffer.writeItem(ingredient.stack);
}
}
}

View file

@ -120,6 +120,7 @@
"hexcasting.tooltip.brainsweep.biome.any": "Any Biome",
"hexcasting.tooltip.brainsweep.min_level": "Level %d or higher",
"hexcasting.spelldata.onitem": "Contains: %s",
"hexcasting.spelldata.anything": "Anything",
"hexcasting.spelldata.entity.whoknows": "An Entity (this should only show up if this was stored before the 0.5.0 update, use Scribe's Reflection, Scribe's Gambit to fix)",
"hexcasting.spelldata.akashic.nopos": "The owning record does not know of any iota here (this is a bug)",