JEI plugin!

This commit is contained in:
yrsegal@gmail.com 2022-04-29 22:12:52 -04:00
parent dbf1f9daa1
commit 2af5dd6764
15 changed files with 492 additions and 151 deletions

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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...

View file

@ -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) {

View file

@ -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);

View file

@ -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));
}
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
}
}

View file

@ -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