diff --git a/src/main/java/gdavid/phi/spell/connector/BridgeConnector.java b/src/main/java/gdavid/phi/spell/connector/BridgeConnector.java index fa8a1dc..7557d28 100644 --- a/src/main/java/gdavid/phi/spell/connector/BridgeConnector.java +++ b/src/main/java/gdavid/phi/spell/connector/BridgeConnector.java @@ -99,6 +99,7 @@ public void drawParams(PoseStack ms, MultiBufferSource buffers, int light) { @OnlyIn(Dist.CLIENT) public void drawLine(PoseStack ms, MultiBufferSource buffers, int light, Side side) { if (!side.isEnabled()) return; + /* TODO fix before 1.19 release GlStateManager._enableBlend(); GlStateManager.glBlendFuncSeparate(SourceFactor.SRC_ALPHA.value, DestFactor.ONE_MINUS_SRC_ALPHA.value, SourceFactor.ZERO.value, SourceFactor.ONE.value); @@ -136,6 +137,7 @@ public void drawLine(PoseStack ms, MultiBufferSource buffers, int light, Side si buffer.vertex(mat, -8, -8, 0).color(r, g, b, a); buffer.uv(minU, minV).uv2(light).endVertex(); GlStateManager._disableBlend(); + */ } @Override diff --git a/src/main/java/gdavid/phi/spell/connector/ClockwiseConnector.java b/src/main/java/gdavid/phi/spell/connector/ClockwiseConnector.java index d1daa31..535c529 100644 --- a/src/main/java/gdavid/phi/spell/connector/ClockwiseConnector.java +++ b/src/main/java/gdavid/phi/spell/connector/ClockwiseConnector.java @@ -1,20 +1,19 @@ package gdavid.phi.spell.connector; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import gdavid.phi.util.EvalHelper; +import gdavid.phi.util.SpellCachedView; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import vazkii.psi.api.spell.EnumPieceType; -import vazkii.psi.api.spell.EnumSpellStat; -import vazkii.psi.api.spell.IGenericRedirector; -import vazkii.psi.api.spell.Spell; -import vazkii.psi.api.spell.SpellCompilationException; -import vazkii.psi.api.spell.SpellContext; -import vazkii.psi.api.spell.SpellMetadata; +import vazkii.psi.api.PsiAPI; +import vazkii.psi.api.spell.*; import vazkii.psi.api.spell.SpellParam.Any; +import vazkii.psi.api.spell.SpellParam.ArrowType; import vazkii.psi.api.spell.SpellParam.Side; -import vazkii.psi.api.spell.SpellPiece; -import vazkii.psi.api.spell.SpellRuntimeException; + +import java.util.*; public class ClockwiseConnector extends SpellPiece implements IGenericRedirector { @@ -42,15 +41,24 @@ public Side reverseSide(Side side) { @Override @OnlyIn(Dist.CLIENT) public void drawParams(PoseStack ms, MultiBufferSource buffers, int light) { - // TODO fix this when there's an API that doesn't require a registered - // SpellParam - /* - * for (SpellParam.Side side : SpellParam.Side.values()) { if (!side.isEnabled() - * || !spell.grid.getPieceAtSideSafely(x, y, - * side).isInputSide(side.getOpposite())) { continue; } RenderHelper.param(ms, - * buffers, light, SpellParam.GRAY, ArrowType.IN, remapSide(side.getOpposite()), - * this); } - */ + VertexConsumer buffer = buffers.getBuffer(PsiAPI.internalHandler.getProgrammerLayer()); + for (Side side : SpellParam.Side.values()) { + if (!isInputSide(side)) continue; + int index = 0, count = 1; + SpellPiece neighbour = spell.grid.getPieceAtSideSafely(x, y, side); + if (neighbour != null) { + int nbcount = neighbour.getParamArrowCount(side.getOpposite()); + if (side.asInt() > side.getOpposite().asInt()) index += nbcount; + count += nbcount; + } + float percent = count > 1 ? (float) index / (count - 1) : 0.5f; + drawParam(ms, buffer, light, side, SpellParam.GRAY, ArrowType.IN, percent); + } + } + + @Override + public int getParamArrowCount(Side side) { + return isInputSide(side) ? 1 : 0; } @Override @@ -78,10 +86,20 @@ public Object execute(SpellContext context) throws SpellRuntimeException { return null; } + // Cache input sides to avoid recalculating them multiple times every frame + private final SpellCachedView> isInputSideView = new SpellCachedView<>(this, () -> { + var res = new HashSet(); + for (Side side : Side.values()) { + if (!side.isEnabled()) continue; + SpellPiece piece = spell.grid.getPieceAtSideSafely(x, y, reverseSide(side).getOpposite()); + if (piece != null && piece.isInputSide(reverseSide(side))) res.add(side); + } + return res; + }, Collections::emptySet); + @Override public boolean isInputSide(Side side) { - // No recursive check to avoid dealing with infinite loops - return spell.grid.getPieceAtSideSafely(x, y, reverseSide(side)) != null; + return isInputSideView.get().contains(side); } } diff --git a/src/main/java/gdavid/phi/util/SpellCachedView.java b/src/main/java/gdavid/phi/util/SpellCachedView.java new file mode 100644 index 0000000..ba66c79 --- /dev/null +++ b/src/main/java/gdavid/phi/util/SpellCachedView.java @@ -0,0 +1,54 @@ +package gdavid.phi.util; + +import org.jetbrains.annotations.NotNull; +import vazkii.psi.api.spell.SpellPiece; + +import java.util.UUID; +import java.util.function.Supplier; + +/** + * Caches a value so it's only computed once for a spell. + * This is useful for things that are expensive to compute but only change when the spell changes, such as loop checks. + */ +public class SpellCachedView { + + private final SpellPiece owner; + private UUID lastSpellUUID = null; + private final Supplier supplier, fallbackSupplier; + private boolean updating = false; + private T value; + + public SpellCachedView(@NotNull SpellPiece owner, @NotNull Supplier supplier) { + this(owner, supplier, () -> { throw new SelfReferentialException(owner); }); + } + + public SpellCachedView(@NotNull SpellPiece owner, @NotNull Supplier supplier, @NotNull Supplier fallbackSupplier) { + this.owner = owner; + this.supplier = supplier; + this.fallbackSupplier = fallbackSupplier; + } + + public T get() throws SelfReferentialException { + if (lastSpellUUID == null || !lastSpellUUID.equals(owner.spell.uuid)) { + // Return a fallback value in case of self-reference + if (updating) return fallbackSupplier.get(); + updating = true; + value = supplier.get(); + lastSpellUUID = owner.spell.uuid; + updating = false; + } + return value; + } + + public static class SelfReferentialException extends IllegalStateException { + + public final SpellPiece piece; + + public SelfReferentialException(SpellPiece owner) { + super("Self-referential SpellCachedView evaluation in " + owner); + piece = owner; + } + + } + +}