JEI plugin!
This commit is contained in:
parent
dbf1f9daa1
commit
2af5dd6764
15 changed files with 492 additions and 151 deletions
|
@ -3,16 +3,32 @@ package at.petrak.hexcasting.client;
|
|||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
// I can't find a better way to do this :(
|
||||
public class ClientTickCounter {
|
||||
private static long tickCount = 0;
|
||||
public static long ticksInGame = 0L;
|
||||
public static float partialTicks = 0.0F;
|
||||
public static float delta = 0.0F;
|
||||
public static float total = 0.0F;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(TickEvent.ClientTickEvent evt) {
|
||||
tickCount++;
|
||||
public static void onRenderTick(TickEvent.RenderTickEvent evt) {
|
||||
if (evt.phase == TickEvent.Phase.START) {
|
||||
partialTicks = evt.renderTickTime;
|
||||
} else {
|
||||
calcDelta();
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onTickEnd(TickEvent.ClientTickEvent evt) {
|
||||
if (evt.phase == TickEvent.Phase.END) {
|
||||
++ticksInGame;
|
||||
partialTicks = 0.0F;
|
||||
calcDelta();
|
||||
}
|
||||
}
|
||||
|
||||
public static long getTickCount() {
|
||||
return tickCount;
|
||||
private static void calcDelta() {
|
||||
float oldTotal = total;
|
||||
total = (float)ticksInGame + partialTicks;
|
||||
delta = total - oldTotal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class HexAdditionalRenderers {
|
|||
sentinel.position().y - playerPos.y,
|
||||
sentinel.position().z - playerPos.z);
|
||||
|
||||
var time = ClientTickCounter.getTickCount() + partialTicks;
|
||||
var time = ClientTickCounter.total / 2;
|
||||
var bobSpeed = 1f / 20;
|
||||
var magnitude = 0.1f;
|
||||
ps.translate(0, Mth.sin(bobSpeed * time) * magnitude, 0);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package at.petrak.hexcasting.client
|
||||
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.utils.HexUtils
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.utils.HexUtils
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
|
@ -169,8 +169,7 @@ object RenderLib {
|
|||
if (points.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
val mc = Minecraft.getInstance()
|
||||
val zSeed = (mc.frameTime.toDouble() + ClientTickCounter.getTickCount()) * speed
|
||||
val zSeed = (ClientTickCounter.total.toDouble()) * speed
|
||||
// Create our output list of zap points
|
||||
val zappyPts = mutableListOf(points[0])
|
||||
// For each segment in the original...
|
||||
|
|
|
@ -77,7 +77,7 @@ public class PatternTooltipGreeble implements ClientTooltipComponent, TooltipCom
|
|||
outer, outer, null);
|
||||
RenderLib.drawLineSeq(mat, this.zappyPoints, 2f, 0,
|
||||
innerDark, innerLight,
|
||||
ClientTickCounter.getTickCount() / 40f);
|
||||
ClientTickCounter.total / 40f);
|
||||
RenderLib.drawSpot(mat, this.zappyPoints.get(0), 2.5f, 1f, 0.1f, 0.15f, 0.6f);
|
||||
|
||||
for (var dot : this.pathfinderDots) {
|
||||
|
|
|
@ -5,8 +5,10 @@ import at.petrak.hexcasting.common.blocks.HexBlocks;
|
|||
import at.petrak.hexcasting.common.items.colorizer.ItemDyeColorizer;
|
||||
import at.petrak.hexcasting.common.items.colorizer.ItemPrideColorizer;
|
||||
import at.petrak.hexcasting.common.items.colorizer.ItemUUIDColorizer;
|
||||
import at.petrak.hexcasting.common.items.magic.*;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import at.petrak.hexcasting.common.items.magic.ItemArtifact;
|
||||
import at.petrak.hexcasting.common.items.magic.ItemCypher;
|
||||
import at.petrak.hexcasting.common.items.magic.ItemManaBattery;
|
||||
import at.petrak.hexcasting.common.items.magic.ItemTrinket;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
@ -15,6 +17,7 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
|
@ -22,26 +25,9 @@ public class HexItems {
|
|||
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, HexMod.MOD_ID);
|
||||
public static final CreativeModeTab TAB = new CreativeModeTab(HexMod.MOD_ID) {
|
||||
@Override
|
||||
public ItemStack makeIcon() {
|
||||
public @NotNull ItemStack makeIcon() {
|
||||
return new ItemStack(SPELLBOOK::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillItemList(NonNullList<ItemStack> items) {
|
||||
super.fillItemList(items);
|
||||
|
||||
var manamounts = new int[]{
|
||||
100_000,
|
||||
1_000_000,
|
||||
10_000_000,
|
||||
100_000_000,
|
||||
1_000_000_000,
|
||||
};
|
||||
for (int manamount : manamounts) {
|
||||
var stack = new ItemStack(BATTERY.get());
|
||||
items.add(ItemManaHolder.withMana(stack, manamount, manamount));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static final RegistryObject<ItemWand> WAND_OAK = ITEMS.register("wand_oak",
|
||||
|
@ -88,7 +74,7 @@ public class HexItems {
|
|||
() -> new ItemArtifact(unstackable()));
|
||||
|
||||
public static final RegistryObject<ItemManaBattery> BATTERY = ITEMS.register("battery",
|
||||
() -> new ItemManaBattery(new Item.Properties().stacksTo(1)));
|
||||
() -> new ItemManaBattery(props().stacksTo(1)));
|
||||
|
||||
public static final EnumMap<DyeColor, RegistryObject<ItemDyeColorizer>> DYE_COLORIZERS = new EnumMap<>(
|
||||
DyeColor.class);
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package at.petrak.hexcasting.common.items.magic;
|
||||
|
||||
import at.petrak.hexcasting.HexMod;
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ItemManaBattery extends ItemManaHolder {
|
||||
public static final ResourceLocation MANA_PREDICATE = new ResourceLocation(HexMod.MOD_ID, "mana");
|
||||
|
@ -21,4 +25,22 @@ public class ItemManaBattery extends ItemManaHolder {
|
|||
public boolean canRecharge(ItemStack stack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillItemCategory(@NotNull CreativeModeTab tab, @NotNull NonNullList<ItemStack> items) {
|
||||
// who was drunk at the wheel when they named this
|
||||
if (allowdedIn(tab)) {
|
||||
var manamounts = new int[]{
|
||||
ManaConstants.CRYSTAL_UNIT,
|
||||
20 * ManaConstants.CRYSTAL_UNIT,
|
||||
64 * ManaConstants.CRYSTAL_UNIT,
|
||||
640 * ManaConstants.CRYSTAL_UNIT,
|
||||
6400 * ManaConstants.CRYSTAL_UNIT,
|
||||
};
|
||||
for (int manamount : manamounts) {
|
||||
var stack = new ItemStack(this);
|
||||
items.add(ItemManaHolder.withMana(stack, manamount, manamount));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package at.petrak.hexcasting.interop.jei;
|
||||
|
||||
import at.petrak.hexcasting.client.ClientTickCounter;
|
||||
import at.petrak.hexcasting.common.recipe.BrainsweepRecipe;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Vector3f;
|
||||
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.drawable.IDrawableStatic;
|
||||
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
|
||||
import mezz.jei.api.helpers.IGuiHelper;
|
||||
import mezz.jei.api.recipe.IFocusGroup;
|
||||
import mezz.jei.api.recipe.RecipeIngredientRole;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import net.minecraft.world.entity.npc.VillagerType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static at.petrak.hexcasting.common.lib.RegisterHelper.prefix;
|
||||
|
||||
public class BrainsweepRecipeCategory implements IRecipeCategory<BrainsweepRecipe> {
|
||||
public static final ResourceLocation UID = prefix("brainsweep");
|
||||
|
||||
private final IDrawableStatic background;
|
||||
private final IDrawable icon;
|
||||
private final Component localizedName;
|
||||
|
||||
public BrainsweepRecipeCategory(IGuiHelper guiHelper) {
|
||||
ResourceLocation location = prefix("textures/gui/brainsweep_jei.png");
|
||||
background = guiHelper.drawableBuilder(location, 0, 0, 118, 86).setTextureSize(128, 128).build();
|
||||
var brainsweep = prefix("brainsweep");
|
||||
localizedName = new TranslatableComponent("hexcasting.spell." + brainsweep);
|
||||
icon = new PatternDrawable(brainsweep, 16, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public @NotNull Component getTitle() {
|
||||
return localizedName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IDrawable getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IDrawable getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Component> getTooltipStrings(@NotNull BrainsweepRecipe recipe, @NotNull IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
|
||||
if (37 <= mouseX && mouseX <= 37 + 26 && 19 <= mouseY && mouseY <= 19 + 48) {
|
||||
List<Component> tooltip = new ArrayList<>(3);
|
||||
var profession = recipe.villagerIn().profession();
|
||||
if (profession == null) {
|
||||
tooltip.add(new TranslatableComponent("hexcasting.tooltip.brainsweep.profession.any"));
|
||||
} else {
|
||||
var professionKey = "entity.minecraft.villager." + profession.getPath();
|
||||
tooltip.add(new TranslatableComponent("hexcasting.tooltip.brainsweep.profession",
|
||||
new TranslatableComponent(professionKey)));
|
||||
}
|
||||
var biome = recipe.villagerIn().biome();
|
||||
if (biome == null) {
|
||||
tooltip.add(new TranslatableComponent("hexcasting.tooltip.brainsweep.biome.any"));
|
||||
} else {
|
||||
var biomeKey = "biome.minecraft." + biome.getPath();
|
||||
tooltip.add(new TranslatableComponent("hexcasting.tooltip.brainsweep.biome",
|
||||
new TranslatableComponent(biomeKey)));
|
||||
}
|
||||
|
||||
tooltip.add(new TranslatableComponent("hexcasting.tooltip.brainsweep.min_level",
|
||||
recipe.villagerIn().minLevel()));
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Villager villager;
|
||||
|
||||
@Override
|
||||
public void draw(@NotNull BrainsweepRecipe recipe, @NotNull IRecipeSlotsView recipeSlotsView, @NotNull PoseStack stack, double mouseX, double mouseY) {
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if (level != null) {
|
||||
VillagerProfession profession = Objects.requireNonNullElse(ForgeRegistries.PROFESSIONS.getValue(recipe.villagerIn().profession()),
|
||||
VillagerProfession.TOOLSMITH);
|
||||
VillagerType biome = Objects.requireNonNullElse(Registry.VILLAGER_TYPE.get(recipe.villagerIn().biome()),
|
||||
VillagerType.PLAINS);
|
||||
int minLevel = recipe.villagerIn().minLevel();
|
||||
if (villager == null)
|
||||
villager = new Villager(EntityType.VILLAGER, level);
|
||||
|
||||
villager.setVillagerData(villager.getVillagerData()
|
||||
.setProfession(profession)
|
||||
.setType(biome)
|
||||
.setLevel(minLevel));
|
||||
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
renderEntity(stack, villager, level, 50, 62.5f, ClientTickCounter.total, 20, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderEntity(PoseStack ms, Entity entity, Level world, float x, float y, float rotation, float renderScale, float offset) {
|
||||
entity.level = world;
|
||||
ms.pushPose();
|
||||
ms.translate(x, y, 50.0D);
|
||||
ms.scale(renderScale, renderScale, renderScale);
|
||||
ms.translate(0.0D, offset, 0.0D);
|
||||
ms.mulPose(Vector3f.ZP.rotationDegrees(180.0F));
|
||||
ms.mulPose(Vector3f.YP.rotationDegrees(rotation));
|
||||
EntityRenderDispatcher erd = Minecraft.getInstance().getEntityRenderDispatcher();
|
||||
MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
erd.setRenderShadow(false);
|
||||
erd.render(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F, ms, immediate, 15728880);
|
||||
erd.setRenderShadow(true);
|
||||
immediate.endBatch();
|
||||
ms.popPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(@NotNull IRecipeLayoutBuilder builder, @NotNull BrainsweepRecipe recipe, @NotNull IFocusGroup focuses) {
|
||||
builder.addSlot(RecipeIngredientRole.INPUT, 12, 35)
|
||||
.addItemStacks(recipe.blockIn().getDisplayedStacks());
|
||||
builder.addSlot(RecipeIngredientRole.OUTPUT, 87, 35)
|
||||
.addItemStack(new ItemStack(recipe.result().getBlock()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull RecipeType<BrainsweepRecipe> getRecipeType() {
|
||||
return HexJEIPlugin.BRAINSWEEPING;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public @NotNull ResourceLocation getUid() {
|
||||
return UID;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public @NotNull Class<? extends BrainsweepRecipe> getRecipeClass() {
|
||||
return BrainsweepRecipe.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package at.petrak.hexcasting.interop.jei;
|
||||
|
||||
import at.petrak.hexcasting.HexMod;
|
||||
import at.petrak.hexcasting.common.items.HexItems;
|
||||
import at.petrak.hexcasting.common.recipe.BrainsweepRecipe;
|
||||
import at.petrak.hexcasting.common.recipe.HexRecipeSerializers;
|
||||
import mezz.jei.api.IModPlugin;
|
||||
import mezz.jei.api.JeiPlugin;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.registration.IRecipeCatalystRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCategoryRegistration;
|
||||
import mezz.jei.api.registration.IRecipeRegistration;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static at.petrak.hexcasting.common.lib.RegisterHelper.prefix;
|
||||
|
||||
@JeiPlugin
|
||||
public class HexJEIPlugin implements IModPlugin {
|
||||
private static final ResourceLocation UID = prefix(HexMod.MOD_ID);
|
||||
|
||||
public static final RecipeType<BrainsweepRecipe> BRAINSWEEPING =
|
||||
RecipeType.create(HexMod.MOD_ID, "brainsweeping", BrainsweepRecipe.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResourceLocation getPluginUid() {
|
||||
return UID;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerCategories(IRecipeCategoryRegistration registration) {
|
||||
registration.addRecipeCategories(new BrainsweepRecipeCategory(registration.getJeiHelpers().getGuiHelper()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRecipes(@NotNull IRecipeRegistration registration) {
|
||||
Level level = Minecraft.getInstance().level;
|
||||
if (level != null) {
|
||||
registration.addRecipes(BRAINSWEEPING, level.getRecipeManager().getAllRecipesFor(HexRecipeSerializers.BRAINSWEEP_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_OAK::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_SPRUCE::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_BIRCH::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_JUNGLE::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_ACACIA::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_DARK_OAK::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_CRIMSON::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_WARPED::get), BRAINSWEEPING);
|
||||
registration.addRecipeCatalyst(new ItemStack(HexItems.WAND_AKASHIC::get), BRAINSWEEPING);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package at.petrak.hexcasting.interop.jei;
|
||||
|
||||
import at.petrak.hexcasting.api.PatternRegistry;
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord;
|
||||
import at.petrak.hexcasting.interop.utils.PatternDrawingUtil;
|
||||
import at.petrak.hexcasting.interop.utils.PatternEntry;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PatternDrawable implements IDrawable {
|
||||
|
||||
private final long startTime = System.currentTimeMillis();
|
||||
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
private final boolean strokeOrder;
|
||||
|
||||
private final List<PatternEntry> patterns;
|
||||
private final List<Vec2> pathfinderDots;
|
||||
|
||||
public PatternDrawable(ResourceLocation pattern, int w, int h) {
|
||||
var entry = PatternRegistry.lookupPattern(pattern);
|
||||
this.strokeOrder = !entry.isPerWorld();
|
||||
var data = PatternDrawingUtil.loadPatterns(List.of(new Pair<>(entry.getPrototype(), HexCoord.getOrigin())));
|
||||
this.patterns = data.patterns();
|
||||
this.pathfinderDots = data.pathfinderDots();
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, int xOffset, int yOffset) {
|
||||
long time = (System.currentTimeMillis() - startTime) / 50;
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(xOffset - 0.5f + width / 2f, yOffset + height / 2f, 0);
|
||||
poseStack.scale(0.25f, 0.25f, 1);
|
||||
PatternDrawingUtil.drawPattern(poseStack, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, time,
|
||||
0xff_333030, 0xff_191818, 0xc8_0c0a0c, 0x80_666363);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
|
@ -1,25 +1,18 @@
|
|||
package at.petrak.hexcasting.interop.patchouli;
|
||||
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.client.RenderLib;
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord;
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import at.petrak.hexcasting.interop.utils.PatternDrawingUtil;
|
||||
import at.petrak.hexcasting.interop.utils.PatternEntry;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import vazkii.patchouli.api.IComponentRenderContext;
|
||||
import vazkii.patchouli.api.ICustomComponent;
|
||||
import vazkii.patchouli.api.IVariable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Page that has a hex pattern on it
|
||||
|
@ -28,7 +21,7 @@ abstract public class AbstractPatternComponent implements ICustomComponent {
|
|||
protected transient int x, y;
|
||||
protected transient float hexSize;
|
||||
|
||||
private transient List<PatternEntryInternal> patterns;
|
||||
private transient List<PatternEntry> patterns;
|
||||
private transient List<Vec2> pathfinderDots;
|
||||
|
||||
/**
|
||||
|
@ -40,119 +33,27 @@ abstract public class AbstractPatternComponent implements ICustomComponent {
|
|||
this.y = y == -1 ? 70 : y;
|
||||
}
|
||||
|
||||
abstract List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup);
|
||||
public abstract List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup);
|
||||
|
||||
abstract boolean showStrokeOrder();
|
||||
public abstract boolean showStrokeOrder();
|
||||
|
||||
@Override
|
||||
public void render(PoseStack poseStack, IComponentRenderContext ctx, float partialTicks, int mouseX, int mouseY) {
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(this.x, this.y, 1);
|
||||
var mat = poseStack.last().pose();
|
||||
var prevShader = RenderSystem.getShader();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
// RenderSystem.disableDepthTest();
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// mark center
|
||||
// RenderLib.drawSpot(mat, Vec2.ZERO, 0f, 0f, 0f, 1f);
|
||||
|
||||
var strokeOrder = this.showStrokeOrder();
|
||||
for (var pat : this.patterns) {
|
||||
var outer = 0xff_d2c8c8;
|
||||
var innerLight = 0xc8_aba2a2;
|
||||
var innerDark = 0xc8_322b33;
|
||||
RenderLib.drawLineSeq(mat, pat.zappyPoints, 5f, 0, outer, outer, null);
|
||||
RenderLib.drawLineSeq(mat, pat.zappyPoints, 2f, 0,
|
||||
strokeOrder ? innerDark : innerLight,
|
||||
innerLight,
|
||||
strokeOrder ? ctx.getTicksInBook() / 20f : null);
|
||||
|
||||
if (strokeOrder) {
|
||||
RenderLib.drawSpot(mat, pat.zappyPoints.get(0), 2.5f, 1f, 0.1f, 0.15f, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
for (var dot : this.pathfinderDots) {
|
||||
RenderLib.drawSpot(mat, dot, 1.5f, 0.82f, 0.8f, 0.8f, 0.5f);
|
||||
}
|
||||
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.setShader(() -> prevShader);
|
||||
|
||||
poseStack.popPose();
|
||||
PatternDrawingUtil.drawPattern(poseStack, this.x, this.y, this.patterns, this.pathfinderDots, this.showStrokeOrder(), ctx.getTicksInBook(),
|
||||
0xff_d2c8c8, 0xc8_aba2a2, 0xc8_322b33, 0x80_d1cccc);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onVariablesAvailable(UnaryOperator<IVariable> lookup) {
|
||||
var patterns = this.getPatterns(lookup);
|
||||
this.patterns = new ArrayList<>(patterns.size());
|
||||
|
||||
// Center the whole thing so the center of all pieces is in the center.
|
||||
// As per PatternTooltipGreeble, we start with a random scale, then re-scale it once we know the COM.
|
||||
var fakeScale = 1;
|
||||
var seenFakePoints = new ArrayList<Vec2>();
|
||||
var seenCoords = new HashSet<HexCoord>();
|
||||
for (var pair : patterns) {
|
||||
var pattern = pair.getFirst();
|
||||
var origin = pair.getSecond();
|
||||
for (var pos : pattern.positions(origin)) {
|
||||
var px = HexUtils.coordToPx(pos, fakeScale, Vec2.ZERO);
|
||||
seenFakePoints.add(px);
|
||||
}
|
||||
|
||||
// And while we're looping add the (COORD ONLY) things internally
|
||||
this.patterns.add(new PatternEntryInternal(pattern, origin, new ArrayList<>()));
|
||||
seenCoords.addAll(pattern.positions(origin));
|
||||
}
|
||||
var fakeCom = HexUtils.FindCenter(seenFakePoints);
|
||||
|
||||
var maxDx = -1f;
|
||||
var maxDy = -1f;
|
||||
for (var dot : seenFakePoints) {
|
||||
var dx = Mth.abs(dot.x - fakeCom.x);
|
||||
if (dx > maxDx) {
|
||||
maxDx = dx;
|
||||
}
|
||||
var dy = Mth.abs(dot.y - fakeCom.y);
|
||||
if (dy > maxDy) {
|
||||
maxDy = dy;
|
||||
}
|
||||
}
|
||||
this.hexSize = Math.min(12, Math.min(120 / 2.5f / maxDx, 70 / 2.5f / maxDy));
|
||||
|
||||
var seenRealPoints = new ArrayList<Vec2>();
|
||||
for (var pat : this.patterns) {
|
||||
for (var pos : pat.pattern.positions(pat.origin)) {
|
||||
var px = HexUtils.coordToPx(pos, this.hexSize, Vec2.ZERO);
|
||||
seenRealPoints.add(px);
|
||||
}
|
||||
}
|
||||
var realCom = HexUtils.FindCenter(seenRealPoints);
|
||||
|
||||
// and NOW for real!
|
||||
for (var pat : this.patterns) {
|
||||
var localOrigin = HexUtils.coordToPx(pat.origin, this.hexSize, realCom.negated());
|
||||
var points = pat.pattern.toLines(this.hexSize, localOrigin);
|
||||
pat.zappyPoints.addAll(RenderLib.makeZappy(points, 10f, 0.8f, 0f));
|
||||
}
|
||||
|
||||
this.pathfinderDots = seenCoords.stream()
|
||||
.map(coord -> HexUtils.coordToPx(coord, this.hexSize, realCom.negated()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private record PatternEntryInternal(HexPattern pattern, HexCoord origin, List<Vec2> zappyPoints) {
|
||||
var data = PatternDrawingUtil.loadPatterns(this.getPatterns(lookup));
|
||||
this.hexSize = data.hexSize();
|
||||
this.patterns = data.patterns();
|
||||
this.pathfinderDots = data.pathfinderDots();
|
||||
}
|
||||
|
||||
protected static class RawPattern {
|
||||
String startdir;
|
||||
String signature;
|
||||
int q, r;
|
||||
|
||||
RawPattern() {
|
||||
}
|
||||
protected String startdir;
|
||||
protected String signature;
|
||||
protected int q, r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.mojang.datafixers.util.Pair;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import vazkii.patchouli.api.IVariable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
|
@ -23,14 +22,14 @@ public class LookupPatternComponent extends AbstractPatternComponent {
|
|||
protected boolean strokeOrder;
|
||||
|
||||
@Override
|
||||
List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup) {
|
||||
public List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup) {
|
||||
var entry = PatternRegistry.lookupPattern(this.opName);
|
||||
this.strokeOrder = !entry.isPerWorld();
|
||||
return Collections.singletonList(new Pair<>(entry.getPrototype(), HexCoord.getOrigin()));
|
||||
return List.of(new Pair<>(entry.getPrototype(), HexCoord.getOrigin()));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean showStrokeOrder() {
|
||||
public boolean showStrokeOrder() {
|
||||
return this.strokeOrder;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public class ManualPatternComponent extends AbstractPatternComponent {
|
|||
protected transient boolean strokeOrder;
|
||||
|
||||
@Override
|
||||
List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup) {
|
||||
public List<Pair<HexPattern, HexCoord>> getPatterns(UnaryOperator<IVariable> lookup) {
|
||||
this.strokeOrder = lookup.apply(IVariable.wrap(this.strokeOrderRaw)).asBoolean(true);
|
||||
var patsRaw = lookup.apply(IVariable.wrap(patternsRaw)).asListOrSingleton();
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class ManualPatternComponent extends AbstractPatternComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean showStrokeOrder() {
|
||||
public boolean showStrokeOrder() {
|
||||
return this.strokeOrder;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package at.petrak.hexcasting.interop.utils;
|
||||
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord;
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern;
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.client.RenderLib;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.util.FastColor;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public final class PatternDrawingUtil {
|
||||
public static void drawPattern(PoseStack poseStack, int x, int y, List<PatternEntry> patterns, List<Vec2> dots, boolean strokeOrder, long animTicks, int outer, int innerLight, int innerDark, int dotColor) {
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(x, y, 1);
|
||||
var mat = poseStack.last().pose();
|
||||
var prevShader = RenderSystem.getShader();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
// RenderSystem.disableDepthTest();
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// mark center
|
||||
// RenderLib.drawSpot(mat, Vec2.ZERO, 0f, 0f, 0f, 1f);
|
||||
|
||||
for (var pat : patterns) {
|
||||
RenderLib.drawLineSeq(mat, pat.zappyPoints(), 5f, 0, outer, outer, null);
|
||||
RenderLib.drawLineSeq(mat, pat.zappyPoints(), 2f, 0,
|
||||
strokeOrder ? innerDark : innerLight,
|
||||
innerLight,
|
||||
strokeOrder ? animTicks / 20f : null);
|
||||
|
||||
if (strokeOrder) {
|
||||
RenderLib.drawSpot(mat, pat.zappyPoints().get(0), 2.5f, 1f, 0.1f, 0.15f, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
float dotR = FastColor.ARGB32.red(dotColor) / 255f;
|
||||
float dotG = FastColor.ARGB32.green(dotColor) / 255f;
|
||||
float dotB = FastColor.ARGB32.blue(dotColor) / 255f;
|
||||
float dotA = FastColor.ARGB32.alpha(dotColor) / 255f;
|
||||
|
||||
for (var dot : dots) {
|
||||
RenderLib.drawSpot(mat, dot, 1.5f, dotR, dotG, dotB, dotA);
|
||||
}
|
||||
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.setShader(() -> prevShader);
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
|
||||
public static PatternRenderingData loadPatterns(List<Pair<HexPattern, HexCoord>> patterns) {
|
||||
var patternEntries = new ArrayList<PatternEntry>(patterns.size());
|
||||
|
||||
var fakeScale = 1;
|
||||
var seenFakePoints = new ArrayList<Vec2>();
|
||||
var seenCoords = new HashSet<HexCoord>();
|
||||
for (var pair : patterns) {
|
||||
var pattern = pair.getFirst();
|
||||
var origin = pair.getSecond();
|
||||
for (var pos : pattern.positions(origin)) {
|
||||
var px = HexUtils.coordToPx(pos, fakeScale, Vec2.ZERO);
|
||||
seenFakePoints.add(px);
|
||||
}
|
||||
|
||||
// And while we're looping add the (COORD ONLY) things internally
|
||||
patternEntries.add(new PatternEntry(pattern, origin, new ArrayList<>()));
|
||||
seenCoords.addAll(pattern.positions(origin));
|
||||
}
|
||||
var fakeCom = HexUtils.FindCenter(seenFakePoints);
|
||||
|
||||
var maxDx = -1f;
|
||||
var maxDy = -1f;
|
||||
for (var dot : seenFakePoints) {
|
||||
var dx = Mth.abs(dot.x - fakeCom.x);
|
||||
if (dx > maxDx) {
|
||||
maxDx = dx;
|
||||
}
|
||||
var dy = Mth.abs(dot.y - fakeCom.y);
|
||||
if (dy > maxDy) {
|
||||
maxDy = dy;
|
||||
}
|
||||
}
|
||||
var hexSize = Math.min(12, Math.min(120 / 2.5f / maxDx, 70 / 2.5f / maxDy));
|
||||
|
||||
var seenRealPoints = new ArrayList<Vec2>();
|
||||
for (var pat : patternEntries) {
|
||||
for (var pos : pat.pattern().positions(pat.origin())) {
|
||||
var px = HexUtils.coordToPx(pos, hexSize, Vec2.ZERO);
|
||||
seenRealPoints.add(px);
|
||||
}
|
||||
}
|
||||
var realCom = HexUtils.FindCenter(seenRealPoints);
|
||||
|
||||
// and NOW for real!
|
||||
for (var pat : patternEntries) {
|
||||
var localOrigin = HexUtils.coordToPx(pat.origin(), hexSize, realCom.negated());
|
||||
var points = pat.pattern().toLines(hexSize, localOrigin);
|
||||
pat.zappyPoints().addAll(RenderLib.makeZappy(points, 10f, 0.8f, 0f));
|
||||
}
|
||||
|
||||
var pathfinderDots = seenCoords.stream()
|
||||
.map(coord -> HexUtils.coordToPx(coord, hexSize, realCom.negated())).toList();
|
||||
|
||||
return new PatternRenderingData(patternEntries, pathfinderDots, hexSize);
|
||||
}
|
||||
|
||||
public record PatternRenderingData(List<PatternEntry> patterns, List<Vec2> pathfinderDots, float hexSize) {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package at.petrak.hexcasting.interop.utils;
|
||||
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord;
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PatternEntry(HexPattern pattern, HexCoord origin, List<Vec2> zappyPoints) {
|
||||
// NO-OP
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in a new issue