diff --git a/.gitignore b/.gitignore index 2da9d42dbf..dc8ca90ac5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,10 @@ eclipse run .DS_Store +# Idk what prompted gradle to create this folder +Fabric/Fabric + + # MacOS moment .DS_Store diff --git a/Common/build.gradle b/Common/build.gradle index d5e6128c84..947b7269a9 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -28,6 +28,8 @@ repositories { url = "https://modmaven.dev" } + maven { url "https://maven.shedaniel.me/" } + } dependencies { @@ -37,6 +39,8 @@ dependencies { compileOnly "at.petra-k.paucal:paucal-common-$minecraftVersion:$paucalVersion" compileOnly "vazkii.patchouli:Patchouli-xplat:$minecraftVersion-$patchouliVersion-SNAPSHOT" + compileOnly "com.samsthenerd.inline:inline-forge:$minecraftVersion-$inlineVersion" + compileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion" testCompileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion" diff --git a/Common/src/generated/resources/.cache/e5c5eb35b4ba40351ecb7d9f04c3527f2f5779b0 b/Common/src/generated/resources/.cache/e5c5eb35b4ba40351ecb7d9f04c3527f2f5779b0 index d97c48d9f5..4c5fd592d7 100644 --- a/Common/src/generated/resources/.cache/e5c5eb35b4ba40351ecb7d9f04c3527f2f5779b0 +++ b/Common/src/generated/resources/.cache/e5c5eb35b4ba40351ecb7d9f04c3527f2f5779b0 @@ -1,6 +1,7 @@ -// 1.20.1 2023-12-24T17:59:13.7659226 Advancements +// 1.20.1 2024-10-01T23:18:15.2302045 Advancements 4016b178322c4784c12c66c227d5b4ff2e43d32d data/hexcasting/advancements/aaa_wasteful_cast.json 6469361b24f473b4d7d900828e6bbf2bdabf916b data/hexcasting/advancements/aab_big_cast.json +b4b921ec01322795b41e88406685c3ab7c7d09cc data/hexcasting/advancements/creative_unlocker.json e02605ac2dff5c426e1d0a58d46daefecda11946 data/hexcasting/advancements/enlightenment.json e2679742ac4e23ba4c79c17d209f16d42d7bccd8 data/hexcasting/advancements/lore.json 6c3fc955783d450e12494b193e985a403b203f0a data/hexcasting/advancements/lore/cardamom1.json diff --git a/Common/src/generated/resources/data/hexcasting/advancements/creative_unlocker.json b/Common/src/generated/resources/data/hexcasting/advancements/creative_unlocker.json new file mode 100644 index 0000000000..83470d5f2e --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancements/creative_unlocker.json @@ -0,0 +1,39 @@ +{ + "parent": "hexcasting:root", + "criteria": { + "has_creative_unlocker": { + "conditions": { + "items": [ + { + "items": [ + "hexcasting:creative_unlocker" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + } + }, + "display": { + "announce_to_chat": false, + "background": "minecraft:textures/block/calcite.png", + "description": { + "translate": "advancement.hexcasting:creative_unlocker.desc" + }, + "frame": "task", + "hidden": true, + "icon": { + "item": "hexcasting:creative_unlocker" + }, + "show_toast": true, + "title": { + "translate": "advancement.hexcasting:creative_unlocker" + } + }, + "requirements": [ + [ + "has_creative_unlocker" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java index 94771a57c5..7a9bac13cc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java @@ -148,6 +148,13 @@ public boolean isVecInRangeEnvironment(Vec3 vec) { return this.execState.bounds.contains(vec); } + @Override + public boolean isEnlightened() { + // have unbound circles be enlightened. + if(getCastingEntity() == null) return true; + return super.isEnlightened(); + } + @Override public boolean hasEditPermissionsAtEnvironment(BlockPos pos) { return true; diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java index fe2ee51f45..2a8023cf01 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java @@ -2,13 +2,18 @@ import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; +import com.samsthenerd.inline.api.InlineAPI; +import com.samsthenerd.inline.api.data.EntityInlineData; +import com.samsthenerd.inline.api.data.PlayerHeadData; 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.MutableComponent; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,13 +43,29 @@ public boolean isTruthy() { Tag serialize() { var out = new CompoundTag(); out.putUUID("uuid", this.getEntity().getUUID()); - out.putString("name", Component.Serializer.toJson(this.getEntity().getName())); + out.putString("name", Component.Serializer.toJson(getEntityNameWithInline(true))); return out; } @Override public Component display() { - return this.getEntity().getName().copy().withStyle(ChatFormatting.AQUA); + return getEntityNameWithInline(false).copy().withStyle(ChatFormatting.AQUA); + } + + private Component getEntityNameWithInline(boolean fearSerializer){ + MutableComponent baseName = this.getEntity().getName().copy(); + Component inlineEnt = null; + if(this.getEntity() instanceof Player player){ + inlineEnt = new PlayerHeadData(player.getGameProfile()).asText(!fearSerializer); + inlineEnt = inlineEnt.plainCopy().withStyle(InlineAPI.INSTANCE.withSizeModifier(inlineEnt.getStyle(), 1.5)); + } else{ + if(fearSerializer){ // we don't want to have to serialize an entity just to display it + inlineEnt = EntityInlineData.fromType(this.getEntity().getType()).asText(!fearSerializer); + } else { + inlineEnt = EntityInlineData.fromEntity(this.getEntity()).asText(!fearSerializer); + } + } + return baseName.append(Component.literal(": ")).append(inlineEnt); } public static IotaType TYPE = new IotaType<>() { @@ -73,6 +94,7 @@ public Component display(Tag tag) { return Component.translatable("hexcasting.spelldata.entity.whoknows"); } var nameJson = ctag.getString("name"); +// return Component.literal(nameJson); return Component.Serializer.fromJsonLenient(nameJson).withStyle(ChatFormatting.AQUA); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ListIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ListIota.java index 255d54662f..251c4e161d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ListIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ListIota.java @@ -107,7 +107,10 @@ public Component display(Tag tag) { out.append(IotaType.getDisplay(csub)); - if (i < list.size() - 1) { + // only add a comma between 2 non-patterns (commas don't look good with Inline patterns) + // TODO: maybe add a config? maybe add a method on IotaType to allow it to opt out of commas + if (i < list.size() - 1 && (IotaType.getTypeFromTag(csub) != PatternIota.TYPE + || IotaType.getTypeFromTag(HexUtils.downcast(list.get(i+1), CompoundTag.TYPE)) != PatternIota.TYPE)) { out.append(", "); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java index 6b52868ad6..b86e8541ce 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java @@ -14,17 +14,18 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapEvalTooMuch; import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidPattern; import at.petrak.hexcasting.api.casting.mishaps.MishapUnenlightened; -import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.common.casting.PatternRegistryManifest; import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; +import at.petrak.hexcasting.interop.inline.InlinePatternData; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.NotNull; @@ -163,6 +164,12 @@ public static PatternIota deserialize(Tag tag) throws IllegalArgumentException { } public static Component display(HexPattern pat) { + Component text = (new InlinePatternData(pat)).asText(true); + return text.copy().withStyle(text.getStyle().applyTo(Style.EMPTY.withColor(ChatFormatting.WHITE))); + } + + // keep around just in case it's needed. + public static Component displayNonInline(HexPattern pat){ var bob = new StringBuilder(); bob.append(pat.getStartDir()); @@ -172,7 +179,7 @@ public static Component display(HexPattern pat) { bob.append(sig); } return Component.translatable("hexcasting.tooltip.pattern_iota", - Component.literal(bob.toString()).withStyle(ChatFormatting.WHITE)) - .withStyle(ChatFormatting.GOLD); + Component.literal(bob.toString()).withStyle(ChatFormatting.WHITE)) + .withStyle(ChatFormatting.GOLD); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexDir.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexDir.kt index 514cb0e467..03f4ca5a56 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexDir.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexDir.kt @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.casting.math import at.petrak.hexcasting.api.utils.getSafe +import com.mojang.serialization.Codec enum class HexDir { NORTH_EAST, EAST, SOUTH_EAST, SOUTH_WEST, WEST, NORTH_WEST; @@ -26,6 +27,11 @@ enum class HexDir { } companion object { + val CODEC: Codec = Codec.STRING.xmap( + HexDir::fromString, + HexDir::name + ) + @JvmStatic fun fromString(key: String): HexDir { return values().getSafe(key, WEST) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt index 6b6c587ea0..001cfdeab4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt @@ -4,6 +4,8 @@ import at.petrak.hexcasting.api.utils.NBTBuilder import at.petrak.hexcasting.api.utils.coordToPx import at.petrak.hexcasting.api.utils.findCenter import at.petrak.hexcasting.api.utils.getSafe +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.Tag import net.minecraft.world.phys.Vec2 @@ -127,6 +129,13 @@ data class HexPattern(val startDir: HexDir, val angles: MutableList = const val TAG_START_DIR = "start_dir" const val TAG_ANGLES = "angles" + @JvmField + val CODEC: Codec = RecordCodecBuilder.create({instance -> instance.group( + Codec.STRING.fieldOf(TAG_START_DIR).forGetter(HexPattern::anglesSignature), + HexDir.CODEC.fieldOf(TAG_ANGLES).forGetter(HexPattern::startDir) + ).apply(instance, HexPattern::fromAngles) + }) + @JvmStatic fun isPattern(tag: CompoundTag): Boolean { return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt()) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java index 351acbef7a..d17e617cd9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java @@ -1,7 +1,6 @@ package at.petrak.hexcasting.client.entity; -import at.petrak.hexcasting.client.render.PatternTextureManager; -import at.petrak.hexcasting.client.render.RenderLib; +import at.petrak.hexcasting.client.render.WorldlyPatternRenderHelpers; import at.petrak.hexcasting.common.entities.EntityWallScroll; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -15,13 +14,9 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec2; import org.joml.Matrix3f; import org.joml.Matrix4f; -import java.util.List; - import static at.petrak.hexcasting.api.HexAPI.modLoc; public class WallScrollRenderer extends EntityRenderer { @@ -31,7 +26,6 @@ public class WallScrollRenderer extends EntityRenderer { private static final ResourceLocation ANCIENT_BG_LARGE = modLoc("textures/entity/scroll_ancient_large.png"); private static final ResourceLocation ANCIENT_BG_MEDIUM = modLoc("textures/entity/scroll_ancient_medium.png"); private static final ResourceLocation ANCIENT_BG_SMOL = modLoc("textures/block/ancient_scroll_paper.png"); - private static final ResourceLocation WHITE = modLoc("textures/entity/white.png"); public WallScrollRenderer(EntityRendererProvider.Context p_174008_) { super(p_174008_); @@ -64,7 +58,9 @@ public void render(EntityWallScroll wallScroll, float yaw, float partialTicks, P var mat = last.pose(); var norm = last.normal(); - var verts = bufSource.getBuffer(RenderType.entityCutout(this.getTextureLocation(wallScroll))); + RenderType layer = RenderType.entityCutout(this.getTextureLocation(wallScroll)); + + var verts = bufSource.getBuffer(layer); // Remember: CCW // Front face vertex(mat, norm, light, verts, 0, 0, dz, 0, 0, 0, 0, -1); @@ -99,42 +95,8 @@ public void render(EntityWallScroll wallScroll, float yaw, float partialTicks, P ps.popPose(); - if (PatternTextureManager.useTextures && wallScroll.points != null) - PatternTextureManager.renderPatternForScroll(wallScroll.points.pointsKey, ps, bufSource, light, wallScroll.points.zappyPoints, wallScroll.blockSize, wallScroll.getShowsStrokeOrder()); - } - - //TODO: remove old rendering if not needed anymore for comparison - if (!PatternTextureManager.useTextures && wallScroll.points != null) { - var points = wallScroll.points.zappyPoints; - ps.pushPose(); - - ps.mulPose(Axis.YP.rotationDegrees(180f)); - ps.translate(0, 0, 1.1f / 16f); - // make smaller scrolls not be charlie kirk-sized - // i swear, learning about these functions with asymptotes where slope != 0 is the most useful thing - // I've ever learned in a math class - float unCharlieKirk = Mth.sqrt(wallScroll.blockSize * wallScroll.blockSize + 60); - float scale = 1f / 300f * unCharlieKirk; - ps.scale(scale, scale, 0.01f); - - var last = ps.last(); - var mat = last.pose(); - var norm = last.normal(); - var outer = 0xff_d2c8c8; - var inner = 0xc8_322b33; - var verts = bufSource.getBuffer(RenderType.entityCutout(WHITE)); - theCoolerDrawLineSeq(mat, norm, light, verts, points, wallScroll.blockSize * 5f / 3f, outer); - ps.translate(0, 0, 0.01); - theCoolerDrawLineSeq(mat, norm, light, verts, points, wallScroll.blockSize * 2f / 3f, inner); - - if (wallScroll.getShowsStrokeOrder()) { - ps.translate(0, 0, 0.01); - var spotFrac = 0.8f * wallScroll.blockSize; - theCoolerDrawSpot(mat, norm, light, verts, points.get(0), 2f / 3f * spotFrac, - 0xff_5b7bd7); - } - - ps.popPose(); + if(wallScroll.pattern != null) + WorldlyPatternRenderHelpers.renderPatternForScroll(wallScroll.pattern, wallScroll, ps, bufSource, light, wallScroll.blockSize, wallScroll.getShowsStrokeOrder()); } ps.popPose(); @@ -163,146 +125,12 @@ public ResourceLocation getTextureLocation(EntityWallScroll wallScroll) { } private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, float x, float y, - float z, float u, - float v, float nx, float ny, float nz) { + float z, float u, + float v, float nx, float ny, float nz) { verts.vertex(mat, x, y, z) - .color(0xffffffff) - .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) - .normal(normal, nx, ny, nz) - .endVertex(); - } - - private static void vertexCol(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, int col, Vec2 pos) { - verts.vertex(mat, -pos.x, pos.y, 0) - .color(col) - .uv(0, 0).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) - .normal(normal, 0, 0, 1) - .endVertex(); - } - - private static void theCoolerDrawLineSeq(Matrix4f mat, Matrix3f normalMat, int light, VertexConsumer verts, - List points, float width, int color - ) { - if (points.size() <= 1) { - return; - } - - // TODO: abstract some of this out with RenderLib to stop WET code - var joinAngles = new float[points.size()]; - var joinOffsets = new float[points.size()]; - for (int i = 2; i < points.size(); i++) { - var p0 = points.get(i - 2); - var p1 = points.get(i - 1); - var p2 = points.get(i); - var prev = p1.add(p0.negated()); - var next = p2.add(p1.negated()); - var angle = (float) Mth.atan2( - prev.x * next.y - prev.y * next.x, - prev.x * next.x + prev.y * next.y); - joinAngles[i - 1] = angle; - var clamp = Math.min(prev.length(), next.length()) / (width * 0.5f); - joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp); - } - - for (var i = 0; i < points.size() - 1; i++) { - var p1 = points.get(i); - var p2 = points.get(i + 1); - - var tangent = p2.add(p1.negated()).normalized().scale(width * 0.5f); - var normal = new Vec2(-tangent.y, tangent.x); - - var jlow = joinOffsets[i]; - var jhigh = joinOffsets[i + 1]; - - var p1Down = p1.add(tangent.scale(Math.max(0f, jlow))).add(normal); - var p1Up = p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated()); - var p2Down = p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal); - var p2Up = p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated()); - - // Draw the chamfer hexagon as two trapezoids - // the points are in different orders to keep clockwise - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, p2); - vertexCol(mat, normalMat, light, verts, color, p2Up); - vertexCol(mat, normalMat, light, verts, color, p1Up); - - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, p1Down); - vertexCol(mat, normalMat, light, verts, color, p2Down); - vertexCol(mat, normalMat, light, verts, color, p2); - - if (i > 0) { - var sangle = joinAngles[i]; - var angle = Math.abs(sangle); - var rnormal = normal.negated(); - var joinSteps = Mth.ceil(angle * 180 / (RenderLib.CAP_THETA * Mth.PI)); - if (joinSteps < 1) continue; - - if (sangle < 0) { - var prevVert = new Vec2(p1.x - rnormal.x, p1.y - rnormal.y); - for (var j = 1; j <= joinSteps; j++) { - var fan = RenderLib.rotate(rnormal, -sangle * ((float) j / joinSteps)); - var fanShift = new Vec2(p1.x - fan.x, p1.y - fan.y); - - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, fanShift); - vertexCol(mat, normalMat, light, verts, color, prevVert); - prevVert = fanShift; - } - } else { - var startFan = RenderLib.rotate(normal, -sangle); - var prevVert = new Vec2(p1.x - startFan.x, p1.y - startFan.y); - for (var j = joinSteps - 1; j >= 0; j--) { - var fan = RenderLib.rotate(normal, -sangle * ((float) j / joinSteps)); - var fanShift = new Vec2(p1.x - fan.x, p1.y - fan.y); - - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, p1); - vertexCol(mat, normalMat, light, verts, color, fanShift); - vertexCol(mat, normalMat, light, verts, color, prevVert); - prevVert = fanShift; - } - } - } - } - - for (var pair : new Vec2[][]{ - {points.get(0), points.get(1)}, - {points.get(points.size() - 1), points.get(points.size() - 2)} - }) { - var point = pair[0]; - var prev = pair[1]; - - var tangent = point.add(prev.negated()).normalized().scale(0.5f * width); - var normal = new Vec2(-tangent.y, tangent.x); - var joinSteps = Mth.ceil(180f / RenderLib.CAP_THETA); - for (int j = joinSteps; j > 0; j--) { - var fan0 = RenderLib.rotate(normal, -Mth.PI * ((float) j / joinSteps)); - var fan1 = RenderLib.rotate(normal, -Mth.PI * ((float) (j - 1) / joinSteps)); - - vertexCol(mat, normalMat, light, verts, color, point); - vertexCol(mat, normalMat, light, verts, color, point); - vertexCol(mat, normalMat, light, verts, color, point.add(fan1)); - vertexCol(mat, normalMat, light, verts, color, point.add(fan0)); - } - } - } - - private static void theCoolerDrawSpot(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, - Vec2 point, float radius, int color) { - var fracOfCircle = 6; - for (int i = 0; i < fracOfCircle; i++) { - // We do need rects, irritatingly - // so we do fake triangles - vertexCol(mat, normal, light, verts, color, point); - vertexCol(mat, normal, light, verts, color, point); - for (int j = 0; j <= 1; j++) { - var theta = (i - j) / (float) fracOfCircle * Mth.TWO_PI; - var rx = Mth.cos(theta) * radius + point.x; - var ry = Mth.sin(theta) * radius + point.y; - vertexCol(mat, normal, light, verts, color, new Vec2(rx, ry)); - } - } + .color(0xffffffff) + .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) + .normal(normal, nx, ny, nz) + .endVertex(); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java index 42d768ddda..c6f7da11d8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java @@ -1,24 +1,18 @@ package at.petrak.hexcasting.client.gui; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.client.render.RenderLib; +import at.petrak.hexcasting.client.render.PatternColors; +import at.petrak.hexcasting.client.render.PatternRenderer; +import at.petrak.hexcasting.client.render.WorldlyPatternRenderHelpers; import at.petrak.hexcasting.common.misc.PatternTooltip; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.tooltip.TooltipComponent; -import net.minecraft.world.phys.Vec2; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.stream.Collectors; - import static at.petrak.hexcasting.api.HexAPI.modLoc; // https://github.com/VazkiiMods/Botania/blob/95bd2d3fbc857b7c102687554e1d1b112f8af436/Xplat/src/main/java/vazkii/botania/client/gui/ManaBarTooltipComponent.java @@ -36,23 +30,11 @@ public class PatternTooltipComponent implements ClientTooltipComponent { private static final int TEXTURE_SIZE = 48; private final HexPattern pattern; - private final List zappyPoints; - private final List pathfinderDots; - private final float scale; private final ResourceLocation background; public PatternTooltipComponent(PatternTooltip tt) { this.pattern = tt.pattern(); this.background = tt.background(); - - var pair = RenderLib.getCenteredPattern(pattern, RENDER_SIZE, RENDER_SIZE, 16f); - this.scale = pair.getFirst(); - var dots = pair.getSecond(); - this.zappyPoints = RenderLib.makeZappy( - dots, RenderLib.findDupIndices(pattern.positions()), - 10, 0.8f, 0f, 0f, RenderLib.DEFAULT_READABILITY_OFFSET, RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP, - 0.0); - this.pathfinderDots = dots.stream().distinct().collect(Collectors.toList()); } @Nullable @@ -65,9 +47,6 @@ public static ClientTooltipComponent tryConvert(TooltipComponent cmp) { @Override public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics graphics) { - var width = this.getWidth(font); - var height = this.getHeight(); - var ps = graphics.pose(); // far as i can tell "mouseX" and "mouseY" are actually the positions of the corner of the tooltip @@ -77,28 +56,13 @@ public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics graphics) renderBG(graphics, this.background); // renderText happens *before* renderImage for some asinine reason -// RenderSystem.disableBlend(); ps.translate(0, 0, 100); + ps.scale(RENDER_SIZE, RENDER_SIZE, 1); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - RenderSystem.disableCull(); - RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - ps.translate(width / 2f, height / 2f, 1); - - var mat = ps.last().pose(); - var outer = 0xff_d2c8c8; - var innerLight = 0xc8_aba2a2; - var innerDark = 0xc8_322b33; - RenderLib.drawLineSeq(mat, this.zappyPoints, 6f, 0, - outer, outer); - RenderLib.drawLineSeq(mat, this.zappyPoints, 6f * 0.4f, 0, - innerDark, innerLight); - RenderLib.drawSpot(mat, this.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); - } + PatternRenderer.renderPattern(pattern, ps, WorldlyPatternRenderHelpers.READABLE_SCROLL_SETTINGS, + (PatternRenderer.shouldDoStrokeGradient() ? PatternColors.DEFAULT_GRADIENT_COLOR : PatternColors.DEFAULT_PATTERN_COLOR) + .withDots(true, true), + 0, 512); ps.popPose(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternLike.java b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternLike.java new file mode 100644 index 0000000000..1b82992398 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternLike.java @@ -0,0 +1,70 @@ +package at.petrak.hexcasting.client.render; + +import at.petrak.hexcasting.api.casting.math.HexPattern; +import net.minecraft.world.phys.Vec2; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * A simple wrapper around the parts of HexPattern that are actually used for rendering. + * + * This lets the pattern renderer work on arbitrary lists of vecs - this is never used in base hex but is included + * to future-proof and for if addons or something wants to use it. + */ +public interface HexPatternLike { + List getNonZappyPoints(); + + String getName(); + + Set getDups(); + + static HexPatternLike of(HexPattern pat){ + return new HexPatternLikeBecauseItsActuallyAHexPattern(pat); + } + + static HexPatternLike of(List lines, String name){ + return new PureLines(lines, name); + } + + record HexPatternLikeBecauseItsActuallyAHexPattern(HexPattern pat) implements HexPatternLike{ + public List getNonZappyPoints(){ + return pat.toLines(1, Vec2.ZERO); + } + + public String getName(){ + return pat.getStartDir() + "-" + pat.anglesSignature(); + } + + public Set getDups(){ + return RenderLib.findDupIndices(pat.positions()); + } + } + + record PureLines(List lines, String name) implements HexPatternLike{ + + public List getNonZappyPoints(){ + return lines; + } + + public String getName(){ + return name; + } + + public Set getDups(){ + return RenderLib.findDupIndices( + lines().stream().map(p -> + // I hate mojang + new Vec2(p.x, p.y){ + @Override public boolean equals(Object other){ + if(other instanceof Vec2 otherVec) return p.equals(otherVec); + return false; + } + + @Override public int hashCode(){ return Objects.hash(p.x, p.y); } + }).toList() + ); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java index b033e8de36..1a55d06b5e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java @@ -1,15 +1,134 @@ package at.petrak.hexcasting.client.render; +import com.google.common.collect.ImmutableList; import net.minecraft.world.phys.Vec2; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +/** + * static points making up a hex pattern to be rendered. It's used primarily for positioning, so we keep a + * number of extra values here to avoid recomputing them. + */ public class HexPatternPoints { - public List zappyPoints = null; - public String pointsKey = null; //TODO: if a string key isnt performant enough override hashcode for points + public final ImmutableList zappyPoints; + public final ImmutableList zappyPointsScaled; - public HexPatternPoints(List zappyPoints) { - this.zappyPoints = zappyPoints; - pointsKey = PatternTextureManager.getPointsKey(zappyPoints); + public final ImmutableList dotsScaled; + + public final double rangeX; + public final double rangeY; + public final double finalScale; + + public final double fullWidth; + public final double fullHeight; + + private double minX = Double.MAX_VALUE; + private double minY = Double.MAX_VALUE; + + private final double offsetX; + private final double offsetY; + + private static final ConcurrentMap CACHED_STATIC_POINTS = new ConcurrentHashMap<>(); + + private HexPatternPoints(HexPatternLike patternlike, PatternSettings patSets, double seed) { + + List dots = patternlike.getNonZappyPoints(); + + // always do space calculations with the static version of the pattern + // so that it doesn't jump around resizing itself. + List zappyPoints = RenderLib.makeZappy(dots, patternlike.getDups(), + patSets.getHops(), patSets.getVariance(), 0f, patSets.getFlowIrregular(), + patSets.getReadabilityOffset(), patSets.getLastSegmentProp(), seed); + + + this.zappyPoints = ImmutableList.copyOf(zappyPoints); + double maxY = Double.MIN_VALUE; + double maxX = Double.MIN_VALUE; + for (Vec2 point : zappyPoints) { + minX = Math.min(minX, point.x); + maxX = Math.max(maxX, point.x); + minY = Math.min(minY, point.y); + maxY = Math.max(maxY, point.y); + } + rangeX = maxX - minX; + rangeY = maxY - minY; + + // scales the patterns so that each point is patSets.baseScale units apart + double baseScale = patSets.getBaseScale() / 1.5; + + // size of the pattern in pose space with no other adjustments + double baseWidth = rangeX * baseScale; + double baseHeight = rangeY * baseScale; + + // make sure that the scale fits within our min sizes + double scale = Math.max(1.0, Math.max( + (patSets.getMinWidth() - patSets.getStrokeWidthGuess()) / baseWidth, + (patSets.getMinHeight() - patSets.getStrokeWidthGuess()) / baseHeight) + ); + + boolean vertFit = patSets.getVertAlignment().fit; + boolean horFit = patSets.getHorAlignment().fit; + + // scale down if needed to fit in vertical space + if(vertFit){ + scale = Math.min(scale, (patSets.getTargetHeight() - 2 * patSets.getVertPadding() - patSets.getStrokeWidthGuess())/(baseHeight)); + } + + // scale down if needed to fit in horizontal space + if(horFit){ + scale = Math.min(scale, (patSets.getTargetWidth() - 2 * patSets.getHorPadding() - patSets.getStrokeWidthGuess())/(baseWidth)); + } + + finalScale = baseScale * scale; + double finalStroke = patSets.getStrokeWidth(finalScale); + + double inherentWidth = (baseWidth * scale) + 2 * patSets.getHorPadding() + finalStroke; + double inherentHeight = (baseHeight * scale) + 2 * patSets.getVertPadding() + finalStroke; + + // this is the amount of actual wiggle room we have for configurable position-ing. + double widthDiff = Math.max(patSets.getTargetWidth() - inherentWidth, 0); + double heightDiff = Math.max(patSets.getTargetHeight() - inherentHeight, 0); + + this.fullWidth = inherentWidth + widthDiff; + this.fullHeight = inherentHeight + heightDiff; + + // center in inherent space and put extra space according to alignment stuff + offsetX = ((inherentWidth - baseWidth * scale) / 2) + (widthDiff * patSets.getHorAlignment().amtInFront / 2); + offsetY = ((inherentHeight - baseHeight * scale) / 2) + (heightDiff * patSets.getVertAlignment().amtInFront / 2); + + this.zappyPointsScaled = ImmutableList.copyOf(scaleVecs(zappyPoints)); + this.dotsScaled = ImmutableList.copyOf(scaleVecs(dots)); + } + + public Vec2 scaleVec(Vec2 point){ + return new Vec2( + (float) (((point.x - this.minX) * this.finalScale) + this.offsetX), + (float) (((point.y - this.minY) * this.finalScale) + this.offsetY) + ); + } + + public List scaleVecs(List points){ + List scaledPoints = new ArrayList<>(); + for (Vec2 point : points) { + scaledPoints.add(scaleVec(point)); + } + return scaledPoints; + } + + + /** + * Gets the static points for the given pattern, settings, and seed. This is cached. + * + * This is used in rendering static patterns and positioning non-static patterns. + * + */ + public static HexPatternPoints getStaticPoints(HexPatternLike patternlike, PatternSettings patSets, double seed){ + + String cacheKey = patSets.getCacheKey(patternlike, seed); + + return CACHED_STATIC_POINTS.computeIfAbsent(cacheKey, (key) -> new HexPatternPoints(patternlike, patSets, seed) ); } } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md b/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md new file mode 100644 index 0000000000..fdeb3eb6e1 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md @@ -0,0 +1,52 @@ +# Pattern Rendering Lore + +This is an overview of the new pattern rendering systems introduced alongside the Inline pattern rendering + +## Brief History / Motivations + +In v0.10.3 (and probably before) the pattern rendering was well known for causing lag if many patterns were rendered at once. +The pattern code was also duplicated *a lot*, pretty much anywhere that did pattern rendering needed to do it slightly different and so the rendering/positioning code got copy-pasted all around, frequently with a lot of magic numbers. + +During 1.20 development, we [added texture based rendering](https://github.com/FallingColors/HexMod/pull/555), and switched most static rendering over to it. There was still a fair bit of duplicate code though, especially with pattern positioning. + +Now with the new system, all of the rendering is contained to a few classes and outside users (such as slates for example) can specify how they want patterns to be rendered using PatternSettings and PatternColors. + +## System Walkthrough (External) + +### PatternRenderer + +This is the main entrypoint for pattern rendering. It has 3 main methods, all called `renderPattern`. One is the driver method and the others are convenience wrappers. + +Generally the idea here is that you shouldn't need to worry about whether the pattern will be rendered as a texture or dynamically, the `PatternRenderer` will make that decision, prefering the texture renderer when it can. The dynamic renderer will be used if the pattern is moving (speed != 0), if the pattern has a gradient stroke, or if the texture isn't ready yet. + +### PatternSettings + +This is where the vast majority of the rendering configuration happens. Arguably it is overkill. + +It's a class with many getters constructed from 3 records: `PositionSettings`, `StrokeSettings`, and `ZappySettings`. The getters can be overridden when/if needed, the records are more for user convenience. See javadocs for details on what can be configured here. + +Pattern textures are also generated based on settings, so it's **VERY ENCOURAGED** to re-use pattern settings when you can. + +### PatternColors + +This is just a simple record holding colors for different parts of pattern drawing. It has probably too many helpers. The main thing to note here is that you can set the alpha to 0 to skip rendering a section (such as dots or innerStroke). Transparent colors for strokes are **discouraged** due to the dynamic renderer having a sort of internal overlapping that is only noticeable with transparent strokes. + +### WorldlyPatternRenderHelpers + +This is where all the worldly base-hex renders ended up. Good to look at for examples of using the renderer and some pattern settings that could be re-used. + +## System Walkthrough (Internal) + +### HexPatternPoints + +This is where the positioning actually happens. It generates dots and zappy points based on the pattern and PatternSettings passed in. This object is then cached to prevent needing to calculate it all each frame. Note that this includes scaling and all that, the returned zappy points are in pose units. + +### VCDrawHelper (& RenderLib changes) + +We do a silly with this one lol. This allows us to separate the lower level vertex handling from the higher level 'drawing'. + +Previously `RenderLib.drawLineSeq(..)` drew straight to the tesselator with the `POSITION_COLOR` shader/format. Now it just passes color and position data to the `VCDrawHelper` that we give it, allowing us to create and push a vertex however we want to wherever we want. This lets us draw to other vertex consumers and use other shaders/formats, like the `EntityTranslucentCull` that we use for worldly rendering with light and normals. + +To maintain API stability we have the previous `RenderLib.drawLineSeq(..)` method signature just call the new version using the `Basic` draw helper. + +Conveniently we can also use this for drawing our textures! \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java new file mode 100644 index 0000000000..fb64669834 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java @@ -0,0 +1,68 @@ +package at.petrak.hexcasting.client.render; + +/** + * An immutable wrapper for pattern colors. + *

+ * This is separate from PatternRenderSettings because it does not affect the shape of the pattern, so we can re-use + * those parts for different colors. + */ +public record PatternColors(int innerStartColor, int innerEndColor, int outerStartColor, int outerEndColor, + int startingDotColor, int gridDotsColor){ + + // keep some handy frequently used colors here. + public static final PatternColors DEFAULT_PATTERN_COLOR = new PatternColors(0xff_554d54, 0xff_d2c8c8); + public static final PatternColors DIMMED_COLOR = new PatternColors(0xFF_B4AAAA, 0xff_d2c8c8); + public static final PatternColors DEFAULT_GRADIENT_COLOR = DEFAULT_PATTERN_COLOR.withGradientEnds(DIMMED_COLOR); + + public static final int STARTING_DOT = 0xff_5b7bd7; + public static final int GRID_DOTS = 0x80_d2c8c8; + + public static final PatternColors READABLE_SCROLL_COLORS = DEFAULT_PATTERN_COLOR.withDots(true, false); + public static final PatternColors READABLE_GRID_SCROLL_COLORS = DEFAULT_PATTERN_COLOR.withDots(true, true); + + public static final PatternColors SLATE_WOBBLY_COLOR = glowyStroke( 0xff_64c8ff); // old blue color + public static final PatternColors SLATE_WOBBLY_PURPLE_COLOR = glowyStroke(0xff_cfa0f3); // shiny new purple one :) + + // no gradient + public PatternColors(int innerColor, int outerColor){ + this(innerColor, innerColor, outerColor, outerColor, 0, 0); + } + + // single color -- no inner layer + public static PatternColors singleStroke(int color){ + return new PatternColors(0, color); + } + + // makes a stroke color similar to the glowy effect that slates have. + public static PatternColors glowyStroke(int color){ + return new PatternColors(RenderLib.screenCol(color), color); + } + + public static PatternColors gradientStrokes(int innerStartColor, int innerEndColor, int outerStartColor, int outerEndColor){ + return new PatternColors(innerStartColor, innerEndColor, outerStartColor, outerEndColor, 0, 0); + } + + // a single stroke with a gradient -- no inner layer. + public static PatternColors gradientStroke(int startColor, int endColor){ + return PatternColors.gradientStrokes(0, 0, startColor, endColor); + } + + public PatternColors withGradientEnds(int endColorInner, int endColorOuter){ + return new PatternColors(this.innerStartColor, endColorInner, this.outerStartColor, endColorOuter, this.startingDotColor, this.gridDotsColor); + } + + public PatternColors withGradientEnds(PatternColors end){ + return withGradientEnds(end.innerEndColor, end.outerEndColor); + } + + // add dots -- note, this is how you tell the renderer to make dots + public PatternColors withDotColors(int startingDotColor, int gridDotsColor){ + return new PatternColors(this.innerStartColor, this.innerEndColor, this.outerStartColor, this.outerEndColor, + startingDotColor, gridDotsColor); + } + + // adds dots with the default colors. + public PatternColors withDots(boolean startingDot, boolean gridDots){ + return withDotColors(startingDot ? STARTING_DOT : 0, gridDots ? GRID_DOTS : 0); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternRenderer.java new file mode 100644 index 0000000000..8fd307a9a4 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternRenderer.java @@ -0,0 +1,151 @@ +package at.petrak.hexcasting.client.render; + + +import at.petrak.hexcasting.api.casting.math.HexPattern; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class PatternRenderer { + + public static void renderPattern(HexPattern pattern, PoseStack ps, PatternSettings patSets, PatternColors patColors, double seed, int resPerUnit) { + renderPattern(pattern, ps, null, patSets, patColors, seed, resPerUnit); + } + + public static void renderPattern(HexPattern pattern, PoseStack ps, @Nullable WorldlyBits worldlyBits, PatternSettings patSets, PatternColors patColors, double seed, int resPerUnit) { + renderPattern(HexPatternLike.of(pattern), ps, worldlyBits, patSets, patColors, seed, resPerUnit); + } + + /** + * Renders a pattern (or rather a pattern-like) according to the given settings. + * @param patternlike the pattern (or more generally the lines) to render. + * @param ps pose/matrix stack to render based on. (0,0) is treated as the top left corner. The size of the render is determined by patSets. + * @param worldlyBits used for rendering with light/normals/render-layers if possible. This is optional and probably shouldn't be used for UI rendering. + * @param patSets settings that control how the pattern is drawn. + * @param patColors colors to use for drawing the pattern and dots. + * @param seed seed to use for zappy wobbles. + * @param resPerUnit the texture resolution per pose unit space to be used *if* the texture renderer is used. + */ + public static void renderPattern(HexPatternLike patternlike, PoseStack ps, @Nullable WorldlyBits worldlyBits, PatternSettings patSets, PatternColors patColors, double seed, int resPerUnit){ + var oldShader = RenderSystem.getShader(); + HexPatternPoints staticPoints = HexPatternPoints.getStaticPoints(patternlike, patSets, seed); + + boolean shouldRenderDynamic = true; + + // only do texture rendering if it's static and has solid colors + if(patSets.getSpeed() == 0 && PatternTextureManager.useTextures && patColors.innerStartColor() == patColors.innerEndColor() + && patColors.outerStartColor() == patColors.outerEndColor()){ + boolean didRender = renderPatternTexture(patternlike, ps, worldlyBits, patSets, patColors, seed, resPerUnit); + if(didRender) shouldRenderDynamic = false; + } + if(shouldRenderDynamic){ + List zappyPattern; + + if(patSets.getSpeed() == 0) { + // re-use our static points if we're rendering a static pattern anyway + zappyPattern = staticPoints.zappyPoints; + } else { + List nonzappyLines = patternlike.getNonZappyPoints(); + Set dupIndices = RenderLib.findDupIndices(nonzappyLines); + zappyPattern = RenderLib.makeZappy(nonzappyLines, dupIndices, + patSets.getHops(), patSets.getVariance(), patSets.getSpeed(), patSets.getFlowIrregular(), + patSets.getReadabilityOffset(), patSets.getLastSegmentProp(), seed); + } + + List zappyRenderSpace = staticPoints.scaleVecs(zappyPattern); + + if(FastColor.ARGB32.alpha(patColors.outerEndColor()) != 0 && FastColor.ARGB32.alpha(patColors.outerStartColor()) != 0){ + RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, (float)patSets.getOuterWidth(staticPoints.finalScale), + patColors.outerStartColor(), patColors.outerEndColor(), VCDrawHelper.getHelper(worldlyBits, ps,outerZ)); + } + if(FastColor.ARGB32.alpha(patColors.innerEndColor()) != 0 && FastColor.ARGB32.alpha(patColors.innerStartColor()) != 0) { + RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, (float)patSets.getInnerWidth(staticPoints.finalScale), + patColors.innerStartColor(), patColors.innerEndColor(), VCDrawHelper.getHelper(worldlyBits, ps,innerZ)); + } + } + + // render dots and grid dynamically + + float dotZ = 0.0011f; + + if(FastColor.ARGB32.alpha(patColors.startingDotColor()) != 0) { + RenderLib.drawSpot(ps.last().pose(), staticPoints.dotsScaled.get(0), (float)patSets.getStartDotRadius(staticPoints.finalScale), + patColors.startingDotColor(), VCDrawHelper.getHelper(worldlyBits, ps, dotZ)); + } + + if(FastColor.ARGB32.alpha(patColors.gridDotsColor()) != 0) { + for(int i = 1; i < staticPoints.dotsScaled.size(); i++){ + Vec2 gridDot = staticPoints.dotsScaled.get(i); + RenderLib.drawSpot(ps.last().pose(), gridDot, (float)patSets.getGridDotsRadius(staticPoints.finalScale), + patColors.gridDotsColor(), VCDrawHelper.getHelper(worldlyBits, ps, dotZ)); + } + } + + RenderSystem.setShader(() -> oldShader); + } + + private static final float outerZ = 0.0005f; + private static final float innerZ = 0.001f; + + private static boolean renderPatternTexture(HexPatternLike patternlike, PoseStack ps, @Nullable WorldlyBits worldlyBits, PatternSettings patSets, PatternColors patColors, double seed, int resPerUnit){ + Optional> maybeTextures = PatternTextureManager.getTextures(patternlike, patSets, seed, resPerUnit); + if(maybeTextures.isEmpty()){ + return false; + } + + Map textures = maybeTextures.get(); + HexPatternPoints staticPoints = HexPatternPoints.getStaticPoints(patternlike, patSets, seed); + + VertexConsumer vc; + + if(FastColor.ARGB32.alpha(patColors.outerStartColor()) != 0) { + VCDrawHelper vcHelper = VCDrawHelper.getHelper(worldlyBits, ps, outerZ, textures.get("outer")); + vc = vcHelper.vcSetupAndSupply(VertexFormat.Mode.QUADS); + + int cl = patColors.outerStartColor(); + + vcHelper.vertex(vc, cl, new Vec2(0, 0), new Vec2(0, 0), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2(0, (float) staticPoints.fullHeight), new Vec2(0, 1), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2((float) staticPoints.fullWidth, (float) staticPoints.fullHeight), new Vec2(1, 1), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2((float) staticPoints.fullWidth, 0), new Vec2(1, 0), ps.last().pose()); + + vcHelper.vcEndDrawer(vc); + } + + if(FastColor.ARGB32.alpha(patColors.innerStartColor()) != 0) { + VCDrawHelper vcHelper = VCDrawHelper.getHelper(worldlyBits, ps, innerZ, textures.get("inner")); + vc = vcHelper.vcSetupAndSupply(VertexFormat.Mode.QUADS); + + int cl = patColors.innerStartColor(); + + vcHelper.vertex(vc, cl, new Vec2(0, 0), new Vec2(0, 0), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2(0, (float) staticPoints.fullHeight), new Vec2(0, 1), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2((float) staticPoints.fullWidth, (float) staticPoints.fullHeight), new Vec2(1, 1), ps.last().pose()); + vcHelper.vertex(vc, cl, new Vec2((float) staticPoints.fullWidth, 0), new Vec2(1, 0), ps.last().pose()); + + vcHelper.vcEndDrawer(vc); + } + + return true; + } + + // TODO did we want to un-hardcode this for accessibility reasons ? + public static boolean shouldDoStrokeGradient(){ + return Screen.hasControlDown(); + } + + public record WorldlyBits(@Nullable MultiBufferSource provider, Integer light, Vec3 normal){} +} diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java new file mode 100644 index 0000000000..4cb223f6f6 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java @@ -0,0 +1,142 @@ +package at.petrak.hexcasting.client.render; + +/** + * A class holding settings for shaping and positioning patterns. + * + * By default, it's a simple wrapper of 3 records, however some use cases may require extending and overriding getters. + * This is done to keep the complexity of the records a bit lower. + */ +public class PatternSettings { + + public PatternSettings(String name, PositionSettings posSets, StrokeSettings strokeSets, ZappySettings zapSets){ + this.name = name; + this.posSets = posSets; + this.strokeSets = strokeSets; + this.zapSets = zapSets; + } + + /** + * Settings for positioning the pattern and defining its general size/render area. All values are in 'pose units', + * meaning we use them directly with the pose/matrix stack given to the renderer. + * + *

+ * We do a first pass at the pattern scale using baseScale. We then make sure it's larger than minWidth and + * minHeight. Then on each axis, if that axis is has a FIT alignment then we may scale down the pattern to make sure it + * fits. Note that the padding is not scaled and is always respected. + *

+ */ + public record PositionSettings(double spaceWidth, double spaceHeight, double hPadding, double vPadding, + AxisAlignment hAxis, AxisAlignment vAxis, double baseScale, double minWidth, double minHeight){ + /** + * Makes settings ideal for rendering in a square. This helper exists because this is the most common positioning + * pattern. + * @param padding a value 0-0.5 for how much padding should go on each side. + * @return a PositionSettings object in a 1x1 space with the given padding value such that the pattern is centered + */ + public static PositionSettings paddedSquare(double padding){ + return paddedSquare(padding, 0.25, 0); + } + + public static PositionSettings paddedSquare(double padding, double baseScale, double minSize){ + return new PositionSettings(1.0, 1.0, padding, padding, AxisAlignment.CENTER_FIT, AxisAlignment.CENTER_FIT, baseScale, minSize, minSize); + } + } + + /** + * Settings for stroke and dot sizings. If you want to *not* render dots or inner/outer you should prefer setting + * alpha to 0 in PatternColors. + */ + public record StrokeSettings(double innerWidth, double outerWidth, + double startDotRadius, double gridDotsRadius){ + public static StrokeSettings fromStroke(double stroke){ + return new StrokeSettings(stroke * 2.0/5.0, stroke, 0.8 * stroke * 2.0 / 5.0, 0.4 * stroke * 2.0 / 5.0); + } + } + + /** + * Controls how the pattern is zappified. + * + * @param hops number of little pulses + * @param variance how jumpy/distorting the pulses are + * @param speed how fast the pulses go + * @param flowIrregular randomness of pulse travel + * @param readabilityOffset how curved inward the corners are + * @param lastSegmentLenProportion length of the last segment relative to the others. used for increased readability. + */ + public record ZappySettings(int hops, float variance, float speed, float flowIrregular, float readabilityOffset, float lastSegmentLenProportion){ + public static float READABLE_OFFSET = 0.2f; + public static float READABLE_SEGMENT = 0.8f; + public static ZappySettings STATIC = new ZappySettings(10, 0.5f, 0f, 0.2f, 0, 1f); + public static ZappySettings READABLE = new ZappySettings(10, 0.5f, 0f, 0.2f, READABLE_OFFSET, READABLE_SEGMENT); + public static ZappySettings WOBBLY = new ZappySettings(10, 2.5f, 0.1f, 0.2f, 0, 1f); + } + + public String getCacheKey(HexPatternLike patternlike, double seed){ + return (patternlike.getName() + "-" + getName() + "-" + seed).toLowerCase(); + } + + // determines how the pattern is fit and aligned on a given axis + public enum AxisAlignment{ + // These 3 scale the pattern down to fit if needed. + BEGIN_FIT(true, 0), + CENTER_FIT(true, 1), + END_FIT(true, 2), + // these 3 do *not* scale the pattern down, it will overflow if needed. + BEGIN(false, 0), + CENTER(false, 1), + END(false, 2); + + public final boolean fit; + public final int amtInFront; // how many halves go in front. yes it's a weird way to do it. + + AxisAlignment(boolean fit, int amtInFront){ + this.fit = fit; + this.amtInFront = amtInFront; + } + } + + private final String name; + // leaving these public for more convenient chaining. Should prefer using the getters for overrideability. + public final PositionSettings posSets; + public final StrokeSettings strokeSets; + public final ZappySettings zapSets; + + public String getName(){ return name; } + + public double getTargetWidth(){ return posSets.spaceWidth; } + public double getTargetHeight(){ return posSets.spaceHeight; } + + public double getHorPadding(){ return posSets.hPadding; } + public double getVertPadding(){ return posSets.vPadding; } + + public AxisAlignment getHorAlignment(){ return posSets.hAxis; } + public AxisAlignment getVertAlignment(){ return posSets.vAxis; } + + public double getBaseScale(){ return posSets.baseScale; } + public double getMinWidth(){ return posSets.minWidth; } + public double getMinHeight(){ return posSets.minHeight; } + + /* these sizing getters take in the final pattern scale so that patterns can vary their stroke width when squished. + * the records keep a static value since that's fine for *most* use cases, override these methods if you need to use them. + * note that these widths are still in pose space units. + */ + + public double getInnerWidth(double scale){ return strokeSets.innerWidth; } + public double getOuterWidth(double scale){ return strokeSets.outerWidth; } + + public double getStartDotRadius(double scale){ return strokeSets.startDotRadius; } + public double getGridDotsRadius(double scale){ return strokeSets.gridDotsRadius; } + + public double getStrokeWidth(double scale){ return Math.max(getOuterWidth(scale), getInnerWidth(scale)); } + + // we have a stroke guess getter so that we can *try* to account for the stroke size when fitting the pattern. + public double getStrokeWidthGuess(){ return Math.max(strokeSets.outerWidth, strokeSets.innerWidth); } + + public int getHops(){ return zapSets.hops; } + public float getVariance(){ return zapSets.variance; } + public float getFlowIrregular(){ return zapSets.flowIrregular; } + public float getReadabilityOffset(){ return zapSets.readabilityOffset; } + public float getLastSegmentProp(){ return zapSets.lastSegmentLenProportion; } + + public float getSpeed(){ return zapSets.speed; } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index c28116900f..8486124920 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -1,340 +1,117 @@ package at.petrak.hexcasting.client.render; -import at.petrak.hexcasting.api.block.HexBlockEntity; -import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; -import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf; -import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; -import at.petrak.hexcasting.common.blocks.circles.BlockSlate; import com.mojang.blaze3d.platform.NativeImage; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Axis; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Tuple; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.phys.Vec2; -import org.joml.Matrix3f; -import org.joml.Matrix4f; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.HashMap; import java.util.List; +import java.util.*; import java.util.concurrent.*; -import java.util.stream.Collectors; public class PatternTextureManager { //TODO: remove if not needed anymore for comparison public static boolean useTextures = true; public static int repaintIndex = 0; - public static int resolutionScaler = 4; - public static int fastRenderScaleFactor = 8; // e.g. this is 8, resolution is 1024, so render at 1024/8 = 128 - public static int resolutionByBlockSize = 128 * resolutionScaler; - public static int paddingByBlockSize = 16 * resolutionScaler; - public static int circleRadiusByBlockSize = 2 * resolutionScaler; - public static int scaleLimit = 4 * resolutionScaler; - public static int scrollLineWidth = 3 * resolutionScaler; - public static int otherLineWidth = 4 * resolutionScaler; - - public static void setResolutionScaler(int resolutionScaler) { - PatternTextureManager.resolutionScaler = resolutionScaler; - resolutionByBlockSize = 128 * resolutionScaler; - paddingByBlockSize = 16 * resolutionScaler; - circleRadiusByBlockSize = 2 * resolutionScaler; - scaleLimit = 4 * resolutionScaler; - scrollLineWidth = 3 * resolutionScaler; - otherLineWidth = 4 * resolutionScaler; - } - - private static final ConcurrentMap patternTexturesToAdd = new ConcurrentHashMap<>(); + private static final ConcurrentMap> patternTexturesToAdd = new ConcurrentHashMap<>(); + private static final Set inProgressPatterns = new HashSet<>(); // basically newCachedThreadPool, but with a max pool size private static final ExecutorService executor = new ThreadPoolExecutor(0, 16, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); + private static final HashMap> patternTextures = new HashMap<>(); - private static final HashMap patternTextures = new HashMap<>(); - - public static String getPointsKey(List zappyPoints) - { - return zappyPoints.stream() - .map(p -> String.format("(%f,%f)", p.x, p.y)) - .collect(Collectors.joining(";")); - } - - public static HexPatternPoints generateHexPatternPoints(HexBlockEntity tile, HexPattern pattern, float flowIrregular) - { - var stupidHash = tile.getBlockPos().hashCode(); - var lines1 = pattern.toLines(1, Vec2.ZERO); - var zappyPoints = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(pattern.positions()), - 10, 0.5f, 0f, flowIrregular, 0f, 1f, stupidHash); - return new HexPatternPoints(zappyPoints); - } - - public static void renderPatternForScroll(String pointsKey, PoseStack ps, MultiBufferSource bufSource, int light, List zappyPoints, int blockSize, boolean showStrokeOrder) - { - renderPattern(pointsKey, ps, bufSource, light, zappyPoints, blockSize, showStrokeOrder, false, true, false,false, true,-1); - } - public static void renderPatternForSlate(BlockEntitySlate tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) - { - if(tile.points == null) - tile.points = generateHexPatternPoints(tile, pattern, 0.2f); - - boolean isOnWall = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.WALL; - boolean isOnCeiling = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.CEILING; - int facing = bs.getValue(BlockSlate.FACING).get2DDataValue(); + public static Optional> getTextures(HexPatternLike patternlike, PatternSettings patSets, double seed, int resPerUnit) { + String patCacheKey = patSets.getCacheKey(patternlike, seed) + "_" + resPerUnit; - renderPatternForBlockEntity(tile.points, ps, buffer, light, isOnWall, isOnCeiling, true, facing); - } - public static void renderPatternForAkashicBookshelf(BlockEntityAkashicBookshelf tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) - { - if(tile.points == null) - tile.points = generateHexPatternPoints(tile, pattern, 0f); + // move textures from concurrent map to normal hashmap as needed + if (patternTexturesToAdd.containsKey(patCacheKey)) { + var patternTexture = patternTexturesToAdd.remove(patCacheKey); + var oldPatternTexture = patternTextures.put(patCacheKey, patternTexture); + inProgressPatterns.remove(patCacheKey); + if (oldPatternTexture != null) // TODO: is this needed? when does this ever happen? + for(ResourceLocation oldPatternTextureSingle : oldPatternTexture.values()) + Minecraft.getInstance().getTextureManager().getTexture(oldPatternTextureSingle).close(); - int facing = bs.getValue(BlockAkashicBookshelf.FACING).get2DDataValue(); - renderPatternForBlockEntity(tile.points, ps, buffer, light, true, false, false, facing); - } - - public static void renderPatternForBlockEntity(HexPatternPoints points, PoseStack ps, MultiBufferSource buffer, int light, boolean isOnWall, boolean isOnCeiling, boolean isSlate, int facing) - { - var oldShader = RenderSystem.getShader(); - ps.pushPose(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - renderPattern(points.pointsKey, ps, buffer, light, points.zappyPoints, 1, false, true, isOnWall, isOnCeiling, isSlate, false, facing); - ps.popPose(); - RenderSystem.setShader(() -> oldShader); - } - - public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSource bufSource, int light, List zappyPoints, int blockSize, boolean showStrokeOrder, boolean useFullSize, boolean isOnWall, boolean isOnCeiling, boolean isSlate, boolean isScroll, int facing) - { - ps.pushPose(); - - PoseStack.Pose last = ps.last(); - Matrix4f mat = last.pose(); - Matrix3f normal = last.normal(); - - float x = blockSize, y = blockSize, z = (-1f / 16f) - 0.01f; - float nx = 0, ny = 0, nz = 0; - - //TODO: refactor this mess of a method - - if(isOnWall) - { - if(isScroll) - { - ps.translate(-blockSize / 2f, -blockSize / 2f, 1f / 32f); - nz = -1; - } - else - { - ps.mulPose(Axis.ZP.rotationDegrees(180)); - - if(isSlate) - { - if(facing == 0) - ps.translate(0,-1,0); - if(facing == 1) - ps.translate(-1,-1,0); - if(facing == 2) - ps.translate(-1,-1,1); - if(facing == 3) - ps.translate(0,-1,1); - } - else - { - z = -0.01f; - if(facing == 0) - ps.translate(0,-1,1); - if(facing == 1) - ps.translate(0,-1,0); - if(facing == 2) - ps.translate(-1,-1,0); - if(facing == 3) - ps.translate(-1,-1,1); - } - - if(facing == 0) - ps.mulPose(Axis.YP.rotationDegrees(180)); - if(facing == 1) - ps.mulPose(Axis.YP.rotationDegrees(270)); - if(facing == 3) - ps.mulPose(Axis.YP.rotationDegrees(90)); - - if(facing == 0 || facing == 2) - nz = -1; - if(facing == 1 || facing == 3) - nx = -1; - ps.translate(0,0,0); - } + return Optional.empty(); // try not giving it immediately to avoid flickering? } - else //slates on the floor or ceiling - { - if(facing == 0) - ps.translate(0,0,0); - if(facing == 1) - ps.translate(1,0,0); - if(facing == 2) - ps.translate(1,0,1); - if(facing == 3) - ps.translate(0,0,1); - ps.mulPose(Axis.YP.rotationDegrees(facing*-90)); + if (patternTextures.containsKey(patCacheKey)) + return Optional.of(patternTextures.get(patCacheKey)); - if(isOnCeiling) - { - ps.mulPose(Axis.XP.rotationDegrees(-90)); - ps.translate(0,-1,1); - } - else - ps.mulPose(Axis.XP.rotationDegrees(90)); - nz = -1; + // render a higher-resolution texture in a background thread so it eventually becomes all nice nice and pretty + if(!inProgressPatterns.contains(patCacheKey)){ + inProgressPatterns.add(patCacheKey); + executor.submit(() -> { + var slowTextures = createTextures(patternlike, patSets, seed, resPerUnit); + + // TextureManager#register doesn't look very thread-safe, so move back to the main thread after the slow part is done + Minecraft.getInstance().execute(() -> { + registerTextures(patCacheKey, slowTextures); + }); + }); } - - int lineWidth = otherLineWidth; - int outerColor = 0xff_d2c8c8; - int innerColor = 0xc8_322b33; - if(isScroll) - lineWidth = scrollLineWidth; - - ResourceLocation texture = getTexture(zappyPoints, pointsKey, blockSize, showStrokeOrder, lineWidth, useFullSize, new Color(innerColor), new Color(outerColor)); - VertexConsumer verts = bufSource.getBuffer(RenderType.entityCutout(texture)); - - vertex(mat, normal, light, verts, 0, 0, z, 0, 0, nx, ny, nz); - vertex(mat, normal, light, verts, 0, y, z, 0, 1, nx, ny, nz); - vertex(mat, normal, light, verts, x, y, z, 1, 1, nx, ny, nz); - vertex(mat, normal, light, verts, x, 0, z, 1, 0, nx, ny, nz); - - ps.popPose(); + return Optional.empty(); } - private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, float x, float y, float z, - float u, float v, float nx, float ny, float nz) { - verts.vertex(mat, x, y, z) - .color(0xffffffff) - .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) - .normal(normal, nx, ny, nz) - .endVertex(); - } + private static Map createTextures(HexPatternLike patternlike, PatternSettings patSets, double seed, int resPerUnit) { + HexPatternPoints staticPoints = HexPatternPoints.getStaticPoints(patternlike, patSets, seed); - public static ResourceLocation getTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor) { - if (patternTexturesToAdd.containsKey(pointsKey)) { - var patternTexture = patternTexturesToAdd.remove(pointsKey); - var oldPatternTexture = patternTextures.put(pointsKey, patternTexture); - if (oldPatternTexture != null) - Minecraft.getInstance().getTextureManager().getTexture(oldPatternTexture).close(); + List zappyRenderSpace = staticPoints.scaleVecs(staticPoints.zappyPoints); - return patternTexture; - } - if (patternTextures.containsKey(pointsKey)) - return patternTextures.get(pointsKey); + Map patTexts = new HashMap<>(); - // render a higher-resolution texture in a background thread so it eventually becomes all nice nice and pretty - executor.submit(() -> { - var slowTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, false); + NativeImage innerLines = drawLines(zappyRenderSpace, staticPoints, (float)patSets.getInnerWidth((staticPoints.finalScale)), resPerUnit); + patTexts.put("inner", new DynamicTexture(innerLines)); - // TextureManager#register doesn't look very thread-safe, so move back to the main thread after the slow part is done - Minecraft.getInstance().execute(() -> registerTexture(points, pointsKey, slowTexture, true)); - }); + NativeImage outerLines = drawLines(zappyRenderSpace, staticPoints, (float)patSets.getOuterWidth((staticPoints.finalScale)), resPerUnit); + patTexts.put("outer", new DynamicTexture(outerLines)); - // quickly create and cache a low-resolution texture so the client has something to look at - var fastTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, true); - return registerTexture(points, pointsKey, fastTexture, false); + return patTexts; } - private static DynamicTexture createTexture(List points, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor, boolean fastRender) - { - int resolution = resolutionByBlockSize * blockSize; - int padding = paddingByBlockSize * blockSize; - - if (fastRender) { - resolution /= fastRenderScaleFactor; - padding /= fastRenderScaleFactor; - lineWidth /= (float)fastRenderScaleFactor; + private static Map registerTextures(String patTextureKeyBase, Map dynamicTextures) { + Map resLocs = new HashMap<>(); + for(Map.Entry textureEntry : dynamicTextures.entrySet()){ + String name = "hex_pattern_texture_" + patTextureKeyBase + "_" + textureEntry.getKey() + "_" + repaintIndex + ".png"; + ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register(name, textureEntry.getValue()); + resLocs.put(textureEntry.getKey(), resourceLocation); } + patternTexturesToAdd.put(patTextureKeyBase, resLocs); + return resLocs; + } - double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; - for (Vec2 point : points) - { - minX = Math.min(minX, point.x); - maxX = Math.max(maxX, point.x); - minY = Math.min(minY, point.y); - maxY = Math.max(maxY, point.y); - } - - double rangeX = maxX - minX; - double rangeY = maxY - minY; - - double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); - - double limit = blockSize * scaleLimit; - if (!useFullSize && scale > limit) - scale = limit; - - double offsetX = ((resolution - 2 * padding) - rangeX * scale) / 2; - double offsetY = ((resolution - 2 * padding) - rangeY * scale) / 2; - - BufferedImage img = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_ARGB); + private static NativeImage drawLines(List points, HexPatternPoints staticPoints, float unscaledLineWidth, int resPerUnit) { + BufferedImage img = new BufferedImage((int)(staticPoints.fullWidth*resPerUnit), (int)(staticPoints.fullHeight*resPerUnit), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setColor(outerColor); - g2d.setStroke(new BasicStroke((blockSize * 5f / 3f) * lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - drawLines(g2d, points, minX, minY, scale, offsetX, offsetY, padding); - - g2d.setColor(innerColor); - g2d.setStroke(new BasicStroke((blockSize * 2f / 3f) * lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - drawLines(g2d, points, minX, minY, scale, offsetX, offsetY, padding); - - - if (showsStrokeOrder) { - g2d.setColor(new Color(0xff_d77b5b)); - Tuple point = getTextureCoordinates(points.get(0), minX, minY, scale, offsetX, offsetY, padding); - int spotRadius = circleRadiusByBlockSize * blockSize; - drawHexagon(g2d, point.getA(), point.getB(), spotRadius); + g2d.setColor(new Color(0xFF_FFFFFF)); // set it to white so we can reuse the texture with different colors + g2d.setStroke(new BasicStroke(unscaledLineWidth * resPerUnit, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + for (int i = 0; i < points.size() - 1; i++) { + Tuple pointFrom = getTextureCoordinates(points.get(i), staticPoints, resPerUnit); + Tuple pointTo = getTextureCoordinates(points.get(i+1), staticPoints, resPerUnit); + g2d.drawLine(pointFrom.getA(), pointFrom.getB(), pointTo.getA(), pointTo.getB()); } - g2d.dispose(); - NativeImage nativeImage = new NativeImage(img.getWidth(), img.getHeight(), true); for (int y = 0; y < img.getHeight(); y++) for (int x = 0; x < img.getWidth(); x++) nativeImage.setPixelRGBA(x, y, img.getRGB(x, y)); - - return new DynamicTexture(nativeImage); - } - - private static ResourceLocation registerTexture(List points, String pointsKey, DynamicTexture dynamicTexture, boolean isSlow) { - // isSlow used to register different textures for the low-resolution, fastly rendered version of each texture - // and the high-resolution, slowly rendered version (this means the slow doesn't replace the fast in the texture manager, - // which causes occasional visual stuttering for a frame). - String name = "hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + "_" + (isSlow ? "slow" : "fast") + ".png"; - ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register(name, dynamicTexture); - patternTexturesToAdd.put(pointsKey, resourceLocation); - return resourceLocation; - } - - private static void drawLines(Graphics2D g2d, List points, double minX, double minY, double scale, double offsetX, double offsetY, int padding) { - for (int i = 0; i < points.size() - 1; i++) { - Tuple pointFrom = getTextureCoordinates(points.get(i), minX, minY, scale, offsetX, offsetY, padding); - Tuple pointTo = getTextureCoordinates(points.get(i+1), minX, minY, scale, offsetX, offsetY, padding); - g2d.drawLine(pointFrom.getA(), pointFrom.getB(), pointTo.getA(), pointTo.getB()); - } + return nativeImage; } - private static Tuple getTextureCoordinates(Vec2 point, double minX, double minY, double scale, double offsetX, double offsetY, int padding) { - int x = (int) ((point.x - minX) * scale + offsetX) + padding; - int y = (int) ((point.y - minY) * scale + offsetY) + padding; + private static Tuple getTextureCoordinates(Vec2 point, HexPatternPoints staticPoints, int resPerUnit) { + int x = (int) ( point.x * resPerUnit); + int y = (int) ( point.y * resPerUnit); return new Tuple<>(x, y); } + // keeping this around just in case we ever decide to put the dots in the textures instead of dynamic private static void drawHexagon(Graphics2D g2d, int x, int y, int radius) { int fracOfCircle = 6; Polygon hexagon = new Polygon(); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt b/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt index 38d70fdfa8..823068439f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt @@ -4,7 +4,7 @@ package at.petrak.hexcasting.client.render import at.petrak.hexcasting.api.casting.math.HexPattern import at.petrak.hexcasting.api.mod.HexConfig -import at.petrak.hexcasting.api.utils.* +import at.petrak.hexcasting.api.utils.TAU import at.petrak.hexcasting.client.ClientTickCounter import at.petrak.hexcasting.client.gui.GuiSpellcasting import com.mojang.blaze3d.vertex.DefaultVertexFormat @@ -16,8 +16,8 @@ import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.screens.Screen import net.minecraft.client.renderer.MultiBufferSource -import net.minecraft.core.BlockPos import net.minecraft.util.FastColor +import net.minecraft.util.FastColor.ARGB32 import net.minecraft.util.Mth import net.minecraft.world.entity.Entity import net.minecraft.world.level.Level @@ -42,6 +42,18 @@ const val CAP_THETA = 180f / 10f const val DEFAULT_READABILITY_OFFSET = 0.2f const val DEFAULT_LAST_SEGMENT_LEN_PROP = 0.8f + +fun drawLineSeq( + mat: Matrix4f, + points: List, + width: Float, + z: Float, + tail: Int, + head: Int +) { + return drawLineSeq(mat, points, width, tail, head, VCDrawHelper.Basic(z)) +} + /** * Draw a sequence of linePoints spanning the given points. * @@ -51,9 +63,9 @@ fun drawLineSeq( mat: Matrix4f, points: List, width: Float, - z: Float, tail: Int, head: Int, + vcHelper: VCDrawHelper ) { if (points.size <= 1) return @@ -61,6 +73,7 @@ fun drawLineSeq( val g1 = FastColor.ARGB32.green(tail).toFloat() val b1 = FastColor.ARGB32.blue(tail).toFloat() val a = FastColor.ARGB32.alpha(tail) + val a1 = a.toFloat() val headSource = if (Screen.hasControlDown() != HexConfig.client().ctrlTogglesOffStrokeOrder()) head else @@ -68,10 +81,9 @@ fun drawLineSeq( val r2 = FastColor.ARGB32.red(headSource).toFloat() val g2 = FastColor.ARGB32.green(headSource).toFloat() val b2 = FastColor.ARGB32.blue(headSource).toFloat() + val a2 = FastColor.ARGB32.alpha(headSource).toFloat() - // they spell it wrong at mojang lmao - val tess = Tesselator.getInstance() - val buf = tess.builder + var vc = vcHelper.vcSetupAndSupply(VertexFormat.Mode.TRIANGLES) val n = points.size val joinAngles = FloatArray(n) @@ -90,10 +102,6 @@ fun drawLineSeq( joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp) } - fun vertex(color: BlockPos, pos: Vec2) = - buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() - - buf.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR) for (i in 0 until points.size - 1) { val p1 = points[i] val p2 = points[i + 1] @@ -103,8 +111,9 @@ fun drawLineSeq( val tangent = p2.add(p1.negated()).normalized().scale(width * 0.5f) val normal = Vec2(-tangent.y, tangent.x) - fun color(time: Float): BlockPos = - BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) + fun color(time: Float): Int = + FastColor.ARGB32.color(Mth.lerp(time, a1, a2).toInt(), Mth.lerp(time, r1, r2).toInt(), + Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) val color1 = color(i.toFloat() / n) val color2 = color((i + 1f) / n) @@ -118,21 +127,21 @@ fun drawLineSeq( val p2Down = p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal) val p2Up = p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated()) - vertex(color1, p1Down) - vertex(color1, p1) - vertex(color1, p1Up) + vcHelper.vertex(vc, color1, p1Down, mat) + vcHelper.vertex(vc, color1, p1, mat) + vcHelper.vertex(vc, color1, p1Up, mat) - vertex(color1, p1Down) - vertex(color1, p1Up) - vertex(color2, p2Up) + vcHelper.vertex(vc, color1, p1Down, mat) + vcHelper.vertex(vc, color1, p1Up, mat) + vcHelper.vertex(vc, color2, p2Up, mat) - vertex(color1, p1Down) - vertex(color2, p2Up) - vertex(color2, p2) + vcHelper.vertex(vc, color1, p1Down, mat) + vcHelper.vertex(vc, color2, p2Up, mat) + vcHelper.vertex(vc, color2, p2, mat) - vertex(color1, p1Down) - vertex(color2, p2) - vertex(color2, p2Down) + vcHelper.vertex(vc, color1, p1Down, mat) + vcHelper.vertex(vc, color2, p2, mat) + vcHelper.vertex(vc, color2, p2Down, mat) if (i > 0) { // Draw the connector to the next line segment @@ -150,9 +159,9 @@ fun drawLineSeq( val fan = rotate(rnormal, -sangle * (j.toFloat() / joinSteps)) val fanShift = Vec2(p1.x - fan.x, p1.y - fan.y) - vertex(color1, p1) - vertex(color1, prevVert) - vertex(color1, fanShift) + vcHelper.vertex(vc, color1, p1, mat) + vcHelper.vertex(vc, color1, prevVert, mat) + vcHelper.vertex(vc, color1, fanShift, mat) prevVert = fanShift } } else { @@ -162,32 +171,33 @@ fun drawLineSeq( val fan = rotate(normal, -sangle * (j.toFloat() / joinSteps)) val fanShift = Vec2(p1.x - fan.x, p1.y - fan.y) - vertex(color1, p1) - vertex(color1, prevVert) - vertex(color1, fanShift) + vcHelper.vertex(vc, color1, p1, mat) + vcHelper.vertex(vc, color1, prevVert, mat) + vcHelper.vertex(vc, color1, fanShift, mat) prevVert = fanShift } } } } - tess.end() + vcHelper.vcEndDrawer(vc) - fun drawCaps(color: BlockPos, point: Vec2, prev: Vec2) { + fun drawCaps(color: Int, point: Vec2, prev: Vec2) { val tangent = point.add(prev.negated()).normalized().scale(0.5f * width) val normal = Vec2(-tangent.y, tangent.x) val joinSteps = Mth.ceil(180f / CAP_THETA) - buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR) - vertex(color, point) + vc = vcHelper.vcSetupAndSupply(VertexFormat.Mode.TRIANGLE_FAN) + vcHelper.vertex(vc, color, point, mat) for (j in joinSteps downTo 0) { val fan = rotate(normal, -Mth.PI * (j.toFloat() / joinSteps)) - buf.vertex(mat, point.x + fan.x, point.y + fan.y, z).color(color.x, color.y, color.z, a).endVertex() + vcHelper.vertex(vc, color, Vec2(point.x + fan.x, point.y + fan.y), mat) } - tess.end() + vcHelper.vcEndDrawer(vc) } - drawCaps(BlockPos(r1.toInt(), g1.toInt(), b1.toInt()), points[0], points[1]) - drawCaps(BlockPos(r2.toInt(), g2.toInt(), b2.toInt()), points[n - 1], points[n - 2]) + drawCaps(ARGB32.color(a1.toInt(), r1.toInt(), g1.toInt(), b1.toInt()), points[0], points[1]) + drawCaps(ARGB32.color(a2.toInt(), r2.toInt(), g2.toInt(), b2.toInt()), points[n - 1], points[n - 2]) } + fun rotate(vec: Vec2, theta: Float): Vec2 { val cos = Mth.cos(theta) val sin = Mth.sin(theta) @@ -343,12 +353,12 @@ fun findDupIndices(pts: Iterable): Set { * include primitive drawing code... */ fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: Float, a: Float) { - val tess = Tesselator.getInstance() - val buf = tess.builder - // https://stackoverflow.com/questions/20394727/gl-triangle-strip-vs-gl-triangle-fan - // Starting point is the center - buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR) - buf.vertex(mat, point.x, point.y, 1f).color(r, g, b, a).endVertex() + drawSpot(mat, point, radius, ARGB32.color((a*255).toInt(), (r*255).toInt(), (g*255).toInt(), (b*255).toInt()), VCDrawHelper.Basic(1f)) +} + +fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, color: Int, vcHelper: VCDrawHelper) { + var vc = vcHelper.vcSetupAndSupply(VertexFormat.Mode.TRIANGLE_FAN); + vcHelper.vertex(vc, color, point, mat) // https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L98 // yes they are gonna be little hexagons fite me @@ -358,10 +368,10 @@ fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: F val theta = i.toFloat() / fracOfCircle * TAU.toFloat() val rx = Mth.cos(theta) * radius + point.x val ry = Mth.sin(theta) * radius + point.y - buf.vertex(mat, rx, ry, 1f).color(r, g, b, a).endVertex() + vcHelper.vertex(vc, color, Vec2(rx, ry), mat) } - tess.end() + vcHelper.vcEndDrawer(vc) } fun screenCol(n: Int): Int { diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt b/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt new file mode 100644 index 0000000000..fb6c734e5f --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt @@ -0,0 +1,144 @@ +package at.petrak.hexcasting.client.render + +import at.petrak.hexcasting.api.HexAPI +import at.petrak.hexcasting.client.render.PatternRenderer.WorldlyBits +import com.ibm.icu.impl.CurrencyData.provider +import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.* +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GameRenderer +import net.minecraft.client.renderer.LightTexture +import net.minecraft.client.renderer.MultiBufferSource +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.texture.OverlayTexture +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.phys.Vec2 +import net.minecraft.world.phys.Vec3 +import org.joml.Matrix4f + + +interface VCDrawHelper { + fun vcSetupAndSupply(vertMode: VertexFormat.Mode): VertexConsumer + fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, matrix: Matrix4f){ + vertex(vc, color, pos, Vec2(0f,0f), matrix) + } + fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, uv: Vec2, matrix: Matrix4f) + + fun vcEndDrawer(vc: VertexConsumer) + + companion object { + + @JvmStatic + val WHITE: ResourceLocation = HexAPI.modLoc("textures/entity/white.png") + + @JvmStatic + fun getHelper(worldlyBits: WorldlyBits?, ps: PoseStack, z: Float, texture: ResourceLocation) : VCDrawHelper{ + if(worldlyBits != null){ + return Worldly(worldlyBits, ps, z, texture) + } + return Basic(z, texture) + } + + @JvmStatic + fun getHelper(worldlyBits: WorldlyBits?, ps: PoseStack, z: Float) : VCDrawHelper{ + return getHelper(worldlyBits, ps, z, WHITE) + } + } + + class Basic(val z: Float, val texture: ResourceLocation = WHITE) : VCDrawHelper { + + override fun vcSetupAndSupply(vertMode: VertexFormat.Mode): VertexConsumer{ + val tess = Tesselator.getInstance() + val buf = tess.builder + buf.begin(vertMode, DefaultVertexFormat.POSITION_COLOR_TEX) + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); + RenderSystem.disableCull() + RenderSystem.enableDepthTest() + RenderSystem.enableBlend() + RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA) + RenderSystem.setShaderTexture(0, texture) + return buf + } + override fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, uv: Vec2, matrix: Matrix4f){ + vc.vertex(matrix, pos.x, pos.y, z).color(color).uv(uv.x, uv.y).endVertex() + } + override fun vcEndDrawer(vc: VertexConsumer){ + Tesselator.getInstance().end() + } + } + + class Worldly(val worldlyBits: WorldlyBits, val ps: PoseStack, val z: Float, val texture: ResourceLocation) : VCDrawHelper { + + var lastVertMode: VertexFormat.Mode ?= null // i guess this assumes that the vcHelper is only used once at a time? maybe reconsider that + + override fun vcSetupAndSupply(vertMode: VertexFormat.Mode): VertexConsumer{ + val provider = worldlyBits.provider + if (provider is MultiBufferSource.BufferSource) { + // tells it to draw whatever was here before so that we don't get depth buffer weirdness + provider.endBatch() + } + lastVertMode = vertMode + val buf = Tesselator.getInstance().builder + if(vertMode == VertexFormat.Mode.QUADS){ + val layer = RenderType.entityTranslucentCull(texture) + layer.setupRenderState() + if (provider == null) { + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.NEW_ENTITY) + RenderSystem.setShader { GameRenderer.getRendertypeEntityTranslucentCullShader() } + return buf + } else { + return provider.getBuffer(layer) + } + } + buf.begin( vertMode, DefaultVertexFormat.NEW_ENTITY ) + // Generally this would be handled by a RenderLayer, but that doesn't seem to actually work here,, + RenderSystem.setShaderTexture(0, texture) + RenderSystem.enableDepthTest() + RenderSystem.disableCull() + Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer() + RenderSystem.enableBlend() + RenderSystem.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA ) + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + if (Minecraft.useShaderTransparency()) { + Minecraft.getInstance().levelRenderer.translucentTarget!!.bindWrite(false) + } + RenderSystem.setShader( GameRenderer::getRendertypeEntityTranslucentCullShader ) + return buf + } + + override fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, uv: Vec2, matrix: Matrix4f){ + val nv = worldlyBits.normal?: Vec3(1.0, 1.0, 1.0) + vc.vertex(matrix, pos.x, pos.y, z) + .color(color) + .uv(uv.x, uv.y) + .overlayCoords(OverlayTexture.NO_OVERLAY) + .uv2(worldlyBits.light?: LightTexture.FULL_BRIGHT ) + .normal(ps.last().normal(), nv.x.toFloat(), nv.y.toFloat(), nv.z.toFloat()) + + vc.endVertex() + } + override fun vcEndDrawer(vc: VertexConsumer){ + if(lastVertMode == VertexFormat.Mode.QUADS){ + if (provider == null) { + val layer = RenderType.entityTranslucentCull(texture) + layer.end(Tesselator.getInstance().builder, VertexSorting.ORTHOGRAPHIC_Z) + } + } else { + Tesselator.getInstance().end() + Minecraft.getInstance().gameRenderer.lightTexture().turnOffLightLayer() + RenderSystem.disableBlend() + RenderSystem.defaultBlendFunc() + if (Minecraft.useShaderTransparency()) { + Minecraft.getInstance().mainRenderTarget.bindWrite(false) + } + RenderSystem.enableCull() + } + lastVertMode = null + } + } + + +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java b/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java new file mode 100644 index 0000000000..68c00d5d92 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java @@ -0,0 +1,150 @@ +package at.petrak.hexcasting.client.render; + +import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; +import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf; +import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; +import at.petrak.hexcasting.common.blocks.circles.BlockSlate; +import at.petrak.hexcasting.common.entities.EntityWallScroll; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.Vec3i; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3f; + +import javax.annotation.Nullable; + +/** + * Helper methods for rendering patterns in the world. + */ +public class WorldlyPatternRenderHelpers { + + public static final PatternSettings SCROLL_SETTINGS = new PatternSettings("scroll", + PatternSettings.PositionSettings.paddedSquare(2.0/16), + PatternSettings.StrokeSettings.fromStroke(0.8/16), + PatternSettings.ZappySettings.STATIC + ); + + public static final PatternSettings READABLE_SCROLL_SETTINGS = new PatternSettings("scroll_readable", + PatternSettings.PositionSettings.paddedSquare(2.0/16), + PatternSettings.StrokeSettings.fromStroke(0.8/16), + PatternSettings.ZappySettings.READABLE + ); + + public static final PatternSettings WORLDLY_SETTINGS = new PatternSettings("worldly", + PatternSettings.PositionSettings.paddedSquare(2.0/16), + PatternSettings.StrokeSettings.fromStroke(0.8/16), + PatternSettings.ZappySettings.STATIC + ); + + public static final PatternSettings WORLDLY_SETTINGS_WOBBLY = new PatternSettings("wobbly_world", + PatternSettings.PositionSettings.paddedSquare(2.0/16), + PatternSettings.StrokeSettings.fromStroke(0.8/16), + PatternSettings.ZappySettings.WOBBLY + ); + + public static void renderPatternForScroll(HexPattern pattern, EntityWallScroll scroll, PoseStack ps, MultiBufferSource bufSource, int light, int blockSize, boolean showStrokeOrder) + { + ps.pushPose(); + ps.translate(-blockSize / 2f, -blockSize / 2f, 1f / 32f); + // there's almost certainly a better way to do this, but we're just flipping the y and z axes to fix normals + ps.last().normal().mul(new Matrix3f(1, 0, 0, 0, 0, 1, 0, 1, 0)); + renderPattern(pattern, showStrokeOrder ? READABLE_SCROLL_SETTINGS : SCROLL_SETTINGS, + showStrokeOrder ? PatternColors.READABLE_SCROLL_COLORS : PatternColors.DEFAULT_PATTERN_COLOR, + scroll.getPos().hashCode(), ps, bufSource, null, null, light, blockSize); + ps.popPose(); + } + + private static final int[] WALL_ROTATIONS = {180, 270, 0, 90}; + private static final Vec3i[] SLATE_FACINGS = {new Vec3i(0, -1, 0), new Vec3i(-1, -1, 0), new Vec3i(-1, -1, 1), new Vec3i(0, -1 , 1)}; + private static final Vec3[] WALL_NORMALS = {new Vec3(0, 0, -1), new Vec3(-1, 0, 0), new Vec3(0, 0, -1), new Vec3(-1, 0, 0)}; + private static final Vec3i[] SLATE_FLOORCEIL_FACINGS = {new Vec3i(0,0,0), new Vec3i(1,0,0), new Vec3i(1,0,1), new Vec3i(0,0,1)}; + + public static void renderPatternForSlate(BlockEntitySlate tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) + { + + boolean isOnWall = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.WALL; + boolean isOnCeiling = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.CEILING; + int facing = bs.getValue(BlockSlate.FACING).get2DDataValue(); + + boolean wombly = bs.getValue(BlockSlate.ENERGIZED); + + ps.pushPose(); + + Vec3 normal = null; + if(isOnWall){ + ps.mulPose(Axis.ZP.rotationDegrees(180)); + Vec3i tV = SLATE_FACINGS[facing % 4]; + ps.translate(tV.getX(), tV.getY(), tV.getZ()); + ps.mulPose(Axis.YP.rotationDegrees(WALL_ROTATIONS[facing % 4])); + normal = WALL_NORMALS[facing % 4]; + } else { + Vec3i tV = SLATE_FLOORCEIL_FACINGS[facing % 4]; + ps.translate(tV.getX(), tV.getY(), tV.getZ()); + + ps.mulPose(Axis.YP.rotationDegrees(facing*-90)); + ps.mulPose(Axis.XP.rotationDegrees(90 * (isOnCeiling ? -1 : 1))); + if(isOnCeiling) ps.translate(0,-1,1); + } + + renderPattern(pattern, + wombly ? WORLDLY_SETTINGS_WOBBLY : WORLDLY_SETTINGS, + wombly ? PatternColors.SLATE_WOBBLY_PURPLE_COLOR : PatternColors.DEFAULT_PATTERN_COLOR, + tile.getBlockPos().hashCode(), ps, buffer, normal, null, light, 1); + ps.popPose(); + } + + private static final Vec3i[] BLOCK_FACINGS = {new Vec3i(0, -1, 1), new Vec3i(0, -1, 0), new Vec3i(-1, -1, 0), new Vec3i(-1, -1, 1)}; + + public static void renderPatternForAkashicBookshelf(BlockEntityAkashicBookshelf tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) + { + + int facing = bs.getValue(BlockAkashicBookshelf.FACING).get2DDataValue(); + + ps.pushPose(); + ps.mulPose(Axis.ZP.rotationDegrees(180)); + + Vec3i tV = BLOCK_FACINGS[facing % 4]; + ps.translate(tV.getX(), tV.getY(), tV.getZ()); + ps.mulPose(Axis.YP.rotationDegrees(WALL_ROTATIONS[facing % 4])); + + int actualLight = LevelRenderer.getLightColor(tile.getLevel(), tile.getBlockPos().relative(bs.getValue(BlockAkashicBookshelf.FACING))); + + renderPattern(pattern, WORLDLY_SETTINGS , PatternColors.DEFAULT_PATTERN_COLOR, + tile.getBlockPos().hashCode(), ps, buffer, WALL_NORMALS[facing % 4].multiply(-1, -1, -1), -0.02f, actualLight, 1); + ps.popPose(); + } + + /** + * Renders a pattern in world space based on the given transform requirements + */ + public static void renderPattern(HexPattern pattern, PatternSettings patSets, PatternColors patColors, + double seed, PoseStack ps, MultiBufferSource bufSource, Vec3 normal, @Nullable Float zOffset, + int light, int blockSize) + { + + ps.pushPose(); + + + float z = zOffset != null ? zOffset : ((-1f / 16f) - 0.01f); + + normal = normal != null ? normal : new Vec3(0, 0, -1); + + ps.translate(0,0, z); + ps.scale(blockSize, blockSize, 1); + + + PoseStack noNormalInv = new PoseStack(); + noNormalInv.scale(1, 1, -1); + ps.mulPoseMatrix(noNormalInv.last().pose()); + + PatternRenderer.renderPattern(pattern, ps, new PatternRenderer.WorldlyBits(bufSource, light, normal), + patSets, patColors, seed, blockSize * 512); + + ps.popPose(); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java index e9064fb54c..5bc52dc211 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java @@ -1,21 +1,12 @@ package at.petrak.hexcasting.client.render.be; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.client.render.PatternTextureManager; -import at.petrak.hexcasting.client.render.RenderLib; -import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; +import at.petrak.hexcasting.client.render.WorldlyPatternRenderHelpers; import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Axis; -import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec2; -import org.joml.AxisAngle4f; -import org.joml.Quaternionf; public class BlockEntityAkashicBookshelfRenderer implements BlockEntityRenderer { public BlockEntityAkashicBookshelfRenderer(BlockEntityRendererProvider.Context ctx) { @@ -32,66 +23,6 @@ public void render(BlockEntityAkashicBookshelf tile, float pPartialTick, PoseSta var bs = tile.getBlockState(); - if(PatternTextureManager.useTextures) { - PatternTextureManager.renderPatternForAkashicBookshelf(tile, pattern, ps, buffer, light, bs); - return; - } - - //TODO: remove old rendering if not needed anymore for comparison - - var oldShader = RenderSystem.getShader(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - RenderSystem.enableDepthTest(); - - ps.pushPose(); - - ps.translate(0.5, 0.5, 0.5); - var quarters = (-bs.getValue(BlockAkashicBookshelf.FACING).get2DDataValue()) % 4; - ps.mulPose(Axis.YP.rotation(Mth.HALF_PI * quarters)); - ps.mulPose(Axis.ZP.rotation(Mth.PI)); - - // and now Z is out? - ps.translate(0, 0, 0.5); - ps.scale(1 / 16f, 1 / 16f, 1 / 16f); - ps.translate(0, 0, 0.01); - - // yoink code from the pattern greeble - // Do two passes: one with a random size to find a good COM and one with the real calculation - var com1 = pattern.getCenter(1); - var lines1 = pattern.toLines(1, Vec2.ZERO); - - var maxDx = -1f; - var maxDy = -1f; - for (var dot : lines1) { - var dx = Mth.abs(dot.x - com1.x); - if (dx > maxDx) { - maxDx = dx; - } - var dy = Mth.abs(dot.y - com1.y); - if (dy > maxDy) { - maxDy = dy; - } - } - var scale = Math.min(3.8f, Math.min(16 / 2.5f / maxDx, 16 / 2.5f / maxDy)); - - var com2 = pattern.getCenter(scale); - var lines2 = pattern.toLines(scale, com2.negated()); - // For some reason it is mirrored left to right and i can't seem to posestack-fu it into shape - for (int j = 0; j < lines2.size(); j++) { - var v = lines2.get(j); - lines2.set(j, new Vec2(-v.x, v.y)); - } - - var stupidHash = tile.getBlockPos().hashCode(); - var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10, 0.5f, 0f, 0f, 0f, - 1f, stupidHash); - - int outer = 0xff_d2c8c8; - int inner = 0xc8_322b33; - RenderLib.drawLineSeq(ps.last().pose(), zappy, 1f, 0f, outer, outer); - RenderLib.drawLineSeq(ps.last().pose(), zappy, 0.4f, 0.01f, inner, inner); - - ps.popPose(); - RenderSystem.setShader(() -> oldShader); + WorldlyPatternRenderHelpers.renderPatternForAkashicBookshelf(tile, pattern, ps, buffer, light, bs); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java index 37a40babcd..7fbf43ffc6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java @@ -1,21 +1,11 @@ package at.petrak.hexcasting.client.render.be; -import at.petrak.hexcasting.client.render.PatternTextureManager; -import at.petrak.hexcasting.client.render.RenderLib; +import at.petrak.hexcasting.client.render.WorldlyPatternRenderHelpers; import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; -import at.petrak.hexcasting.common.blocks.circles.BlockSlate; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Axis; -import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.properties.AttachFace; -import net.minecraft.world.phys.Vec2; - -import java.util.ArrayList; public class BlockEntitySlateRenderer implements BlockEntityRenderer { public BlockEntitySlateRenderer(BlockEntityRendererProvider.Context ctx) { @@ -30,94 +20,6 @@ public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, var bs = tile.getBlockState(); - if(PatternTextureManager.useTextures && !bs.getValue(BlockSlate.ENERGIZED)) { - PatternTextureManager.renderPatternForSlate(tile, tile.pattern, ps, buffer, light, bs); - return; - } - - //TODO: remove old rendering if not needed anymore for comparison - - var oldShader = RenderSystem.getShader(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - RenderSystem.enableDepthTest(); - - ps.pushPose(); - - ps.translate(0.5, 0.5, 0.5); - var attchFace = bs.getValue(BlockSlate.ATTACH_FACE); - if (attchFace == AttachFace.WALL) { - var quarters = (-bs.getValue(BlockSlate.FACING).get2DDataValue()) % 4; - ps.mulPose(Axis.YP.rotation(Mth.HALF_PI * quarters)); - ps.mulPose(Axis.ZP.rotation(Mth.PI)); - } else { - var neg = attchFace == AttachFace.FLOOR ? -1 : 1; - ps.mulPose(Axis.XP.rotation(neg * Mth.HALF_PI)); - var quarters = (bs.getValue(BlockSlate.FACING).get2DDataValue() + 2) % 4; - ps.mulPose(Axis.ZP.rotation(neg * Mth.HALF_PI * quarters)); - } - - // Resolution is the number of sub-voxels in the block for rendering purposes, 16 is the default - // padding is the space to leave on the edges free of pattern - var resolution = 16; - var padding = resolution * PatternTextureManager.paddingByBlockSize / PatternTextureManager.resolutionByBlockSize; - - // and now Z is out? - ps.translate(0, 0, -0.5); - ps.scale(1f / resolution, 1f / resolution, 1f / resolution); - ps.translate(0, 0, 1.01); - - var isLit = bs.getValue(BlockSlate.ENERGIZED); - var variance = isLit ? 2.5f : 0.5f; - var speed = isLit ? 0.1f : 0f; - - var lines1 = tile.pattern.toLines(1, Vec2.ZERO); - var stupidHash = tile.getBlockPos().hashCode(); - var zappyPattern = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), - 10, variance, speed, 0.2f, 0f, 1f, stupidHash); - - // always do space calculations with the static version of the pattern - // so that it doesn't jump around resizing itself. - var zappyPatternSpace = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), - 10, 0.5f, 0f, 0.2f, 0f, 1f, stupidHash); - - double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; - for (Vec2 point : zappyPatternSpace) - { - minX = Math.min(minX, point.x); - maxX = Math.max(maxX, point.x); - minY = Math.min(minY, point.y); - maxY = Math.max(maxY, point.y); - } - - double rangeX = maxX - minX; - double rangeY = maxY - minY; - - double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); - - double offsetX = ((- 2 * padding) - rangeX * scale) / 2; - double offsetY = ((- 2 * padding) - rangeY * scale) / 2; - - var zappyRenderSpace = new ArrayList(); - - for (Vec2 point : zappyPattern) { - zappyRenderSpace.add(new Vec2( - (float) (((point.x - minX) * scale + offsetX) + padding), - (float) (((point.y - minY) * scale + offsetY) + padding) - )); - } - - // For some reason it is mirrored left to right and i can't seem to posestack-fu it into shape - for (int i = 0; i < zappyRenderSpace.size(); i++) { - var v = zappyRenderSpace.get(i); - zappyRenderSpace.set(i, new Vec2(-v.x, v.y)); - } - - int outer = isLit ? 0xff_64c8ff : 0xff_d2c8c8; - int inner = isLit ? RenderLib.screenCol(outer) : 0xc8_322b33; - RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, 1f, 0f, outer, outer); - RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, 0.4f, 0.01f, inner, inner); - - ps.popPose(); - RenderSystem.setShader(() -> oldShader); + WorldlyPatternRenderHelpers.renderPatternForSlate(tile, tile.pattern, ps, buffer, light, bs); } } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java index 63489e8c0e..9a0ec965bc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java @@ -2,7 +2,6 @@ import at.petrak.hexcasting.api.block.HexBlockEntity; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.client.render.HexPatternPoints; import at.petrak.hexcasting.common.lib.HexBlockEntities; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -15,7 +14,6 @@ public class BlockEntitySlate extends HexBlockEntity { @Nullable public HexPattern pattern; - public HexPatternPoints points; public BlockEntitySlate(BlockPos pos, BlockState state) { super(HexBlockEntities.SLATE_TILE, pos, state); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java index e653759aef..868f02e2de 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java @@ -1,32 +1,29 @@ package at.petrak.hexcasting.common.command; import at.petrak.hexcasting.client.render.PatternTextureManager; -import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; public class PatternTexturesCommand { public static void add(LiteralArgumentBuilder cmd) { + // TODO: do we want these in release ?? cmd.then(Commands.literal("textureToggle") .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) .executes(ctx -> { PatternTextureManager.useTextures = !PatternTextureManager.useTextures; + String log = (PatternTextureManager.useTextures ? "Enabled" : "Disabled") + " pattern texture rendering. This is meant for debugging."; + ctx.getSource().sendSuccess(() -> Component.literal(log), true); return 1; })); cmd.then(Commands.literal("textureRepaint") .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) .executes(ctx -> { PatternTextureManager.repaint(); + ctx.getSource().sendSuccess(() -> Component.literal("Repainting pattern textures. This is meant for debugging."), true); return 1; })); - cmd.then(Commands.literal("textureSetResolutionScaler") - .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) - .then(Commands.argument("integer", IntegerArgumentType.integer()).executes(ctx -> { - PatternTextureManager.setResolutionScaler(IntegerArgumentType.getInteger(ctx, "integer")); - PatternTextureManager.repaint(); - return 1; - }))); } } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java index cd9ab651cb..03d916c8f7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java @@ -3,8 +3,6 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.api.utils.NBTHelper; -import at.petrak.hexcasting.client.render.HexPatternPoints; -import at.petrak.hexcasting.client.render.RenderLib; import at.petrak.hexcasting.common.items.storage.ItemScroll; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexSounds; @@ -32,12 +30,9 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; -import java.util.List; - public class EntityWallScroll extends HangingEntity { private static final EntityDataAccessor SHOWS_STROKE_ORDER = SynchedEntityData.defineId( EntityWallScroll.class, @@ -48,9 +43,6 @@ public class EntityWallScroll extends HangingEntity { public HexPattern pattern; public boolean isAncient; public int blockSize; - // Client-side only! - @Nullable - public HexPatternPoints points; public EntityWallScroll(EntityType type, Level world) { super(type, world); @@ -72,21 +64,9 @@ public void recalculateDisplay() { CompoundTag patternTag = NBTHelper.getCompound(scroll, ItemScroll.TAG_PATTERN); if (patternTag != null) { this.pattern = HexPattern.fromNBT(patternTag); - if (this.level().isClientSide) { - var pair = RenderLib.getCenteredPattern(pattern, 128f / 3 * blockSize, 128f / 3 * blockSize, - 16f / 3 * blockSize); - var dots = pair.getSecond(); - var readOffset = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f; - var lastProp = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f; - var zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10, 0.4f, - 0f, 0f, readOffset, lastProp, this.getId()); - this.points = new HexPatternPoints(zappyPoints); - } - this.isAncient = NBTHelper.hasString(scroll, ItemScroll.TAG_OP_ID); } else { this.pattern = null; - this.points = null; this.isAncient = false; } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java index 96241ea367..036e5129b4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java @@ -9,6 +9,7 @@ import at.petrak.hexcasting.common.entities.EntityWallScroll; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import at.petrak.hexcasting.common.misc.PatternTooltip; +import at.petrak.hexcasting.interop.inline.InlinePatternData; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -132,7 +133,13 @@ public Component getName(ItemStack pStack) { return Component.translatable(descID + ".of", Component.translatable("hexcasting.action." + ResourceLocation.tryParse(ancientId))); } else if (NBTHelper.hasCompound(pStack, TAG_PATTERN)) { - return Component.translatable(descID); + var compound = NBTHelper.getCompound(pStack, ItemScroll.TAG_PATTERN); + var patternLabel = Component.literal(""); + if (compound != null) { + var pattern = HexPattern.fromNBT(compound); + patternLabel = Component.literal(": ").append(new InlinePatternData(pattern).asText(false)); + } + return Component.translatable(descID).append(patternLabel); } else { return Component.translatable(descID + ".empty"); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java index 6ad6f5b51b..98227d1eab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java @@ -11,6 +11,7 @@ import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import at.petrak.hexcasting.common.misc.PatternTooltip; +import at.petrak.hexcasting.interop.inline.InlinePatternData; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; @@ -38,16 +39,27 @@ public ItemSlate(Block pBlock, Properties pProperties) { @Override public Component getName(ItemStack pStack) { var key = "block." + HexAPI.MOD_ID + ".slate." + (hasPattern(pStack) ? "written" : "blank"); - return Component.translatable(key); + Component patternText = getPattern(pStack) + .map(pat -> Component.literal(": ").append(new InlinePatternData(pat).asText(false))) + .orElse(Component.literal("")); + return Component.translatable(key).append(patternText); } - public static boolean hasPattern(ItemStack stack) { + public static Optional getPattern(ItemStack stack){ var bet = NBTHelper.getCompound(stack, "BlockEntityTag"); - if (bet != null) { - return bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND) && - !bet.getCompound(BlockEntitySlate.TAG_PATTERN).isEmpty(); + + if (bet != null && bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND)) { + var patTag = bet.getCompound(BlockEntitySlate.TAG_PATTERN); + if (!patTag.isEmpty()) { + var pattern = HexPattern.fromNBT(patTag); + return Optional.of(pattern); + } } - return false; + return Optional.empty(); + } + + public static boolean hasPattern(ItemStack stack) { + return getPattern(stack).isPresent(); } @SoftImplement("IForgeItem") @@ -112,15 +124,6 @@ public void writeDatum(ItemStack stack, Iota datum) { @Override public Optional getTooltipImage(ItemStack stack) { - var bet = NBTHelper.getCompound(stack, "BlockEntityTag"); - - if (bet != null && bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND)) { - var patTag = bet.getCompound(BlockEntitySlate.TAG_PATTERN); - if (!patTag.isEmpty()) { - var pattern = HexPattern.fromNBT(patTag); - return Optional.of(new PatternTooltip(pattern, PatternTooltipComponent.SLATE_BG)); - } - } - return Optional.empty(); + return getPattern(stack).map(pat -> new PatternTooltip(pat, PatternTooltipComponent.SLATE_BG)); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java index 28012e0da5..d095b06044 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java @@ -53,6 +53,18 @@ public void generate(HolderLookup.Provider provider, Consumer consu ItemPredicate.Builder.item().of(HexTags.Items.GRANTS_ROOT_ADVANCEMENT).build())) .save(consumer, prefix("root")); // how the hell does one even read this + //Creative Debug Unlocker + Advancement.Builder.advancement() + .display(new DisplayInfo(new ItemStack(HexItems.CREATIVE_UNLOCKER), + Component.translatable("advancement.hexcasting:creative_unlocker"), + Component.translatable("advancement.hexcasting:creative_unlocker.desc"), + new ResourceLocation("minecraft", "textures/block/calcite.png"), + FrameType.TASK, true, false, true)) + .parent(root) + .addCriterion("has_creative_unlocker", InventoryChangeTrigger.TriggerInstance.hasItems( + ItemPredicate.Builder.item().of(HexItems.CREATIVE_UNLOCKER).build())) + .save(consumer, prefix("creative_unlocker")); + // weird names so we have alphabetical parity Advancement.Builder.advancement() .display(simpleDisplay(Items.GLISTERING_MELON_SLICE, "wasteful_cast", FrameType.TASK)) diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java index e6ecbf58db..520df8a48c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java @@ -47,7 +47,7 @@ protected void addTags(HolderLookup.Provider provider) { Items.GLASS_BOTTLE); add(tag(HexTags.Items.GRANTS_ROOT_ADVANCEMENT), HexItems.AMETHYST_DUST, Items.AMETHYST_SHARD, - HexItems.CHARGED_AMETHYST); + HexItems.CHARGED_AMETHYST, HexItems.CREATIVE_UNLOCKER); add(tag(HexTags.Items.SEAL_MATERIALS), Items.HONEYCOMB); diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java b/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java index 79220f4ab9..6ecbc2d40f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java @@ -1,5 +1,7 @@ package at.petrak.hexcasting.interop; +import at.petrak.hexcasting.interop.inline.InlineHex; +import at.petrak.hexcasting.interop.inline.InlineHexClient; import at.petrak.hexcasting.interop.pehkui.PehkuiInterop; import at.petrak.hexcasting.xplat.IClientXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatAbstractions; @@ -30,10 +32,13 @@ public static void init() { } xplat.initPlatformSpecific(); + + InlineHex.init(); } public static void clientInit() { IClientXplatAbstractions.INSTANCE.initPlatformSpecific(); + InlineHexClient.init(); } private static void initPatchouli() { diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/HexPatternMatcher.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/HexPatternMatcher.java new file mode 100644 index 0000000000..55af9756e8 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/HexPatternMatcher.java @@ -0,0 +1,105 @@ +package at.petrak.hexcasting.interop.inline; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.casting.math.HexDir; +import at.petrak.hexcasting.api.casting.math.HexPattern; +import com.samsthenerd.inline.api.InlineAPI; +import com.samsthenerd.inline.api.matching.InlineMatch; +import com.samsthenerd.inline.api.matching.MatchContext; +import com.samsthenerd.inline.api.matching.MatcherInfo; +import com.samsthenerd.inline.api.matching.RegexMatcher; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Tuple; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.MatchResult; +import java.util.regex.Pattern; + +public class HexPatternMatcher implements RegexMatcher { + + private static final ResourceLocation patternMatcherID = HexAPI.modLoc("pattern"); + private static final MatcherInfo patternMatcherInfo = MatcherInfo.fromId(patternMatcherID); + + // thx kyra <3 + private static final Pattern PATTERN_PATTERN_REGEX = Pattern.compile("(?\\\\?)(?:HexPattern)?[<(\\[{]\\s*(?[a-zA-Z_-]+)(?:\\s*(?[,!+:; ])\\s*(?[aqwedsAQWEDS]+)?)\\s*[>)\\]}]", Pattern.CASE_INSENSITIVE); + + public static HexPatternMatcher INSTANCE = new HexPatternMatcher(); + + public Pattern getRegex(){ + return PATTERN_PATTERN_REGEX; + } + + @Override + @NotNull + public Tuple getMatchAndGroup(MatchResult regexMatch, MatchContext ctx) { + String escaped = regexMatch.group(1); + String dirString = regexMatch.group(2).toLowerCase().strip().replace("_", ""); + String sizeModString = regexMatch.group(3); + String angleSigs = regexMatch.group(4); + if(escaped == null){ + return new Tuple<>(new InlineMatch.TextMatch(Component.literal("")), 1); + } + // need to convert dirString to a HexDir + HexDir dir = dirMap.get(dirString); + if(dir == null) + return new Tuple<>(null, 0); + HexPattern pat; + if(angleSigs == null){ + angleSigs = ""; + } + try{ + pat = HexPattern.fromAngles(angleSigs.toLowerCase(), dir); + InlinePatternData patData = new InlinePatternData(pat); + Style patDataStyle = patData.getExtraStyle(); + if(sizeModString != null && sizeModString.equals("+")) + patDataStyle = InlineAPI.INSTANCE.withSizeModifier(patDataStyle, 2); + if(sizeModString != null && sizeModString.equals("!")) + patDataStyle = InlineAPI.INSTANCE.withSizeModifier(patDataStyle, 1.5); + return new Tuple<>(new InlineMatch.DataMatch(patData,patDataStyle ), 0); + } catch (Exception e){ + return new Tuple<>(null, 0); + } + } + + // not really used since we're doing escaping + @Override + @Nullable + public InlineMatch getMatch(MatchResult mr, MatchContext ctx){ + return null; // nop + } + + public MatcherInfo getInfo(){ + return patternMatcherInfo; + } + + /** + * Get the ID for this matcher + * @return matcher's ID + */ + public ResourceLocation getId(){ + return patternMatcherID; + } + + private static final Map dirMap = new HashMap<>(); + + static { + dirMap.put("northwest", HexDir.NORTH_WEST); + dirMap.put("west", HexDir.WEST); + dirMap.put("southwest", HexDir.SOUTH_WEST); + dirMap.put("southeast", HexDir.SOUTH_EAST); + dirMap.put("east", HexDir.EAST); + dirMap.put("northeast", HexDir.NORTH_EAST); + dirMap.put("nw", HexDir.NORTH_WEST); + + dirMap.put("w", HexDir.WEST); + dirMap.put("sw", HexDir.SOUTH_WEST); + dirMap.put("se", HexDir.SOUTH_EAST); + dirMap.put("e", HexDir.EAST); + dirMap.put("ne", HexDir.NORTH_EAST); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHex.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHex.java new file mode 100644 index 0000000000..fa9ce27a93 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHex.java @@ -0,0 +1,9 @@ +package at.petrak.hexcasting.interop.inline; + +import com.samsthenerd.inline.api.InlineAPI; + +public class InlineHex { + public static void init(){ + InlineAPI.INSTANCE.addDataType(InlinePatternData.InlinePatternDataType.INSTANCE); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHexClient.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHexClient.java new file mode 100644 index 0000000000..aa61b7e193 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlineHexClient.java @@ -0,0 +1,11 @@ +package at.petrak.hexcasting.interop.inline; + +import com.samsthenerd.inline.api.client.InlineClientAPI; + +public class InlineHexClient { + + public static void init(){ + InlineClientAPI.INSTANCE.addMatcher(HexPatternMatcher.INSTANCE); + InlineClientAPI.INSTANCE.addRenderer(InlinePatternRenderer.INSTANCE); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java new file mode 100644 index 0000000000..5dc2dba2ff --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java @@ -0,0 +1,89 @@ +package at.petrak.hexcasting.interop.inline; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.casting.PatternShapeMatch; +import at.petrak.hexcasting.api.casting.iota.PatternIota; +import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.common.casting.PatternRegistryManifest; +import at.petrak.hexcasting.common.lib.HexItems; +import com.mojang.serialization.Codec; +import com.samsthenerd.inline.api.InlineData; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class InlinePatternData implements InlineData{ + + public static final ResourceLocation rendererId = HexAPI.modLoc("pattern"); + + @NotNull + public final HexPattern pattern; + + public InlinePatternData(@NotNull HexPattern pattern){ + this.pattern = pattern; + } + + @Override + public InlinePatternDataType getType(){ + return InlinePatternDataType.INSTANCE; + } + + @Override + public ResourceLocation getRendererId(){ + return rendererId; + } + + @Override + public Style getExtraStyle() { + ItemStack scrollStack = new ItemStack(HexItems.SCROLL_MEDIUM); + HexItems.SCROLL_MEDIUM.writeDatum(scrollStack, new PatternIota(pattern)); + scrollStack.setHoverName(getPatternName(pattern).copy().withStyle(ChatFormatting.WHITE)); + HoverEvent he = new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(scrollStack)); + ClickEvent ce = new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, pattern.toString()); + return Style.EMPTY.withHoverEvent(he).withClickEvent(ce); + } + + public static Component getPatternName(HexPattern pattern){ + try { + PatternShapeMatch shapeMatch = PatternRegistryManifest.matchPattern(pattern, null, false); + if(shapeMatch instanceof PatternShapeMatch.Normal normMatch){ + return HexAPI.instance().getActionI18n(normMatch.key, false); + } + // TODO: this doesn't actually ever hit because it errors out with server castinv env stuff first :( + if(shapeMatch instanceof PatternShapeMatch.Special specialMatch){ + return HexAPI.instance().getSpecialHandlerI18n(specialMatch.key); + } + } catch (Exception e){ + // nop + } + return PatternIota.displayNonInline(pattern); + } + + @Override + public Component asText(boolean withExtra) { + return Component.literal(pattern.toString()).withStyle(asStyle(withExtra)); + } + + public static class InlinePatternDataType implements InlineDataType { + private static final ResourceLocation ID = new ResourceLocation(HexAPI.MOD_ID, "pattern"); + public static final InlinePatternDataType INSTANCE = new InlinePatternDataType(); + + @Override + public ResourceLocation getId(){ + return ID; + } + + @Override + public Codec getCodec(){ + return HexPattern.CODEC.xmap( + InlinePatternData::new, + data -> data.pattern + ); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternRenderer.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternRenderer.java new file mode 100644 index 0000000000..eb7b798487 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternRenderer.java @@ -0,0 +1,82 @@ +package at.petrak.hexcasting.interop.inline; + +import at.petrak.hexcasting.client.render.*; +import com.samsthenerd.inline.api.client.GlowHandling; +import com.samsthenerd.inline.api.client.InlineRenderer; +import com.samsthenerd.inline.impl.InlineStyle; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; + +public class InlinePatternRenderer implements InlineRenderer { + + public static final InlinePatternRenderer INSTANCE = new InlinePatternRenderer(); + + public ResourceLocation getId(){ + return InlinePatternData.rendererId; + } + + public static final PatternSettings INLINE_SETTINGS = new PatternSettings("inline", + new PatternSettings.PositionSettings(1.0, 9.0, 0, 0.5, + PatternSettings.AxisAlignment.CENTER, PatternSettings.AxisAlignment.CENTER_FIT, 4.0, 0, 0), + PatternSettings.StrokeSettings.fromStroke(1.0), + new PatternSettings.ZappySettings(10, 0, 0, 0, + PatternSettings.ZappySettings.READABLE_OFFSET, 0.7f) + ){ + @Override + public double getOuterWidth(double scale){ + if(scale >= 1) return 1; + if(scale >= 0.75) return 0.75; + if(scale >= 0.5) return 0.5; + return 0.25; + } + }; + + public static final PatternSettings INLINE_SETTINGS_GLOWY = new PatternSettings("inlineglowy", + new PatternSettings.PositionSettings(1.0, 11.0, 0, 0.5, + PatternSettings.AxisAlignment.CENTER, PatternSettings.AxisAlignment.CENTER_FIT, 4.0, 0, 0), + new PatternSettings.StrokeSettings(1, 3, 0.8 * 1 * 2.0 / 5.0, 0.4 * 1 * 2.0 / 5.0), + INLINE_SETTINGS.zapSets + ){ + @Override + public double getInnerWidth(double scale){ + if(scale >= 1) return 1; + if(scale >= 0.75) return 0.75; + if(scale >= 0.5) return 0.5; + return 0.25; + } + }; + + @Override + public GlowHandling getGlowPreference(InlinePatternData forData) { + return new GlowHandling.None(); + } + + public static final int INLINE_TEXTURE_RES = 16; // 128px so it looks good and pretty on up close signs and whatnot + + public int render(InlinePatternData data, GuiGraphics drawContext, int index, Style style, int codepoint, TextRenderingContext trContext){ + if(trContext.isGlowy()) return charWidth(data, style, codepoint); + int glowyParentColor = ((InlineStyle) style).getComponent(InlineStyle.GLOWY_PARENT_COMP); + boolean isGlowy = glowyParentColor != -1; + drawContext.pose().pushPose(); + drawContext.pose().translate(isGlowy ? -1f : 0, isGlowy ? -1.5f : -0.5f, 0f); + int color = trContext.usableColor(); + PatternRenderer.renderPattern(data.pattern, drawContext.pose(), new PatternRenderer.WorldlyBits(drawContext.bufferSource(), trContext.light(), null), + isGlowy ? INLINE_SETTINGS_GLOWY : INLINE_SETTINGS, + isGlowy ? new PatternColors(color, 0xFF_000000 | glowyParentColor) : PatternColors.singleStroke(color), + 0, INLINE_TEXTURE_RES); + + drawContext.pose().popPose(); + return charWidth(data, style, codepoint); + } + + public int charWidth(InlinePatternData data, Style style, int codepoint){ + + HexPatternPoints staticPoints = HexPatternPoints.getStaticPoints(HexPatternLike.of(data.pattern), INLINE_SETTINGS, 0); + + double baseScale = 4.0 / 1.5; + double baseHeight = staticPoints.rangeY * baseScale; + + return (int)Math.ceil(Math.min(baseHeight, 8.0) * staticPoints.rangeX / staticPoints.rangeY) + 1; // (+2 for padding) + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java index 4165756417..997bb09411 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java @@ -1,14 +1,11 @@ package at.petrak.hexcasting.interop.patchouli; -import at.petrak.hexcasting.api.casting.math.HexCoord; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.client.render.RenderLib; -import at.petrak.hexcasting.interop.utils.PatternDrawingUtil; -import at.petrak.hexcasting.interop.utils.PatternEntry; +import at.petrak.hexcasting.client.render.PatternColors; +import at.petrak.hexcasting.client.render.PatternRenderer; +import at.petrak.hexcasting.client.render.PatternSettings; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.world.phys.Vec2; import vazkii.patchouli.api.IComponentRenderContext; import vazkii.patchouli.api.ICustomComponent; import vazkii.patchouli.api.IVariable; @@ -23,8 +20,7 @@ abstract public class AbstractPatternComponent implements ICustomComponent { protected transient int x, y; protected transient float hexSize; - private transient List patterns; - private transient List zappyPoints; + private transient List patterns; /** * Pass -1, -1 to center it. @@ -35,29 +31,57 @@ public void build(int x, int y, int pagenum) { this.y = y == -1 ? 70 : y; } - public abstract List> getPatterns(UnaryOperator lookup); + public abstract List getPatterns(UnaryOperator lookup); public abstract boolean showStrokeOrder(); @Override public void render(GuiGraphics graphics, IComponentRenderContext context, float pticks, int mouseX, int mouseY) { - PatternDrawingUtil.drawPattern(graphics, this.x, this.y, this.patterns, this.zappyPoints, - this.showStrokeOrder(), - 0xff_d2c8c8, 0xc8_aba2a2, 0xc8_322b33, 0x80_d1cccc); + PoseStack ps = graphics.pose(); + // want to position x: [0, 116], y: [16, 80] + ps.pushPose(); + + int cols = (int)Math.ceil(Math.sqrt(patterns.size())); + int rows = (int)Math.ceil(patterns.size()/(double)cols); + + double cellW = 116 / (double)cols; + double cellH = 64 / (double)rows; + + PatternSettings patSets = new PatternSettings("book" + patterns.size() + (showStrokeOrder() ? "" : "r"), + new PatternSettings.PositionSettings(cellW, cellH, 2, 2, + PatternSettings.AxisAlignment.CENTER_FIT, PatternSettings.AxisAlignment.CENTER_FIT, 16, 0, 0), + PatternSettings.StrokeSettings.fromStroke(4), + showStrokeOrder() ? PatternSettings.ZappySettings.READABLE : PatternSettings.ZappySettings.STATIC + ); + + PatternColors patCols = PatternColors.DIMMED_COLOR.withDots(false, true); + + if(showStrokeOrder()){ + patCols = PatternRenderer.shouldDoStrokeGradient() ? PatternColors.DEFAULT_GRADIENT_COLOR.withDots(true, true) + : PatternColors.READABLE_GRID_SCROLL_COLORS; + } + + for(int p = 0; p < patterns.size(); p++){ + + int r = p / cols; + int c = p % cols; + HexPattern pattern = patterns.get(p); + + ps.pushPose(); + ps.translate(cellW * c, cellH * r + 16, 100); + + PatternRenderer.renderPattern(pattern, graphics.pose(), patSets, patCols, 0, 4); + ps.popPose(); + } + ps.popPose(); } @Override public void onVariablesAvailable(UnaryOperator lookup) { - var patterns = this.getPatterns(lookup); - var data = PatternDrawingUtil.loadPatterns( - patterns, - this.showStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f, - this.showStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f); - this.hexSize = data.hexSize(); - this.patterns = data.patterns(); - this.zappyPoints = data.pathfinderDots(); + this.patterns = this.getPatterns(lookup); } + // used for deserialization from patchi protected static class RawPattern { protected String startdir; protected String signature; diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java index 7f5517b361..632c7abf79 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java @@ -1,11 +1,9 @@ package at.petrak.hexcasting.interop.patchouli; -import at.petrak.hexcasting.api.casting.math.HexCoord; import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.xplat.IXplatAbstractions; import com.google.gson.annotations.SerializedName; -import com.mojang.datafixers.util.Pair; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import vazkii.patchouli.api.IVariable; @@ -24,13 +22,13 @@ public class LookupPatternComponent extends AbstractPatternComponent { protected boolean strokeOrder; @Override - public List> getPatterns(UnaryOperator lookup) { + public List getPatterns(UnaryOperator lookup) { var key = ResourceKey.create(IXplatAbstractions.INSTANCE.getActionRegistry().key(), this.opName); var entry = IXplatAbstractions.INSTANCE.getActionRegistry().get(key); this.strokeOrder = !IXplatAbstractions.INSTANCE.getActionRegistry().getHolderOrThrow(key).is(HexTags.Actions.PER_WORLD_PATTERN); - return List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin())); + return List.of(entry.prototype()); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java index f03946384c..06f77903ba 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java @@ -1,12 +1,10 @@ package at.petrak.hexcasting.interop.patchouli; -import at.petrak.hexcasting.api.casting.math.HexCoord; import at.petrak.hexcasting.api.casting.math.HexDir; import at.petrak.hexcasting.api.casting.math.HexPattern; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; -import com.mojang.datafixers.util.Pair; import vazkii.patchouli.api.IVariable; import java.util.ArrayList; @@ -25,19 +23,18 @@ public class ManualPatternComponent extends AbstractPatternComponent { protected transient boolean strokeOrder; @Override - public List> getPatterns(UnaryOperator lookup) { + public List getPatterns(UnaryOperator lookup) { this.strokeOrder = lookup.apply(IVariable.wrap(this.strokeOrderRaw)).asBoolean(true); var patsRaw = lookup.apply(IVariable.wrap(patternsRaw)).asListOrSingleton(); - var out = new ArrayList>(); + var out = new ArrayList(); for (var ivar : patsRaw) { JsonElement json = ivar.unwrap(); RawPattern raw = new Gson().fromJson(json, RawPattern.class); var dir = HexDir.fromString(raw.startdir); var pat = HexPattern.fromAngles(raw.signature, dir); - var origin = new HexCoord(raw.q, raw.r); - out.add(new Pair<>(pat, origin)); + out.add(pat); } return out; diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index dfdc98cdd0..bb94438ab0 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -353,6 +353,10 @@ "": "Hexcasting Research", desc: "Find and mine a concentrated form of media growing deep beneath the earth.", }, + creative_unlocker:{ + "": "UNLIMITED POWAH", + "desc": "Found the creative debug item." + }, enlightenment: { "": "Achieve Enlightenment", desc: "Shatter a barrier by casting a hex using almost all of your health.", @@ -433,7 +437,15 @@ "fail.already": "%s is already empty", }, }, - + + // === Inline ! === + "matcher.hexcasting.pattern": { + "title": "Hex Pattern", + "title.styled": "Hex Pattern ", + "description": "Visual Hex Casting Patterns", + "example": "" + }, + hexcasting: { "pattern.unknown": "Unknown pattern resource location %s", @@ -1051,7 +1063,7 @@ "": "Cross-Mod Compatibility", desc: "It appears I have installed some mods Hexcasting interoperates with! I've detailed them here.", }, - + patterns: { "": "Patterns", desc: "A list of all the patterns I've discovered, as well as what they do.", @@ -1067,11 +1079,16 @@ It's probably just the ramblings of extinct traditionalists, though -- a pattern's a pattern.$(br2)\ What could possibly go wrong?", }, + creative_unlocker: { + "": "The Media Cube", + desc: "I have found a source of near limitless power, The Media Cube.", + } }, // ^ categories entry: { media: "Media", + media_cube: "The Media Cube", geodes: "Geodes", couldnt_cast: "A Frustration", start_to_see: "WHAT DID I SEE", @@ -1169,6 +1186,13 @@ // ^ entries page: { + creative_unlocker: { + "1": "The $(#74b3f2)Media Cube/$ is a near-limitless source of power, acting as an infinite source of _media for whatever _Hexes I wish to cast. It also looks quite tasty. Eating it might perhaps reveal more about the world, possibly delving into spoiler territory...", + "2": "Additionally, it seems that by renaming a $(#74b3f2)Media Cube/$ at an Anvil, I should be able to utilize it to test and understand more about my _Hexes. If I have somehow acquired Creative power over the world, I might wish to turn that off before attempting any of the following.", + "3": "By renaming the $(#74b3f2)Media Cube/$ to 'debug media', I will be given feedback in the chat window about the amount of media consumed.", + // NOTE: The following feature documented is broken in the current implementation. It should be uncommented and the page in patchouli should be updated when the feature is fixed. + //"4": "By renaming the $(#74b3f2)Media Cube/$ to 'debug patterns', I will be given feedback in the chat window about the order patterns are ran." + }, media: { "1": "_Media is a form of mental energy external to a mind. All living creatures generate trace amounts of _media when thinking about anything; after the thought is finished, the media is released into the environment.$(br2)The art of casting _Hexes is all about manipulating _media to do your bidding.", "2": "_Media can exert influences on other media-- the strength and type of influence can be manipulated by drawing _media out into patterns.$(p)Scholars of the art used a concentrated blob of _media on the end of a stick: by waving it in the air in precise configurations, they were able to manipulate enough _media with enough precision to influence the world itself, in the form of a _Hex.", @@ -1624,7 +1648,7 @@ numlist: "Set operations are odd, in that some of them can accept two numbers or two lists, but not a combination thereof. Such arguments will be written as \"(num, num)|(list, list)\".$(br2)When numbers are used in those operations, they are being used as so-called binary \"bitsets\", lists of 1 and 0, true and false, \"on\" and \"off\".", "or.1": "Unifies two sets.", - "or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to $(l:patterns/lists#hexcasting:add)$(action)Combination Distillation/$.", + "or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is somewhat similar to $(l:patterns/lists#hexcasting:add)$(action)Additive Distillation/$.", "and.1": "Takes the intersection of two sets.", "and.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit present in $(italics)both/$ bitsets.$(li)With two lists, this creates a list of every element from the first list that is also in the second list.", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/categories/creative_unlocker.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/categories/creative_unlocker.json new file mode 100644 index 0000000000..bfb372c2c2 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/categories/creative_unlocker.json @@ -0,0 +1,7 @@ +{ + "name": "hexcasting.category.creative_unlocker", + "icon": "hexcasting:creative_unlocker", + "description": "hexcasting.category.creative_unlocker.desc", + "sortnum": 99, + "secret": true +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/creative_unlocker/media_cube.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/creative_unlocker/media_cube.json new file mode 100644 index 0000000000..fc8e245733 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/creative_unlocker/media_cube.json @@ -0,0 +1,22 @@ +{ + "name": "hexcasting.entry.media_cube", + "icon": "hexcasting:creative_unlocker", + "category": "hexcasting:creative_unlocker", + "sortnum": 0, + "priority": true, + "advancement": "hexcasting:creative_unlocker", + "pages": [ + { + "type": "patchouli:text", + "text": "hexcasting.page.creative_unlocker.1" + }, + { + "type": "patchouli:text", + "text": "hexcasting.page.creative_unlocker.2" + }, + { + "type": "patchouli:text", + "text": "hexcasting.page.creative_unlocker.3" + } + ] +} \ No newline at end of file diff --git a/Fabric/build.gradle b/Fabric/build.gradle index aafe9a125d..9e60ab70d3 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -84,6 +84,8 @@ dependencies { modImplementation "at.petra-k.paucal:paucal-fabric-$minecraftVersion:$paucalVersion" modImplementation "vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion-FABRIC-SNAPSHOT" + modImplementation "com.samsthenerd.inline:inline-fabric:$minecraftVersion-$inlineVersion" + modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-base:$cardinalComponentsVersion" // modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-util:$cardinalComponentsVersion" modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:$cardinalComponentsVersion" diff --git a/Fabric/gradle.properties b/Fabric/gradle.properties index 403ee97acd..912673b4a7 100644 --- a/Fabric/gradle.properties +++ b/Fabric/gradle.properties @@ -11,7 +11,6 @@ emiVersion=1.0.4+1.20.1 #gravityApiVersion=1.0.6 trinketsVersion=3.7.0 -clothConfigVersion=11.1.106 modmenuVersion=7.0.1 # Optimizations diff --git a/Fabric/src/generated/resources/.cache/19f2b40f78e342d65a8cb499a41e3fcb2eadaca3 b/Fabric/src/generated/resources/.cache/19f2b40f78e342d65a8cb499a41e3fcb2eadaca3 index e5e85cf919..235cf8d080 100644 --- a/Fabric/src/generated/resources/.cache/19f2b40f78e342d65a8cb499a41e3fcb2eadaca3 +++ b/Fabric/src/generated/resources/.cache/19f2b40f78e342d65a8cb499a41e3fcb2eadaca3 @@ -1,58 +1,58 @@ -// 1.20.1 2024-08-27T12:42:38.112410929 Hex Casting/Loot Tables -1dd4268edf7d6fa247013ab45541c7bfb915eef8 data/hexcasting/loot_tables/blocks/amethyst_bricks_small.json -601384d888edab27efe4a33027bb557eb7cb6ca2 data/hexcasting/loot_tables/blocks/edified_log_purple.json -2c9af74a82ca462e5986354966d5a0a1fd5a2083 data/hexcasting/loot_tables/blocks/slate_tiles.json -7c9c94d5b6b570d25eff32d4fa2ecc1e842e5231 data/hexcasting/loot_tables/blocks/quenched_allay_tiles.json -ecaeb4d5703a7aa206627ed38ee71aeb7e93d688 data/hexcasting/loot_tables/blocks/impetus/rightclick.json -a4e0194d8966a24531e43e04437cdb2a96456898 data/hexcasting/loot_tables/blocks/edified_tile.json -847bc3ead8a88a8f210a24e7732c28d50aa2f5dc data/hexcasting/loot_tables/blocks/edified_planks.json -92331eb19422730ffda0a3e52427a75aa1f7aff2 data/hexcasting/loot_tables/blocks/ancient_scroll_paper_lantern.json -4efd95d408d050c36ff21b18f3c37116491fef92 data/hexcasting/loot_tables/blocks/directrix/redstone.json -8c6c0486170537d73b923a2b9f83722107fc8716 data/hexcasting/loot_tables/blocks/edified_log_aventurine.json -ab86e126a704550d3f21c0b43f99fdc2665e4b09 data/hexcasting/loot_tables/blocks/slate_amethyst_tiles.json -7123b1a0469d7bd5bf8a2772182d222bf354df1a data/hexcasting/loot_tables/blocks/slate_bricks_small.json -b6c23fdde4f2c22c81f008604d5ff1c32ca8eb61 data/hexcasting/loot_tables/blocks/amethyst_tiles.json -b706c8a064f717c57104c48ea42aa860b45cf7a4 data/hexcasting/loot_tables/blocks/amethyst_dust_block.json -6eecc98b606d7ea5ec6f4c1fa4f63f7c1eba9223 data/hexcasting/loot_tables/blocks/slate_amethyst_bricks.json -b19ac49146149555038e6d2e06200d514df1ef43 data/hexcasting/loot_tables/blocks/akashic_bookshelf.json -9ff760d5db5628328ea9274c98e18a08f1ab983e data/hexcasting/loot_tables/blocks/slate_block.json -2ab674e834184b4e17dc002556d4473cac137445 data/hexcasting/loot_tables/blocks/edified_slab.json -df5496da8e48b61a171bc7a3936495c016cc002e data/hexcasting/loot_tables/blocks/directrix/empty.json -49940d1cb2599212e2837d7ed66c6c66e54f80f8 data/hexcasting/loot_tables/blocks/akashic_record.json -c81a5cb81141ab1fe09dd5dd3a0968b69dfffbd7 data/hexcasting/loot_tables/blocks/stripped_edified_log.json -10cb1b94596ac7131efe3bd5c36c1543ddba9302 data/hexcasting/loot_tables/blocks/impetus/redstone.json -499af9f15cf0a7f16fd2939e5d3af60a8089cc3e data/hexcasting/loot_tables/blocks/slate_bricks.json -147e0739a712a9050856cebcad1757b3f418f647 data/hexcasting/loot_tables/blocks/edified_trapdoor.json -2ad288784b0dc106ace2e6e0a40669f83476c414 data/hexcasting/loot_tables/blocks/slate.json -6c35afda4ca349f3506fe08f86f0afe58a6f2c44 data/hexcasting/loot_tables/blocks/quenched_allay.json -e6ff979aa47877c1b807075c448defd249cd3484 data/hexcasting/loot_tables/blocks/slate_amethyst_pillar.json -55f265961463a89c243ec8ac1970c70185f064a6 data/hexcasting/loot_tables/blocks/edified_button.json -c15d3ced89c882dfe552f84435fcdd560b729567 data/hexcasting/loot_tables/blocks/scroll_paper.json -1c6b077aae560e780be29e74ddcd4b0ca10ce3cf data/hexcasting/loot_tables/blocks/impetus/empty.json -dc4c6d270b8e93d05ac8ddeb1b9dd1d64828ac5d data/hexcasting/loot_tables/blocks/stripped_edified_wood.json -a62ffbcec2aa40172e05cd9fcd8e70e295d008e9 data/hexcasting/loot_tables/blocks/edified_fence_gate.json -cc7313cc33609fe1120baa7b4db631eaa29fbba1 data/hexcasting/loot_tables/blocks/citrine_edified_leaves.json -6920654f50532b5e557646e34edc4872339eb79f data/hexcasting/loot_tables/blocks/edified_log_amethyst.json -849afa706e7479d1c11bb40ae223ae5833e71286 data/hexcasting/loot_tables/blocks/scroll_paper_lantern.json -9905b767be7849e02a8e4ec4170af1bdde4e7fab data/hexcasting/loot_tables/blocks/edified_stairs.json -92528799c8ee13ff26c3c505e4dfb286c30f97c7 data/hexcasting/loot_tables/blocks/akashic_connector.json -45dc91d820caa5c421fe6f2afc7f71e45d6acd4d data/hexcasting/loot_tables/blocks/slate_pillar.json -1a1236e54c24b5aeff05919c73c76151da2cf115 data/hexcasting/loot_tables/blocks/amethyst_sconce.json -74159c21634679a6ab1dde1c181433db8b31c6ae data/hexcasting/loot_tables/blocks/edified_log_citrine.json -30f06db8c1ea74c9f4d95474e412336d065ac888 data/hexcasting/loot_tables/blocks/edified_door.json -95be0cf7f277257671631929462131b6d611119a data/hexcasting/loot_tables/inject/amethyst_cluster.json -bedbc2bd04f79372aedea64214ba2ea49cde9640 data/hexcasting/loot_tables/blocks/amethyst_edified_leaves.json -44658abcf122575878834d276ebcf5d8a6b7b398 data/hexcasting/loot_tables/blocks/aventurine_edified_leaves.json -cf6ff1ed1ee6fdbb05af16468a0a0ced79ac334e data/hexcasting/loot_tables/blocks/amethyst_bricks.json -45ae0ec668a07aa5b33d491377b2978f69f9f019 data/hexcasting/loot_tables/blocks/edified_panel.json -5f8d09e8c759d05cf9c2265ae28ea942cfbbe2be data/hexcasting/loot_tables/blocks/edified_pressure_plate.json -c426245d51f1e0fa0db7c4bfb454284d75506c9c data/hexcasting/loot_tables/blocks/quenched_allay_bricks.json -0b734693c926045b60fb515814b7a6695d0295fc data/hexcasting/loot_tables/blocks/impetus/look.json -d16fa9e366d48646686470c2d1f9bda4db3a1afa data/hexcasting/loot_tables/blocks/ancient_scroll_paper.json -2ac70e3c3600c88b2544d9755fc634216a7a523c data/hexcasting/loot_tables/blocks/edified_wood.json -509ecbb9731e75b63638c6012b2f986f131fd42f data/hexcasting/loot_tables/blocks/slate_amethyst_bricks_small.json -2902c4dae60875a1b2daf0a948a49a3419d8ec9d data/hexcasting/loot_tables/blocks/edified_log.json -434c2a6d2645e56e9a6ca56249ffa84645558e3b data/hexcasting/loot_tables/blocks/quenched_allay_bricks_small.json -65fe724d4c4ba8b0ab7d7a11bf37687413d9119d data/hexcasting/loot_tables/blocks/edified_fence.json -f1145860d80ff053970b1ad4f3b2f5d9f28e7c73 data/hexcasting/loot_tables/blocks/directrix/boolean.json -8ea8fd68719a960c2e132df441564a70c0e376a8 data/hexcasting/loot_tables/blocks/amethyst_pillar.json +// 1.20.1 2024-10-01T23:18:33.0642845 Hex Casting/Loot Tables +4efd95d408d050c36ff21b18f3c37116491fef92 data\hexcasting\loot_tables\blocks\directrix\redstone.json +6eecc98b606d7ea5ec6f4c1fa4f63f7c1eba9223 data\hexcasting\loot_tables\blocks\slate_amethyst_bricks.json +a62ffbcec2aa40172e05cd9fcd8e70e295d008e9 data\hexcasting\loot_tables\blocks\edified_fence_gate.json +92331eb19422730ffda0a3e52427a75aa1f7aff2 data\hexcasting\loot_tables\blocks\ancient_scroll_paper_lantern.json +434c2a6d2645e56e9a6ca56249ffa84645558e3b data\hexcasting\loot_tables\blocks\quenched_allay_bricks_small.json +c15d3ced89c882dfe552f84435fcdd560b729567 data\hexcasting\loot_tables\blocks\scroll_paper.json +b706c8a064f717c57104c48ea42aa860b45cf7a4 data\hexcasting\loot_tables\blocks\amethyst_dust_block.json +1a1236e54c24b5aeff05919c73c76151da2cf115 data\hexcasting\loot_tables\blocks\amethyst_sconce.json +95be0cf7f277257671631929462131b6d611119a data\hexcasting\loot_tables\inject\amethyst_cluster.json +5f8d09e8c759d05cf9c2265ae28ea942cfbbe2be data\hexcasting\loot_tables\blocks\edified_pressure_plate.json +147e0739a712a9050856cebcad1757b3f418f647 data\hexcasting\loot_tables\blocks\edified_trapdoor.json +74159c21634679a6ab1dde1c181433db8b31c6ae data\hexcasting\loot_tables\blocks\edified_log_citrine.json +847bc3ead8a88a8f210a24e7732c28d50aa2f5dc data\hexcasting\loot_tables\blocks\edified_planks.json +9905b767be7849e02a8e4ec4170af1bdde4e7fab data\hexcasting\loot_tables\blocks\edified_stairs.json +2ac70e3c3600c88b2544d9755fc634216a7a523c data\hexcasting\loot_tables\blocks\edified_wood.json +2ab674e834184b4e17dc002556d4473cac137445 data\hexcasting\loot_tables\blocks\edified_slab.json +499af9f15cf0a7f16fd2939e5d3af60a8089cc3e data\hexcasting\loot_tables\blocks\slate_bricks.json +1dd4268edf7d6fa247013ab45541c7bfb915eef8 data\hexcasting\loot_tables\blocks\amethyst_bricks_small.json +30f06db8c1ea74c9f4d95474e412336d065ac888 data\hexcasting\loot_tables\blocks\edified_door.json +2c9af74a82ca462e5986354966d5a0a1fd5a2083 data\hexcasting\loot_tables\blocks\slate_tiles.json +601384d888edab27efe4a33027bb557eb7cb6ca2 data\hexcasting\loot_tables\blocks\edified_log_purple.json +b6c23fdde4f2c22c81f008604d5ff1c32ca8eb61 data\hexcasting\loot_tables\blocks\amethyst_tiles.json +849afa706e7479d1c11bb40ae223ae5833e71286 data\hexcasting\loot_tables\blocks\scroll_paper_lantern.json +10cb1b94596ac7131efe3bd5c36c1543ddba9302 data\hexcasting\loot_tables\blocks\impetus\redstone.json +2902c4dae60875a1b2daf0a948a49a3419d8ec9d data\hexcasting\loot_tables\blocks\edified_log.json +c426245d51f1e0fa0db7c4bfb454284d75506c9c data\hexcasting\loot_tables\blocks\quenched_allay_bricks.json +0b734693c926045b60fb515814b7a6695d0295fc data\hexcasting\loot_tables\blocks\impetus\look.json +45dc91d820caa5c421fe6f2afc7f71e45d6acd4d data\hexcasting\loot_tables\blocks\slate_pillar.json +dc4c6d270b8e93d05ac8ddeb1b9dd1d64828ac5d data\hexcasting\loot_tables\blocks\stripped_edified_wood.json +e6ff979aa47877c1b807075c448defd249cd3484 data\hexcasting\loot_tables\blocks\slate_amethyst_pillar.json +ab86e126a704550d3f21c0b43f99fdc2665e4b09 data\hexcasting\loot_tables\blocks\slate_amethyst_tiles.json +7123b1a0469d7bd5bf8a2772182d222bf354df1a data\hexcasting\loot_tables\blocks\slate_bricks_small.json +df5496da8e48b61a171bc7a3936495c016cc002e data\hexcasting\loot_tables\blocks\directrix\empty.json +6c35afda4ca349f3506fe08f86f0afe58a6f2c44 data\hexcasting\loot_tables\blocks\quenched_allay.json +6920654f50532b5e557646e34edc4872339eb79f data\hexcasting\loot_tables\blocks\edified_log_amethyst.json +cf6ff1ed1ee6fdbb05af16468a0a0ced79ac334e data\hexcasting\loot_tables\blocks\amethyst_bricks.json +92528799c8ee13ff26c3c505e4dfb286c30f97c7 data\hexcasting\loot_tables\blocks\akashic_connector.json +a4e0194d8966a24531e43e04437cdb2a96456898 data\hexcasting\loot_tables\blocks\edified_tile.json +49940d1cb2599212e2837d7ed66c6c66e54f80f8 data\hexcasting\loot_tables\blocks\akashic_record.json +1c6b077aae560e780be29e74ddcd4b0ca10ce3cf data\hexcasting\loot_tables\blocks\impetus\empty.json +cc7313cc33609fe1120baa7b4db631eaa29fbba1 data\hexcasting\loot_tables\blocks\citrine_edified_leaves.json +2ad288784b0dc106ace2e6e0a40669f83476c414 data\hexcasting\loot_tables\blocks\slate.json +c81a5cb81141ab1fe09dd5dd3a0968b69dfffbd7 data\hexcasting\loot_tables\blocks\stripped_edified_log.json +45ae0ec668a07aa5b33d491377b2978f69f9f019 data\hexcasting\loot_tables\blocks\edified_panel.json +44658abcf122575878834d276ebcf5d8a6b7b398 data\hexcasting\loot_tables\blocks\aventurine_edified_leaves.json +b19ac49146149555038e6d2e06200d514df1ef43 data\hexcasting\loot_tables\blocks\akashic_bookshelf.json +65fe724d4c4ba8b0ab7d7a11bf37687413d9119d data\hexcasting\loot_tables\blocks\edified_fence.json +d16fa9e366d48646686470c2d1f9bda4db3a1afa data\hexcasting\loot_tables\blocks\ancient_scroll_paper.json +55f265961463a89c243ec8ac1970c70185f064a6 data\hexcasting\loot_tables\blocks\edified_button.json +509ecbb9731e75b63638c6012b2f986f131fd42f data\hexcasting\loot_tables\blocks\slate_amethyst_bricks_small.json +ecaeb4d5703a7aa206627ed38ee71aeb7e93d688 data\hexcasting\loot_tables\blocks\impetus\rightclick.json +bedbc2bd04f79372aedea64214ba2ea49cde9640 data\hexcasting\loot_tables\blocks\amethyst_edified_leaves.json +8ea8fd68719a960c2e132df441564a70c0e376a8 data\hexcasting\loot_tables\blocks\amethyst_pillar.json +9ff760d5db5628328ea9274c98e18a08f1ab983e data\hexcasting\loot_tables\blocks\slate_block.json +7c9c94d5b6b570d25eff32d4fa2ecc1e842e5231 data\hexcasting\loot_tables\blocks\quenched_allay_tiles.json +f1145860d80ff053970b1ad4f3b2f5d9f28e7c73 data\hexcasting\loot_tables\blocks\directrix\boolean.json +8c6c0486170537d73b923a2b9f83722107fc8716 data\hexcasting\loot_tables\blocks\edified_log_aventurine.json diff --git a/Fabric/src/generated/resources/.cache/2ba8da2cf2d44ff18dc72cc891b094eca6836a5c b/Fabric/src/generated/resources/.cache/2ba8da2cf2d44ff18dc72cc891b094eca6836a5c index d7f56c26ff..712d957772 100644 --- a/Fabric/src/generated/resources/.cache/2ba8da2cf2d44ff18dc72cc891b094eca6836a5c +++ b/Fabric/src/generated/resources/.cache/2ba8da2cf2d44ff18dc72cc891b094eca6836a5c @@ -1,25 +1,25 @@ -// 1.20.1 2024-08-27T12:42:38.116625477 Hex Casting/Tags for minecraft:item -5928bad07d3872bb60f29ef4f3c885c8e1967c20 data/hexcasting/tags/items/phial_base.json -fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data/minecraft/tags/items/wooden_doors.json -fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data/minecraft/tags/items/doors.json -37cff4ce449b8069b59b2327d78e073fc026d348 data/minecraft/tags/items/wooden_pressure_plates.json -30780136e6469a01369d7e278998edb6d7f6a16b data/hexcasting/tags/items/staves.json -20183cd61968ff6548df2dde1100b6378d68d64b data/minecraft/tags/items/wooden_buttons.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/hexcasting/tags/items/edified_logs.json -e186f43ed06770e698c886691f91b2c6acdb5a2a data/hexcasting/tags/items/seal_materials.json -4461ef6db41a675fd077dd833cfd0ea537e755be data/c/tags/items/amethyst_dusts.json -5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data/minecraft/tags/items/trapdoors.json -e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data/minecraft/tags/items/planks.json -c72a147bc65d26424df199388969ebd11119aed3 data/hexcasting/tags/items/brainswept_circle_components.json -5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data/minecraft/tags/items/wooden_trapdoors.json -bdb90cee0e88e02f0b98f12d5dd212adfaca9afd data/hexcasting/tags/items/impeti.json -e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data/hexcasting/tags/items/edified_planks.json -20183cd61968ff6548df2dde1100b6378d68d64b data/minecraft/tags/items/buttons.json -38d781b60c5c37dc025d4c7e9ec5aa680f2a5835 data/c/tags/items/gems.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/minecraft/tags/items/logs_that_burn.json -24145229528668829a1bcecf18a6377ebd07ccf8 data/hexcasting/tags/items/grants_root_advancement.json -5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data/minecraft/tags/items/leaves.json -9d18fb7a889031a704ca0e553600e1d6f8c3759d data/hexcasting/tags/items/directrices.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/minecraft/tags/items/logs.json -5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data/minecraft/tags/items/slabs.json -5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data/minecraft/tags/items/wooden_slabs.json +// 1.20.1 2024-10-01T23:18:33.0667937 Hex Casting/Tags for minecraft:item +5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data\minecraft\tags\items\wooden_slabs.json +fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data\minecraft\tags\items\wooden_doors.json +37cff4ce449b8069b59b2327d78e073fc026d348 data\minecraft\tags\items\wooden_pressure_plates.json +5928bad07d3872bb60f29ef4f3c885c8e1967c20 data\hexcasting\tags\items\phial_base.json +e186f43ed06770e698c886691f91b2c6acdb5a2a data\hexcasting\tags\items\seal_materials.json +38d781b60c5c37dc025d4c7e9ec5aa680f2a5835 data\c\tags\items\gems.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\minecraft\tags\items\logs_that_burn.json +5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data\minecraft\tags\items\leaves.json +4461ef6db41a675fd077dd833cfd0ea537e755be data\c\tags\items\amethyst_dusts.json +5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data\minecraft\tags\items\wooden_trapdoors.json +5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data\minecraft\tags\items\slabs.json +e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data\minecraft\tags\items\planks.json +20183cd61968ff6548df2dde1100b6378d68d64b data\minecraft\tags\items\wooden_buttons.json +9d18fb7a889031a704ca0e553600e1d6f8c3759d data\hexcasting\tags\items\directrices.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\hexcasting\tags\items\edified_logs.json +5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data\minecraft\tags\items\trapdoors.json +e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data\hexcasting\tags\items\edified_planks.json +c72a147bc65d26424df199388969ebd11119aed3 data\hexcasting\tags\items\brainswept_circle_components.json +fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data\minecraft\tags\items\doors.json +bdb90cee0e88e02f0b98f12d5dd212adfaca9afd data\hexcasting\tags\items\impeti.json +20183cd61968ff6548df2dde1100b6378d68d64b data\minecraft\tags\items\buttons.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\minecraft\tags\items\logs.json +30780136e6469a01369d7e278998edb6d7f6a16b data\hexcasting\tags\items\staves.json +ef8ae066fea6277ba2ab43faf18757b88f7c4803 data\hexcasting\tags\items\grants_root_advancement.json diff --git a/Fabric/src/generated/resources/.cache/3cb4ab563deee432e7d307024048f57946bafb1c b/Fabric/src/generated/resources/.cache/3cb4ab563deee432e7d307024048f57946bafb1c index 1e7f2dc25b..53f58a46b7 100644 --- a/Fabric/src/generated/resources/.cache/3cb4ab563deee432e7d307024048f57946bafb1c +++ b/Fabric/src/generated/resources/.cache/3cb4ab563deee432e7d307024048f57946bafb1c @@ -1,4 +1,4 @@ -// 1.20.1 2024-08-27T12:42:38.120411259 Hex Casting/Tags for hexcasting:action -6fe30f41e2bcd48589caab26d210a513dce1ab7c data/hexcasting/tags/action/per_world_pattern.json -6fe30f41e2bcd48589caab26d210a513dce1ab7c data/hexcasting/tags/action/requires_enlightenment.json -6fe30f41e2bcd48589caab26d210a513dce1ab7c data/hexcasting/tags/action/can_start_enlighten.json +// 1.20.1 2024-10-01T23:18:33.0697946 Hex Casting/Tags for hexcasting:action +6fe30f41e2bcd48589caab26d210a513dce1ab7c data\hexcasting\tags\action\requires_enlightenment.json +6fe30f41e2bcd48589caab26d210a513dce1ab7c data\hexcasting\tags\action\can_start_enlighten.json +6fe30f41e2bcd48589caab26d210a513dce1ab7c data\hexcasting\tags\action\per_world_pattern.json diff --git a/Fabric/src/generated/resources/.cache/812fdb58b7018b2d5c5af7da57a2b1857fa66794 b/Fabric/src/generated/resources/.cache/812fdb58b7018b2d5c5af7da57a2b1857fa66794 index e7b75bcd42..0378ffd050 100644 --- a/Fabric/src/generated/resources/.cache/812fdb58b7018b2d5c5af7da57a2b1857fa66794 +++ b/Fabric/src/generated/resources/.cache/812fdb58b7018b2d5c5af7da57a2b1857fa66794 @@ -1,33 +1,33 @@ -// 1.20.1 2024-08-27T12:42:38.115300691 Hex Casting/Tags for minecraft:block -c72a147bc65d26424df199388969ebd11119aed3 data/hexcasting/tags/blocks/brainswept_circle_components.json -357eddf3cee6f16725bed0701d57b2ca3097d74d data/minecraft/tags/blocks/mineable/shovel.json -20183cd61968ff6548df2dde1100b6378d68d64b data/minecraft/tags/blocks/buttons.json -8cd7a960fd719f200b0bf38100cd17c73b66d39c data/minecraft/tags/blocks/mineable/pickaxe.json -643994ee757a533cfb5001689e0f0263956b8a35 data/minecraft/tags/blocks/mineable/axe.json -5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data/minecraft/tags/blocks/mineable/hoe.json -6ae561f7399e39ffa0e97bd0569aeffa9eabff6a data/hexcasting/tags/blocks/water_plants.json -e8d5ef7eabb567228b279b2419e4f042082d7491 data/minecraft/tags/blocks/fences.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/minecraft/tags/blocks/logs_that_burn.json -eba53f6c7645de4ef5ffb1e10ef34a4c23e98887 data/hexcasting/tags/blocks/cheap_to_break_block.json -7e1e353cb7f561f086898f991ece48e047991934 data/minecraft/tags/blocks/unstable_bottom_center.json -5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data/minecraft/tags/blocks/leaves.json -281cb08b9b68ef049820c4f3f36b40820044681e data/minecraft/tags/blocks/wooden_stairs.json -6f52ca5e42991af6d7b829f626010ce304277464 data/minecraft/tags/blocks/crystal_sound_blocks.json -5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data/minecraft/tags/blocks/trapdoors.json -37cff4ce449b8069b59b2327d78e073fc026d348 data/minecraft/tags/blocks/wooden_pressure_plates.json -20183cd61968ff6548df2dde1100b6378d68d64b data/minecraft/tags/blocks/wooden_buttons.json -5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data/minecraft/tags/blocks/wooden_trapdoors.json -7acae0c88f5ead65339db1b11b16f60214434c86 data/minecraft/tags/blocks/wooden_fences.json -fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data/minecraft/tags/blocks/wooden_doors.json -7e1e353cb7f561f086898f991ece48e047991934 data/minecraft/tags/blocks/fence_gates.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/minecraft/tags/blocks/logs.json -c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data/hexcasting/tags/blocks/edified_logs.json -5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data/minecraft/tags/blocks/slabs.json -e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data/minecraft/tags/blocks/planks.json -281cb08b9b68ef049820c4f3f36b40820044681e data/minecraft/tags/blocks/stairs.json -bdb90cee0e88e02f0b98f12d5dd212adfaca9afd data/hexcasting/tags/blocks/impeti.json -9d18fb7a889031a704ca0e553600e1d6f8c3759d data/hexcasting/tags/blocks/directrices.json -37cff4ce449b8069b59b2327d78e073fc026d348 data/minecraft/tags/blocks/pressure_plates.json -fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data/minecraft/tags/blocks/doors.json -5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data/minecraft/tags/blocks/wooden_slabs.json -e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data/hexcasting/tags/blocks/edified_planks.json +// 1.20.1 2024-10-01T23:18:33.0657931 Hex Casting/Tags for minecraft:block +357eddf3cee6f16725bed0701d57b2ca3097d74d data\minecraft\tags\blocks\mineable\shovel.json +5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data\minecraft\tags\blocks\trapdoors.json +643994ee757a533cfb5001689e0f0263956b8a35 data\minecraft\tags\blocks\mineable\axe.json +5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data\minecraft\tags\blocks\mineable\hoe.json +fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data\minecraft\tags\blocks\doors.json +6f52ca5e42991af6d7b829f626010ce304277464 data\minecraft\tags\blocks\crystal_sound_blocks.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\hexcasting\tags\blocks\edified_logs.json +281cb08b9b68ef049820c4f3f36b40820044681e data\minecraft\tags\blocks\wooden_stairs.json +e8d5ef7eabb567228b279b2419e4f042082d7491 data\minecraft\tags\blocks\fences.json +5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data\minecraft\tags\blocks\slabs.json +281cb08b9b68ef049820c4f3f36b40820044681e data\minecraft\tags\blocks\stairs.json +20183cd61968ff6548df2dde1100b6378d68d64b data\minecraft\tags\blocks\buttons.json +37cff4ce449b8069b59b2327d78e073fc026d348 data\minecraft\tags\blocks\wooden_pressure_plates.json +9d18fb7a889031a704ca0e553600e1d6f8c3759d data\hexcasting\tags\blocks\directrices.json +e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data\hexcasting\tags\blocks\edified_planks.json +5f3b600b4fd98744bd08c993ce7bcb9c2f195cd2 data\minecraft\tags\blocks\leaves.json +fdb48f194d7937ab6b423fa4b90a4d438bf6dd90 data\minecraft\tags\blocks\wooden_doors.json +7e1e353cb7f561f086898f991ece48e047991934 data\minecraft\tags\blocks\unstable_bottom_center.json +8cd7a960fd719f200b0bf38100cd17c73b66d39c data\minecraft\tags\blocks\mineable\pickaxe.json +7e1e353cb7f561f086898f991ece48e047991934 data\minecraft\tags\blocks\fence_gates.json +6ae561f7399e39ffa0e97bd0569aeffa9eabff6a data\hexcasting\tags\blocks\water_plants.json +5bbfd513fd2eb2090b0c2d1ec33504deb79d53b9 data\minecraft\tags\blocks\wooden_slabs.json +5216ba5c57db29b8dee9aebc63a2e3b17c97dc17 data\minecraft\tags\blocks\wooden_trapdoors.json +eba53f6c7645de4ef5ffb1e10ef34a4c23e98887 data\hexcasting\tags\blocks\cheap_to_break_block.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\minecraft\tags\blocks\logs.json +e5df19a1dc6eadf14cd9b0f0fe45a74330b745e9 data\minecraft\tags\blocks\planks.json +c72a147bc65d26424df199388969ebd11119aed3 data\hexcasting\tags\blocks\brainswept_circle_components.json +7acae0c88f5ead65339db1b11b16f60214434c86 data\minecraft\tags\blocks\wooden_fences.json +20183cd61968ff6548df2dde1100b6378d68d64b data\minecraft\tags\blocks\wooden_buttons.json +c562b4be24d0b6b13f3c65599d3bfa3bf2c4ce21 data\minecraft\tags\blocks\logs_that_burn.json +37cff4ce449b8069b59b2327d78e073fc026d348 data\minecraft\tags\blocks\pressure_plates.json +bdb90cee0e88e02f0b98f12d5dd212adfaca9afd data\hexcasting\tags\blocks\impeti.json diff --git a/Fabric/src/generated/resources/.cache/c70ef2fe5da52437c1f53bcc9ea0e416f16bcc0b b/Fabric/src/generated/resources/.cache/c70ef2fe5da52437c1f53bcc9ea0e416f16bcc0b index 1a07bbdc44..318ea65e9d 100644 --- a/Fabric/src/generated/resources/.cache/c70ef2fe5da52437c1f53bcc9ea0e416f16bcc0b +++ b/Fabric/src/generated/resources/.cache/c70ef2fe5da52437c1f53bcc9ea0e416f16bcc0b @@ -1,218 +1,218 @@ -// 1.20.1 2024-08-27T12:42:38.11755991 Hex Casting/Recipes -f482a4349786388cc8f11d5550548f7d60265438 data/hexcasting/recipes/staff/mangrove.json -b10d590e918e35b16578a8b739a1c4e7e2202e16 data/hexcasting/advancements/recipes/misc/dye_colorizer_cyan.json -7aa3bf4a3d6fb92743b29dfe89d50537fefc0db9 data/hexcasting/advancements/recipes/misc/pride_colorizer_intersex.json -648f1862fde1dd8ade80b2991b8c8e3991389e95 data/hexcasting/recipes/dye_colorizer_light_blue.json -23eff6111b0385b66d3ad5fbabfc625f426517a6 data/hexcasting/advancements/recipes/brainsweep/brainsweep/directrix_redstone.json -a3130e3098e35b75afae4f31996d9ab7468e0bc3 data/hexcasting/advancements/recipes/tools/thought_knot.json -c8f2ad363e4d20054f4e56fde02c8775a45a7169 data/hexcasting/recipes/artifact.json -f80dbf59957be175fbcd63224005e09c4cd1a122 data/hexcasting/recipes/compat/farmersdelight/cutting/edified_log_citrine.json -2fff80cd3dabd2bc1744eecd72b2364b0f91c7c1 data/hexcasting/advancements/recipes/misc/dye_colorizer_yellow.json -9269b17eaae3217422352354fc6006c9808b398c data/hexcasting/recipes/dye_colorizer_black.json -441f336edb635e5d8c2a7183906fed1c501f06fd data/hexcasting/recipes/pride_colorizer_bisexual.json -a72a0fcc0f3a81d31b30a7a626aef537796ca73b data/hexcasting/advancements/recipes/tools/staff/quenched.json -2aa7d74e29a7c5ee4f1b8835cf7c6109eed81d77 data/hexcasting/recipes/brainsweep/quench_allay.json -2c292e12b5e85b1701740c222e5c5465799ad1dc data/hexcasting/recipes/pride_colorizer_aroace.json -5d6d73e16a36da5f9df6a7b8ac859181d401766d data/hexcasting/recipes/uuid_colorizer.json -49e706193bb57a957091e419bd0d8aa58135da1f data/hexcasting/recipes/dye_colorizer_green.json -2cea013887734cbc4971bcd57e7e4f6a2b25c8e1 data/hexcasting/advancements/recipes/tools/focus.json -36d26f34d0405ff2d1e728e5b5174502686e3590 data/hexcasting/advancements/recipes/brainsweep/brainsweep/budding_amethyst.json -daa7b13d5370f4306f8cdf3037fc346e8918950a data/hexcasting/recipes/dye_colorizer_brown.json -b94bc4dd4a63db10af86c524ba00eae157c1824b data/hexcasting/advancements/recipes/building_blocks/edified_fence_gate.json -9ea4fe5272ce2241d98f30359f55cfc1936c7b48 data/hexcasting/advancements/recipes/tools/staff/cherry.json -e0609202271e402d8ae58e4f8eaf11dcdda10a9e data/hexcasting/recipes/brainsweep/akashic_record.json -c3f7b03fe184ed5e54a8ae06d130adf507b7683d data/hexcasting/recipes/staff/bamboo.json -7ca0f9fc6e8ae1ad08ef5c29a0b279b891f7d8d4 data/hexcasting/advancements/recipes/misc/pride_colorizer_aroace.json -4aaefc65af5fe69d312247fdda7d983edf8dcd9a data/hexcasting/recipes/pride_colorizer_intersex.json -641d8c38b8109665314fccbebd9068ba10b04118 data/hexcasting/advancements/recipes/misc/dye_colorizer_gray.json -fd2f25b0a71806c96af5a307fad76f66de6210a4 data/hexcasting/advancements/recipes/building_blocks/slate_block.json -b1f8375aaf0d66035dee720ea59605f69fc0a154 data/hexcasting/recipes/edified_fence.json -ae88fcdecbfbdd0a0fe778467421a3b32d7ed735 data/create/recipes/crushing/amethyst_cluster.json -8b7136c206b799a2e394aa02316b0509674ff64f data/hexcasting/advancements/recipes/tools/staff/bamboo.json -fb852d8e4bcfa7b75f41a6ac7dc1e76b00d95fb1 data/hexcasting/advancements/recipes/misc/dye_colorizer_red.json -5401828f85e709b5817ecc8464dc63e536a730dc data/hexcasting/recipes/staff/cherry.json -54335e0004423899ad37763a1d8456cc0a6e72a7 data/hexcasting/advancements/recipes/misc/decompose_quenched_shard/charged.json -c1846dd794f5cc5814b8a839291e82512a02ba12 data/hexcasting/advancements/recipes/misc/pride_colorizer_plural.json -0ead307e47242ba140584f6bd20088a1fa7c2909 data/hexcasting/recipes/directrix/empty.json -b7084f131b0cdb9c2c698a3c5b3450d69e788d6e data/hexcasting/recipes/dye_colorizer_yellow.json -55ea553a96e1d6a54385890f7c48fe7b2bed6871 data/hexcasting/advancements/recipes/tools/trinket.json -2003fed3aa4eb622b6b07a9e65946fb40be14420 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_rightclick.json -1b092acfc3115702c74e141492e649d58512f259 data/hexcasting/recipes/staff/oak.json -5a90084c03d6e8424872870c8b65f4771b447f03 data/hexcasting/recipes/brainsweep/budding_amethyst.json -61e53f02baefd31308e99407d56403dfc18e36e1 data/hexcasting/recipes/akashic_connector.json -93ed0491548920bc75797d18501c750ef07fe3ea data/hexcasting/advancements/recipes/misc/pride_colorizer_bisexual.json -0f2e63a9361d18aac764f6a4a4f13b9b862ac2ee data/hexcasting/recipes/compat/create/crushing/amethyst_shard.json -c4b985635c3b1a519d7a83da65daba5bdd3a5f59 data/hexcasting/advancements/recipes/decorations/ageing_scroll_paper_lantern.json -b6720c1c73455ad817bac9b5ca2ca045c5c4050c data/hexcasting/recipes/pride_colorizer_agender.json -5f216dbb7b89fd837e2dd73e3ed41c8d412de234 data/hexcasting/advancements/recipes/misc/decompose_quenched_shard/dust.json -903cbe4d4c4e5abcd5e006f9d0237e8c596228ba data/hexcasting/recipes/edified_tile.json -fb486df96798724da2fcc0df5706f19bc1ff94dc data/hexcasting/advancements/recipes/misc/dye_colorizer_light_blue.json -410bfde90cb977db3f13814e94484fa11fca7cfc data/hexcasting/recipes/thought_knot.json -30352d8ad510768770bb1b2d378959b7a502f825 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_look.json -a8cab28cffdf495253a320094d202fccc5aeb113 data/hexcasting/advancements/recipes/decorations/ancient_scroll_paper_lantern.json -af8fe74b624df4a31727347b9826614a66092b0a data/hexcasting/advancements/recipes/misc/pride_colorizer_agender.json -e765ee2bd324240e8ed3d625be431de3281f0070 data/hexcasting/recipes/dye_colorizer_gray.json -a0b87b1b21506708d09c9295b7afc13de6b1fce6 data/hexcasting/recipes/pride_colorizer_aromantic.json -4d941fc399c6b7a470513a572ecd88982823da84 data/hexcasting/advancements/recipes/building_blocks/edified_wood.json -aa1caae7eba6aede0f179619488e2253b3b723dd data/hexcasting/recipes/focus_rotated.json -505eb9192df0b48867e58e09ce36b2259dc6d3e8 data/hexcasting/advancements/recipes/decorations/scroll.json -1d1e73244fb3da633d8a5f84bad93c6022a94368 data/hexcasting/advancements/recipes/misc/pride_colorizer_demiboy.json -71d38559bf455ea343ac0237a57db4d3f0833a7c data/hexcasting/advancements/recipes/misc/dye_colorizer_magenta.json -fd7c8325fcaa6a718e90c09251b447fb365523d4 data/hexcasting/recipes/pride_colorizer_demiboy.json -b5946314683e5a823b577a18d13fb437a35aafd5 data/hexcasting/recipes/decompose_quenched_shard/charged.json -011f8daf15148d4b77686c6d382d8f5c288a333d data/hexcasting/advancements/recipes/building_blocks/ancient_scroll_paper.json -494aa470790ae46baebbf24ee5b76f5885c1af1a data/hexcasting/recipes/ageing_scroll_paper_lantern.json -c6228d72ca800a7dd336e82bbb9b4f20f89de29d data/hexcasting/advancements/recipes/redstone/edified_pressure_plate.json -5889e2df2fb4e1ea29f2590b96bb3aa94961a09a data/hexcasting/recipes/scroll.json -a9111ff52513200af47b79cf98b2e545699497bb data/hexcasting/advancements/recipes/building_blocks/amethyst_tiles.json -e9166f40c8797cdbf3d8062dfa35c74f850f1000 data/hexcasting/advancements/recipes/misc/dye_colorizer_white.json -2c56c267e23e75d5a3b9358d424d69642e001b50 data/hexcasting/recipes/decompose_quenched_shard/dust.json -ea87956c49dcfabb0d39af45c016130d258181da data/hexcasting/recipes/staff/birch.json -98c0843e6a83b91820f1c720e206295eec20ff95 data/hexcasting/recipes/ancient_scroll_paper.json -bc8fe4d2f55fe119b0b146a71782a3d4788380b1 data/create/recipes/crushing/amethyst_block.json -97062771a426f6e4b9e3bfd6daa62b1d4b3c7039 data/hexcasting/recipes/abacus.json -24c244e53c7e47b85845d2ee36b1665410cf495a data/hexcasting/recipes/edified_planks.json -417695497a95436186c1a4ed842d7975d754f9eb data/hexcasting/recipes/stripped_edified_wood.json -7f2f29981df2ca4464ee0250180e670f5331f65b data/hexcasting/recipes/dye_colorizer_pink.json -ea63e49709bd80cb9f4cd1fe13e9bd0281101c9a data/hexcasting/recipes/slate.json -f64fa00d85a9abb24e89b0d2c9f818001371f5e6 data/hexcasting/recipes/slate_block.json -14f3b217e150efbbff329d67aec96f818a1da99c data/hexcasting/recipes/dye_colorizer_purple.json -9b7c5220fbaf3e84fa9e81eae322eed5d37b22d3 data/hexcasting/recipes/pride_colorizer_transgender.json -17a1adf747b99848381ca8e7c5e2cd9dd96c014f data/hexcasting/advancements/recipes/misc/default_colorizer.json -a85cfbd7988f5df0b18d160591605aea8e6808d2 data/hexcasting/recipes/trinket.json -4003f297be29810cebde4995fb2838c2c68a25ea data/hexcasting/recipes/pride_colorizer_lesbian.json -41a570f970c9af8229cb1140a11a5220fac00957 data/hexcasting/advancements/recipes/tools/staff/spruce.json -b300f7729e75614fce412457f6717686680f81da data/hexcasting/recipes/sub_sandwich.json -0b951ce7b9d1bfb07ae012b12225b595d36c6e66 data/hexcasting/recipes/amethyst_dust_packing.json -2b64261bd4aefdc55d35400f25835434f88856cf data/hexcasting/recipes/amethyst_tiles.json -963d87d2738686e5398a178b8b369228ff067403 data/hexcasting/recipes/spellbook.json -6e2dc32f975d987b8dfd329507334f647bceadc0 data/hexcasting/advancements/recipes/tools/staff/mangrove.json -996c8361766377a70e0b5a5caff3076fc6031b0a data/hexcasting/recipes/impetus/empty.json -71f821f5d24b0bf9ecd860d51e055628fe4af50c data/hexcasting/recipes/edified_panel.json -7166cd4355d11c209bc7749bc862caddcfd795fb data/hexcasting/recipes/dye_colorizer_cyan.json -f347f4ce869207e62a7887df1252505a3432e12a data/hexcasting/recipes/pride_colorizer_genderfluid.json -1b570b35288be9f6faab1536d6e45cb52eb088c0 data/hexcasting/advancements/recipes/tools/staff/dark_oak.json -31ec6474ddae967a6c1dadf9be8292d375510364 data/hexcasting/advancements/recipes/building_blocks/edified_tile.json -5e66982df6a1074c81f381898033b521ca337695 data/hexcasting/recipes/staff/quenched.json -45915b542d8070f2502a4047218679b08033b12d data/hexcasting/advancements/recipes/decorations/scroll_paper_lantern.json -946cde51bbfc2af344b078f6b39389ffc44462f4 data/hexcasting/advancements/recipes/brainsweep/brainsweep/impetus_storedplayer.json -1093cccc6b1c45eb91f7c1680ef575a7bffb2744 data/hexcasting/advancements/recipes/building_blocks/edified_planks.json -72447ac69a0d85f91064180d3c852040a9e33832 data/hexcasting/recipes/pride_colorizer_asexual.json -0e792d49c81d2164e827d1bdedaa0fa358dfc437 data/hexcasting/advancements/recipes/misc/pride_colorizer_aromantic.json -b84c113ef5321c9df9ac9080de03e8d8639feab2 data/hexcasting/advancements/recipes/misc/pride_colorizer_genderqueer.json -e6a592721234448f2ee7ec402bca10a9b78b4677 data/hexcasting/advancements/recipes/decorations/slate.json -de38d15e7a91c77df24c1dc954b3e98ee197876f data/hexcasting/recipes/focus.json -157ee5fba985bbd01a87f44578890dab5489a8e5 data/hexcasting/advancements/recipes/misc/dye_colorizer_green.json -c1541738df1ee41c362ad3b9c3a9f0e181bd5c62 data/hexcasting/recipes/pride_colorizer_plural.json -233aeedc73173427e7b2287772a4f914f97b072c data/hexcasting/recipes/dye_colorizer_red.json -12bd3d04c791ef16aad5e992f038d6726229a436 data/hexcasting/advancements/recipes/tools/artifact.json -862f1a61a296a834df8a93dbd5a6cdfa2df15721 data/hexcasting/advancements/recipes/tools/staff/acacia.json -a1f9df0537c0ef33a1164cf94e8ff4b1094f889f data/hexcasting/advancements/recipes/tools/staff/warped.json -b6e762c198b9632defd7f8b11287702abecd681d data/hexcasting/recipes/staff/mindsplice.json -7c479398bbc7185a2c3efd568ad266d8109245bf data/hexcasting/advancements/recipes/redstone/edified_door.json -5fab1b9c93304a53a4c305b511704458e4593444 data/hexcasting/recipes/pride_colorizer_demigirl.json -e536791d0c6fb48206e6e30d56879eaf0a9e4bd7 data/hexcasting/recipes/akashic_bookshelf.json -b90ad4cbffc2e3c01671dfe8bda5e42d9b8a685c data/hexcasting/advancements/recipes/tools/staff/crimson.json -68ab70e0b4e432a3492767c5597ecd836f106714 data/hexcasting/advancements/recipes/tools/staff/mindsplice.json -c2ef04b311251b4eb22320b2f5313c54533a9974 data/hexcasting/advancements/recipes/tools/staff/birch.json -1a0d55e6824c078453c1d44e885a1c51ba707a41 data/hexcasting/recipes/dye_colorizer_white.json -8f8773a541bc6a4a6c55a23f4f98b5da4f61a031 data/hexcasting/recipes/scroll_paper.json -bc729ac7cf84d29a99cd34d50c152c0b9d20bd7a data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json -4a803e049915fd3c7144155ae3a1b05a917ea290 data/hexcasting/recipes/pride_colorizer_pansexual.json -0654e70ed1ed8be20ae3dd9f4955cd14f9fa40d0 data/hexcasting/advancements/recipes/tools/staff/jungle.json -8bea75fdc5e64c464dcf5f85166e767ff44e6dc2 data/hexcasting/advancements/recipes/misc/pride_colorizer_lesbian.json -5e98cec2084f0cfbb959c3ec39bd85a3369f443b data/hexcasting/advancements/recipes/tools/abacus.json -0b172aef920da7ba63fe152903ce005c1f5df5f1 data/hexcasting/recipes/staff/acacia.json -7e1a5a873d655e0efba80f22ae9b1de4f248e67a data/hexcasting/advancements/recipes/misc/decompose_quenched_shard/shard.json -3608f0ec056f2c5d29a9a89305218497fd2c4383 data/hexcasting/recipes/stonecutting/amethyst_tiles.json -2a2f60fb0f63ee278b74c418acf04575304c521f data/hexcasting/advancements/recipes/tools/jeweler_hammer.json -8c043c7f6a7911b67324e2fd42f0b3b19a792af3 data/hexcasting/recipes/ancient_scroll_paper_lantern.json -4680e9dafcf9b60b3485609519d66eefcfd539bc data/hexcasting/recipes/staff/dark_oak.json -095aeb2882c6849f10fb6536e7c780790778e5e7 data/hexcasting/recipes/staff/jungle.json -b624d103d944a8a1d4d8a9e85c198a5492b476f8 data/hexcasting/advancements/recipes/redstone/edified_trapdoor.json -eb9ebf77f0daa32f665a60888fcda19c940f0b2f data/hexcasting/advancements/recipes/misc/pride_colorizer_demigirl.json -8f7b81add0153ad94900acc66cd8174ae7115f64 data/hexcasting/advancements/recipes/building_blocks/slate_block_from_slates.json -838b91c33a72a58aa286607eaaa17cdd6b4c90ba data/hexcasting/recipes/amethyst_sconce.json -664ce1a38c9b1c9ec21b7e078631e181fc0b2498 data/hexcasting/recipes/staff/edified.json -7522be58b09554a3f1a54d5b2343c3eab01447a3 data/hexcasting/recipes/dye_colorizer_magenta.json -ee5db13cbb33d9c62bcb1eb645e2c4bea97ad44a data/hexcasting/advancements/recipes/building_blocks/amethyst_dust_unpacking.json -203b7035125390abb4ed77b3a4dca8f8f8f57bc5 data/hexcasting/recipes/dye_colorizer_light_gray.json -f8ee073c1c03f1c11147e4801eeba1f86e5459ba data/hexcasting/recipes/dye_colorizer_blue.json -a366ea3750adc0d336ab8f318c40baed3f9c3eb7 data/hexcasting/recipes/brainsweep/impetus_storedplayer.json -51b047601368a103be166d907633b196d2d8a4e8 data/hexcasting/recipes/compat/farmersdelight/cutting/edified_log.json -f4c56ea7143ce92a0ae0b663310e53644a7309f7 data/hexcasting/advancements/recipes/misc/pride_colorizer_pansexual.json -6f2634e5588aede8e29157ecc859652d8a9f4065 data/hexcasting/advancements/recipes/misc/dye_colorizer_orange.json -f1bae034d27d218bf262a8c777b787d232489f16 data/hexcasting/recipes/lens.json -06402fb37fe4bb05918d13dbfdb89f4c2b67f3ec data/hexcasting/advancements/recipes/tools/cypher.json -ed5c690324e3d9b55599f00f078ae225072a2e7f data/hexcasting/recipes/brainsweep/impetus_rightclick.json -c43fb770003c8d882fd9c1e7d1ecb5f196cba1ab data/hexcasting/recipes/cypher.json -4d5e4a6374731b2d0a90c70a5d489703fd966977 data/hexcasting/advancements/recipes/misc/dye_colorizer_lime.json -0864e8b86bdad0bf9ab2ddeb0cd5a182808b5a0a data/hexcasting/recipes/default_colorizer.json -7d71eb93bbb0856167cf4521283e39f0048078ee data/hexcasting/advancements/recipes/redstone/edified_button.json -72f70637aea1c11683e9ee91d83c2807c6ec33a9 data/hexcasting/recipes/compat/farmersdelight/cutting/akashic_trapdoor.json -1e51cd4f527b3aea4d61d91829e47c191c9c05bb data/hexcasting/recipes/pride_colorizer_gay.json -42b8e462de1d7006de3a7658757377450e773107 data/hexcasting/advancements/recipes/misc/dye_colorizer_blue.json -775560efa36581389c0319435bda035be262ed4f data/hexcasting/advancements/recipes/building_blocks/edified_stairs.json -09096a40275b6c49d4b4e6984869aa43b34712c3 data/hexcasting/recipes/dynamicseal_focus.json -8f515bf8ccea70b3d88845ed83966dc0c66082f6 data/hexcasting/advancements/recipes/tools/staff/oak.json -b29f9d9c14e60ded1148680e2e0ef405b5a3c845 data/hexcasting/advancements/recipes/misc/uuid_colorizer.json -071e5875b13b60aac33bc97e408d2ca710ac5d02 data/hexcasting/advancements/recipes/building_blocks/stonecutting/amethyst_tiles.json -3bf96944a8eed8b8d3f5d96b609297727c078cb7 data/hexcasting/advancements/recipes/misc/dye_colorizer_purple.json -846baaef37844216b57bb9b35e52b1bb6b56b413 data/hexcasting/advancements/recipes/decorations/scroll_small.json -db5ae3a2fda235cf1c83fd83e0026a262e668217 data/hexcasting/advancements/recipes/building_blocks/edified_slab.json -6493676f8ca93a7be8d70e25d69ddad935b3f16b data/hexcasting/advancements/recipes/tools/lens.json -a8d604ba059d54502837809815d3ac9bbcaa89bf data/hexcasting/advancements/recipes/redstone/akashic_bookshelf.json -0aaf55492e850d2bb1ec2f9986406ca61fde4cfd data/hexcasting/recipes/dye_colorizer_lime.json -dcc9bf721dd40724abcc69f1f7e8a1610dbf88f3 data/hexcasting/recipes/compat/farmersdelight/cutting/akashic_door.json -f81053a3269c1b371be3f8057bad4803056ee0f9 data/hexcasting/recipes/dye_colorizer_orange.json -f77518b6993fe8e31de10af286c33ab72c0f9077 data/hexcasting/advancements/recipes/redstone/impetus/empty.json -3b03fdae3896212a0b8b9b3a2d4880d197e67d2d data/hexcasting/recipes/jeweler_hammer.json -d7de5d626fd799a2522af36f0c62c52fe490e6d2 data/hexcasting/recipes/edified_door.json -aa7558ec1baf6070efbe448d886e20e964e33f96 data/hexcasting/advancements/recipes/brainsweep/brainsweep/quench_allay.json -cedc2889c4f327b18755bbe8c3c595d302e2a9d0 data/hexcasting/recipes/decompose_quenched_shard/shard.json -8c52917fc7041c483fb6dfe8d16c90f096f2beaf data/hexcasting/recipes/compat/farmersdelight/cutting/edified_log_amethyst.json -40ed21dc80d39236ca0e6d2cea60861c637cf931 data/hexcasting/advancements/recipes/misc/pride_colorizer_nonbinary.json -ef96ae9709ec931ce6b6af8a539f9bc483236449 data/hexcasting/recipes/scroll_medium.json -61fafd43af83bdca6720d0993ab71f40a8bebd40 data/hexcasting/advancements/recipes/redstone/akashic_connector.json -f08a0aee92b281ae325d907e6fe4a3b03980f2aa data/hexcasting/advancements/recipes/tools/staff/edified.json -7552df3fc726cc4cdaa88aa4823eff6ce069fb75 data/hexcasting/recipes/slate_block_from_slates.json -77369113dc54d1c64b9101861dd8a1930bf1c1c4 data/hexcasting/recipes/edified_wood.json -1ad54df5eaee3d1e810d2c91bd03f626084e30b6 data/hexcasting/recipes/edified_trapdoor.json -ce9d0b976f7cc8ad4a0815bbea6c43115addb90f data/hexcasting/advancements/recipes/building_blocks/scroll_paper.json -af9a260c24e0a65eea321f0dd9dd2fa7d648707f data/hexcasting/advancements/recipes/building_blocks/amethyst_dust_packing.json -923e7cd200518042f11474713eca9ccad126dab7 data/hexcasting/recipes/staff/spruce.json -ad647a2078099344ea7f9836a68e1bf8e8119277 data/hexcasting/advancements/recipes/misc/dye_colorizer_brown.json -0038883bd294cc8a1b324d6782478d5e37b4dbf9 data/hexcasting/advancements/recipes/misc/dye_colorizer_pink.json -170af3c83a45f9550827cc48e4bb5a621d06d685 data/hexcasting/advancements/recipes/misc/pride_colorizer_transgender.json -8815ea5d8d7379062e050adc5736cc579c3bdd9e data/hexcasting/recipes/edified_stairs.json -b6fa898369ac52cdd9d7f91e3b8a2cb881c3829f data/hexcasting/advancements/recipes/decorations/scroll_medium.json -04902d4eca30560bc601a8196d82f74f3fa5b191 data/hexcasting/recipes/dynamicseal_spellbook.json -d6b7a9392320c11866b3f139f97977dc9f55bc47 data/hexcasting/recipes/scroll_small.json -8e48c680b38666c2e7da71fbe4ceddf5d99a5cbc data/hexcasting/advancements/recipes/food/sub_sandwich.json -5e28e2c352366720ce91b73f8c8c38e217f7198d data/hexcasting/recipes/edified_fence_gate.json -004e0694b3bf53140be7df89a4defc255b800619 data/hexcasting/advancements/recipes/tools/focus_rotated.json -faaa9c39dbcdd131c5fbec9ac6a26d6dc5e72053 data/hexcasting/advancements/recipes/misc/dye_colorizer_light_gray.json -55602e415fc1b797439b674050887e9e388558c9 data/hexcasting/advancements/recipes/building_blocks/edified_panel.json -151875101066f7af5788c7a2e1c6b342971a546a data/hexcasting/recipes/compat/farmersdelight/cutting/akashic_wood.json -0bd7c9f4a9bf29c1b63b2f9378f0a7e2f594b7b7 data/hexcasting/recipes/pride_colorizer_nonbinary.json -ea46e570a43cd3ea1cc78c51d9da45d93944730a data/hexcasting/advancements/recipes/redstone/directrix/empty.json -b20be6eb5a8b60567871444e65d773ec9a67ece1 data/hexcasting/recipes/staff/crimson.json -c03c81dc123294472e8bb6f836c319e96f8db4f5 data/hexcasting/advancements/recipes/building_blocks/edified_fence.json -92bdf87687d8823036fae6bd01782c653831286b data/hexcasting/recipes/brainsweep/impetus_look.json -06ca609ba1a32f094cf6edbc989bc9ddaf9d342c data/hexcasting/advancements/recipes/misc/pride_colorizer_genderfluid.json -552c235dc58a46a3e57913c9b9faf3f21abeae32 data/hexcasting/advancements/recipes/building_blocks/stripped_edified_wood.json -c2a0a489967db4064dfbe1ee6367e132665f3c00 data/hexcasting/recipes/edified_slab.json -1a9dd55a24f56a4e9467f1117e0898f7e71ade67 data/hexcasting/advancements/recipes/decorations/amethyst_sconce.json -27dc4a1647f264c45b27f5552fd9403a02853484 data/hexcasting/advancements/recipes/tools/spellbook.json -2eacf53894ae97712dc3874777e29dce0a0e5540 data/hexcasting/advancements/recipes/misc/pride_colorizer_asexual.json -e11aeded7f5d3fdd224627c67661bbd993901703 data/hexcasting/recipes/edified_pressure_plate.json -e691130641b11c0a030a51c71dee0ba356f3b5bd data/hexcasting/recipes/compat/farmersdelight/cutting/edified_log_aventurine.json -7baf0777533737aef68bcac36944943b77138d29 data/hexcasting/recipes/edified_button.json -63189af501442318a90c16d6951e51c0c5d6d4f3 data/hexcasting/recipes/compat/farmersdelight/cutting/edified_log_purple.json -499c5c09e3772989350f9ab3264b8692449a6dea data/hexcasting/advancements/recipes/misc/pride_colorizer_gay.json -b16ff5314d457bc7e9e224e102d1e04ce3a62361 data/hexcasting/recipes/brainsweep/directrix_redstone.json -bd63b845e02ee4b1b9abe168a196335ccbed1ca5 data/hexcasting/recipes/scroll_paper_lantern.json -afb422ad4a918ee0161bf077f09475bb1da2b4eb data/hexcasting/recipes/amethyst_dust_unpacking.json -d47352426739a0fc500a385d820d767a307e1d16 data/hexcasting/advancements/recipes/misc/dye_colorizer_black.json -f0e71ae8c6a9170669f44096a55a875d11497c56 data/hexcasting/recipes/staff/warped.json -78958099bf4337ad281580d90f434b3074ad18c8 data/hexcasting/recipes/pride_colorizer_genderqueer.json +// 1.20.1 2024-10-01T23:18:33.0677934 Hex Casting/Recipes +7166cd4355d11c209bc7749bc862caddcfd795fb data\hexcasting\recipes\dye_colorizer_cyan.json +c2a0a489967db4064dfbe1ee6367e132665f3c00 data\hexcasting\recipes\edified_slab.json +7baf0777533737aef68bcac36944943b77138d29 data\hexcasting\recipes\edified_button.json +3b03fdae3896212a0b8b9b3a2d4880d197e67d2d data\hexcasting\recipes\jeweler_hammer.json +b6fa898369ac52cdd9d7f91e3b8a2cb881c3829f data\hexcasting\advancements\recipes\decorations\scroll_medium.json +8f8773a541bc6a4a6c55a23f4f98b5da4f61a031 data\hexcasting\recipes\scroll_paper.json +06402fb37fe4bb05918d13dbfdb89f4c2b67f3ec data\hexcasting\advancements\recipes\tools\cypher.json +31ec6474ddae967a6c1dadf9be8292d375510364 data\hexcasting\advancements\recipes\building_blocks\edified_tile.json +b94bc4dd4a63db10af86c524ba00eae157c1824b data\hexcasting\advancements\recipes\building_blocks\edified_fence_gate.json +ea87956c49dcfabb0d39af45c016130d258181da data\hexcasting\recipes\staff\birch.json +78958099bf4337ad281580d90f434b3074ad18c8 data\hexcasting\recipes\pride_colorizer_genderqueer.json +e765ee2bd324240e8ed3d625be431de3281f0070 data\hexcasting\recipes\dye_colorizer_gray.json +5f216dbb7b89fd837e2dd73e3ed41c8d412de234 data\hexcasting\advancements\recipes\misc\decompose_quenched_shard\dust.json +0b951ce7b9d1bfb07ae012b12225b595d36c6e66 data\hexcasting\recipes\amethyst_dust_packing.json +a3130e3098e35b75afae4f31996d9ab7468e0bc3 data\hexcasting\advancements\recipes\tools\thought_knot.json +7ca0f9fc6e8ae1ad08ef5c29a0b279b891f7d8d4 data\hexcasting\advancements\recipes\misc\pride_colorizer_aroace.json +417695497a95436186c1a4ed842d7975d754f9eb data\hexcasting\recipes\stripped_edified_wood.json +5a90084c03d6e8424872870c8b65f4771b447f03 data\hexcasting\recipes\brainsweep\budding_amethyst.json +63189af501442318a90c16d6951e51c0c5d6d4f3 data\hexcasting\recipes\compat\farmersdelight\cutting\edified_log_purple.json +daa7b13d5370f4306f8cdf3037fc346e8918950a data\hexcasting\recipes\dye_colorizer_brown.json +2cea013887734cbc4971bcd57e7e4f6a2b25c8e1 data\hexcasting\advancements\recipes\tools\focus.json +f4c56ea7143ce92a0ae0b663310e53644a7309f7 data\hexcasting\advancements\recipes\misc\pride_colorizer_pansexual.json +5d6d73e16a36da5f9df6a7b8ac859181d401766d data\hexcasting\recipes\uuid_colorizer.json +e11aeded7f5d3fdd224627c67661bbd993901703 data\hexcasting\recipes\edified_pressure_plate.json +5889e2df2fb4e1ea29f2590b96bb3aa94961a09a data\hexcasting\recipes\scroll.json +f0e71ae8c6a9170669f44096a55a875d11497c56 data\hexcasting\recipes\staff\warped.json +c1846dd794f5cc5814b8a839291e82512a02ba12 data\hexcasting\advancements\recipes\misc\pride_colorizer_plural.json +a8cab28cffdf495253a320094d202fccc5aeb113 data\hexcasting\advancements\recipes\decorations\ancient_scroll_paper_lantern.json +de38d15e7a91c77df24c1dc954b3e98ee197876f data\hexcasting\recipes\focus.json +71f821f5d24b0bf9ecd860d51e055628fe4af50c data\hexcasting\recipes\edified_panel.json +a9111ff52513200af47b79cf98b2e545699497bb data\hexcasting\advancements\recipes\building_blocks\amethyst_tiles.json +9ea4fe5272ce2241d98f30359f55cfc1936c7b48 data\hexcasting\advancements\recipes\tools\staff\cherry.json +b90ad4cbffc2e3c01671dfe8bda5e42d9b8a685c data\hexcasting\advancements\recipes\tools\staff\crimson.json +5e66982df6a1074c81f381898033b521ca337695 data\hexcasting\recipes\staff\quenched.json +e6a592721234448f2ee7ec402bca10a9b78b4677 data\hexcasting\advancements\recipes\decorations\slate.json +49e706193bb57a957091e419bd0d8aa58135da1f data\hexcasting\recipes\dye_colorizer_green.json +0f2e63a9361d18aac764f6a4a4f13b9b862ac2ee data\hexcasting\recipes\compat\create\crushing\amethyst_shard.json +9269b17eaae3217422352354fc6006c9808b398c data\hexcasting\recipes\dye_colorizer_black.json +45915b542d8070f2502a4047218679b08033b12d data\hexcasting\advancements\recipes\decorations\scroll_paper_lantern.json +f08a0aee92b281ae325d907e6fe4a3b03980f2aa data\hexcasting\advancements\recipes\tools\staff\edified.json +996c8361766377a70e0b5a5caff3076fc6031b0a data\hexcasting\recipes\impetus\empty.json +30352d8ad510768770bb1b2d378959b7a502f825 data\hexcasting\advancements\recipes\brainsweep\brainsweep\impetus_look.json +04902d4eca30560bc601a8196d82f74f3fa5b191 data\hexcasting\recipes\dynamicseal_spellbook.json +b1f8375aaf0d66035dee720ea59605f69fc0a154 data\hexcasting\recipes\edified_fence.json +3608f0ec056f2c5d29a9a89305218497fd2c4383 data\hexcasting\recipes\stonecutting\amethyst_tiles.json +93ed0491548920bc75797d18501c750ef07fe3ea data\hexcasting\advancements\recipes\misc\pride_colorizer_bisexual.json +aa1caae7eba6aede0f179619488e2253b3b723dd data\hexcasting\recipes\focus_rotated.json +61fafd43af83bdca6720d0993ab71f40a8bebd40 data\hexcasting\advancements\recipes\redstone\akashic_connector.json +4aaefc65af5fe69d312247fdda7d983edf8dcd9a data\hexcasting\recipes\pride_colorizer_intersex.json +c2ef04b311251b4eb22320b2f5313c54533a9974 data\hexcasting\advancements\recipes\tools\staff\birch.json +8b7136c206b799a2e394aa02316b0509674ff64f data\hexcasting\advancements\recipes\tools\staff\bamboo.json +7552df3fc726cc4cdaa88aa4823eff6ce069fb75 data\hexcasting\recipes\slate_block_from_slates.json +b84c113ef5321c9df9ac9080de03e8d8639feab2 data\hexcasting\advancements\recipes\misc\pride_colorizer_genderqueer.json +b7084f131b0cdb9c2c698a3c5b3450d69e788d6e data\hexcasting\recipes\dye_colorizer_yellow.json +6e2dc32f975d987b8dfd329507334f647bceadc0 data\hexcasting\advancements\recipes\tools\staff\mangrove.json +b10d590e918e35b16578a8b739a1c4e7e2202e16 data\hexcasting\advancements\recipes\misc\dye_colorizer_cyan.json +dcc9bf721dd40724abcc69f1f7e8a1610dbf88f3 data\hexcasting\recipes\compat\farmersdelight\cutting\akashic_door.json +0b172aef920da7ba63fe152903ce005c1f5df5f1 data\hexcasting\recipes\staff\acacia.json +203b7035125390abb4ed77b3a4dca8f8f8f57bc5 data\hexcasting\recipes\dye_colorizer_light_gray.json +1e51cd4f527b3aea4d61d91829e47c191c9c05bb data\hexcasting\recipes\pride_colorizer_gay.json +12bd3d04c791ef16aad5e992f038d6726229a436 data\hexcasting\advancements\recipes\tools\artifact.json +24c244e53c7e47b85845d2ee36b1665410cf495a data\hexcasting\recipes\edified_planks.json +846baaef37844216b57bb9b35e52b1bb6b56b413 data\hexcasting\advancements\recipes\decorations\scroll_small.json +f80dbf59957be175fbcd63224005e09c4cd1a122 data\hexcasting\recipes\compat\farmersdelight\cutting\edified_log_citrine.json +8bea75fdc5e64c464dcf5f85166e767ff44e6dc2 data\hexcasting\advancements\recipes\misc\pride_colorizer_lesbian.json +fd7c8325fcaa6a718e90c09251b447fb365523d4 data\hexcasting\recipes\pride_colorizer_demiboy.json +cedc2889c4f327b18755bbe8c3c595d302e2a9d0 data\hexcasting\recipes\decompose_quenched_shard\shard.json +42b8e462de1d7006de3a7658757377450e773107 data\hexcasting\advancements\recipes\misc\dye_colorizer_blue.json +a0b87b1b21506708d09c9295b7afc13de6b1fce6 data\hexcasting\recipes\pride_colorizer_aromantic.json +441f336edb635e5d8c2a7183906fed1c501f06fd data\hexcasting\recipes\pride_colorizer_bisexual.json +7aa3bf4a3d6fb92743b29dfe89d50537fefc0db9 data\hexcasting\advancements\recipes\misc\pride_colorizer_intersex.json +ea46e570a43cd3ea1cc78c51d9da45d93944730a data\hexcasting\advancements\recipes\redstone\directrix\empty.json +e536791d0c6fb48206e6e30d56879eaf0a9e4bd7 data\hexcasting\recipes\akashic_bookshelf.json +8e48c680b38666c2e7da71fbe4ceddf5d99a5cbc data\hexcasting\advancements\recipes\food\sub_sandwich.json +a1f9df0537c0ef33a1164cf94e8ff4b1094f889f data\hexcasting\advancements\recipes\tools\staff\warped.json +963d87d2738686e5398a178b8b369228ff067403 data\hexcasting\recipes\spellbook.json +09096a40275b6c49d4b4e6984869aa43b34712c3 data\hexcasting\recipes\dynamicseal_focus.json +f81053a3269c1b371be3f8057bad4803056ee0f9 data\hexcasting\recipes\dye_colorizer_orange.json +c4b985635c3b1a519d7a83da65daba5bdd3a5f59 data\hexcasting\advancements\recipes\decorations\ageing_scroll_paper_lantern.json +2c56c267e23e75d5a3b9358d424d69642e001b50 data\hexcasting\recipes\decompose_quenched_shard\dust.json +98c0843e6a83b91820f1c720e206295eec20ff95 data\hexcasting\recipes\ancient_scroll_paper.json +7f2f29981df2ca4464ee0250180e670f5331f65b data\hexcasting\recipes\dye_colorizer_pink.json +c03c81dc123294472e8bb6f836c319e96f8db4f5 data\hexcasting\advancements\recipes\building_blocks\edified_fence.json +2003fed3aa4eb622b6b07a9e65946fb40be14420 data\hexcasting\advancements\recipes\brainsweep\brainsweep\impetus_rightclick.json +0864e8b86bdad0bf9ab2ddeb0cd5a182808b5a0a data\hexcasting\recipes\default_colorizer.json +6493676f8ca93a7be8d70e25d69ddad935b3f16b data\hexcasting\advancements\recipes\tools\lens.json +7d71eb93bbb0856167cf4521283e39f0048078ee data\hexcasting\advancements\recipes\redstone\edified_button.json +f77518b6993fe8e31de10af286c33ab72c0f9077 data\hexcasting\advancements\recipes\redstone\impetus\empty.json +0ead307e47242ba140584f6bd20088a1fa7c2909 data\hexcasting\recipes\directrix\empty.json +d7de5d626fd799a2522af36f0c62c52fe490e6d2 data\hexcasting\recipes\edified_door.json +5e28e2c352366720ce91b73f8c8c38e217f7198d data\hexcasting\recipes\edified_fence_gate.json +0038883bd294cc8a1b324d6782478d5e37b4dbf9 data\hexcasting\advancements\recipes\misc\dye_colorizer_pink.json +aa7558ec1baf6070efbe448d886e20e964e33f96 data\hexcasting\advancements\recipes\brainsweep\brainsweep\quench_allay.json +648f1862fde1dd8ade80b2991b8c8e3991389e95 data\hexcasting\recipes\dye_colorizer_light_blue.json +b29f9d9c14e60ded1148680e2e0ef405b5a3c845 data\hexcasting\advancements\recipes\misc\uuid_colorizer.json +c8f2ad363e4d20054f4e56fde02c8775a45a7169 data\hexcasting\recipes\artifact.json +641d8c38b8109665314fccbebd9068ba10b04118 data\hexcasting\advancements\recipes\misc\dye_colorizer_gray.json +7e1a5a873d655e0efba80f22ae9b1de4f248e67a data\hexcasting\advancements\recipes\misc\decompose_quenched_shard\shard.json +fb852d8e4bcfa7b75f41a6ac7dc1e76b00d95fb1 data\hexcasting\advancements\recipes\misc\dye_colorizer_red.json +77369113dc54d1c64b9101861dd8a1930bf1c1c4 data\hexcasting\recipes\edified_wood.json +8f515bf8ccea70b3d88845ed83966dc0c66082f6 data\hexcasting\advancements\recipes\tools\staff\oak.json +552c235dc58a46a3e57913c9b9faf3f21abeae32 data\hexcasting\advancements\recipes\building_blocks\stripped_edified_wood.json +eb9ebf77f0daa32f665a60888fcda19c940f0b2f data\hexcasting\advancements\recipes\misc\pride_colorizer_demigirl.json +151875101066f7af5788c7a2e1c6b342971a546a data\hexcasting\recipes\compat\farmersdelight\cutting\akashic_wood.json +41a570f970c9af8229cb1140a11a5220fac00957 data\hexcasting\advancements\recipes\tools\staff\spruce.json +1b570b35288be9f6faab1536d6e45cb52eb088c0 data\hexcasting\advancements\recipes\tools\staff\dark_oak.json +494aa470790ae46baebbf24ee5b76f5885c1af1a data\hexcasting\recipes\ageing_scroll_paper_lantern.json +e9166f40c8797cdbf3d8062dfa35c74f850f1000 data\hexcasting\advancements\recipes\misc\dye_colorizer_white.json +72f70637aea1c11683e9ee91d83c2807c6ec33a9 data\hexcasting\recipes\compat\farmersdelight\cutting\akashic_trapdoor.json +ed5c690324e3d9b55599f00f078ae225072a2e7f data\hexcasting\recipes\brainsweep\impetus_rightclick.json +0e792d49c81d2164e827d1bdedaa0fa358dfc437 data\hexcasting\advancements\recipes\misc\pride_colorizer_aromantic.json +0654e70ed1ed8be20ae3dd9f4955cd14f9fa40d0 data\hexcasting\advancements\recipes\tools\staff\jungle.json +2eacf53894ae97712dc3874777e29dce0a0e5540 data\hexcasting\advancements\recipes\misc\pride_colorizer_asexual.json +c43fb770003c8d882fd9c1e7d1ecb5f196cba1ab data\hexcasting\recipes\cypher.json +ea63e49709bd80cb9f4cd1fe13e9bd0281101c9a data\hexcasting\recipes\slate.json +838b91c33a72a58aa286607eaaa17cdd6b4c90ba data\hexcasting\recipes\amethyst_sconce.json +c6228d72ca800a7dd336e82bbb9b4f20f89de29d data\hexcasting\advancements\recipes\redstone\edified_pressure_plate.json +b20be6eb5a8b60567871444e65d773ec9a67ece1 data\hexcasting\recipes\staff\crimson.json +1093cccc6b1c45eb91f7c1680ef575a7bffb2744 data\hexcasting\advancements\recipes\building_blocks\edified_planks.json +97062771a426f6e4b9e3bfd6daa62b1d4b3c7039 data\hexcasting\recipes\abacus.json +af8fe74b624df4a31727347b9826614a66092b0a data\hexcasting\advancements\recipes\misc\pride_colorizer_agender.json +c1541738df1ee41c362ad3b9c3a9f0e181bd5c62 data\hexcasting\recipes\pride_colorizer_plural.json +bc8fe4d2f55fe119b0b146a71782a3d4788380b1 data\create\recipes\crushing\amethyst_block.json +d47352426739a0fc500a385d820d767a307e1d16 data\hexcasting\advancements\recipes\misc\dye_colorizer_black.json +55602e415fc1b797439b674050887e9e388558c9 data\hexcasting\advancements\recipes\building_blocks\edified_panel.json +72447ac69a0d85f91064180d3c852040a9e33832 data\hexcasting\recipes\pride_colorizer_asexual.json +af9a260c24e0a65eea321f0dd9dd2fa7d648707f data\hexcasting\advancements\recipes\building_blocks\amethyst_dust_packing.json +7c479398bbc7185a2c3efd568ad266d8109245bf data\hexcasting\advancements\recipes\redstone\edified_door.json +4d5e4a6374731b2d0a90c70a5d489703fd966977 data\hexcasting\advancements\recipes\misc\dye_colorizer_lime.json +fd2f25b0a71806c96af5a307fad76f66de6210a4 data\hexcasting\advancements\recipes\building_blocks\slate_block.json +4680e9dafcf9b60b3485609519d66eefcfd539bc data\hexcasting\recipes\staff\dark_oak.json +b16ff5314d457bc7e9e224e102d1e04ce3a62361 data\hexcasting\recipes\brainsweep\directrix_redstone.json +946cde51bbfc2af344b078f6b39389ffc44462f4 data\hexcasting\advancements\recipes\brainsweep\brainsweep\impetus_storedplayer.json +40ed21dc80d39236ca0e6d2cea60861c637cf931 data\hexcasting\advancements\recipes\misc\pride_colorizer_nonbinary.json +71d38559bf455ea343ac0237a57db4d3f0833a7c data\hexcasting\advancements\recipes\misc\dye_colorizer_magenta.json +9b7c5220fbaf3e84fa9e81eae322eed5d37b22d3 data\hexcasting\recipes\pride_colorizer_transgender.json +157ee5fba985bbd01a87f44578890dab5489a8e5 data\hexcasting\advancements\recipes\misc\dye_colorizer_green.json +004e0694b3bf53140be7df89a4defc255b800619 data\hexcasting\advancements\recipes\tools\focus_rotated.json +8f7b81add0153ad94900acc66cd8174ae7115f64 data\hexcasting\advancements\recipes\building_blocks\slate_block_from_slates.json +f8ee073c1c03f1c11147e4801eeba1f86e5459ba data\hexcasting\recipes\dye_colorizer_blue.json +1a0d55e6824c078453c1d44e885a1c51ba707a41 data\hexcasting\recipes\dye_colorizer_white.json +14f3b217e150efbbff329d67aec96f818a1da99c data\hexcasting\recipes\dye_colorizer_purple.json +2b64261bd4aefdc55d35400f25835434f88856cf data\hexcasting\recipes\amethyst_tiles.json +b6720c1c73455ad817bac9b5ca2ca045c5c4050c data\hexcasting\recipes\pride_colorizer_agender.json +c3f7b03fe184ed5e54a8ae06d130adf507b7683d data\hexcasting\recipes\staff\bamboo.json +54335e0004423899ad37763a1d8456cc0a6e72a7 data\hexcasting\advancements\recipes\misc\decompose_quenched_shard\charged.json +ae88fcdecbfbdd0a0fe778467421a3b32d7ed735 data\create\recipes\crushing\amethyst_cluster.json +f64fa00d85a9abb24e89b0d2c9f818001371f5e6 data\hexcasting\recipes\slate_block.json +bd63b845e02ee4b1b9abe168a196335ccbed1ca5 data\hexcasting\recipes\scroll_paper_lantern.json +505eb9192df0b48867e58e09ce36b2259dc6d3e8 data\hexcasting\advancements\recipes\decorations\scroll.json +2a2f60fb0f63ee278b74c418acf04575304c521f data\hexcasting\advancements\recipes\tools\jeweler_hammer.json +862f1a61a296a834df8a93dbd5a6cdfa2df15721 data\hexcasting\advancements\recipes\tools\staff\acacia.json +5401828f85e709b5817ecc8464dc63e536a730dc data\hexcasting\recipes\staff\cherry.json +ee5db13cbb33d9c62bcb1eb645e2c4bea97ad44a data\hexcasting\advancements\recipes\building_blocks\amethyst_dust_unpacking.json +1ad54df5eaee3d1e810d2c91bd03f626084e30b6 data\hexcasting\recipes\edified_trapdoor.json +06ca609ba1a32f094cf6edbc989bc9ddaf9d342c data\hexcasting\advancements\recipes\misc\pride_colorizer_genderfluid.json +27dc4a1647f264c45b27f5552fd9403a02853484 data\hexcasting\advancements\recipes\tools\spellbook.json +b5946314683e5a823b577a18d13fb437a35aafd5 data\hexcasting\recipes\decompose_quenched_shard\charged.json +1d1e73244fb3da633d8a5f84bad93c6022a94368 data\hexcasting\advancements\recipes\misc\pride_colorizer_demiboy.json +071e5875b13b60aac33bc97e408d2ca710ac5d02 data\hexcasting\advancements\recipes\building_blocks\stonecutting\amethyst_tiles.json +b624d103d944a8a1d4d8a9e85c198a5492b476f8 data\hexcasting\advancements\recipes\redstone\edified_trapdoor.json +51b047601368a103be166d907633b196d2d8a4e8 data\hexcasting\recipes\compat\farmersdelight\cutting\edified_log.json +a8d604ba059d54502837809815d3ac9bbcaa89bf data\hexcasting\advancements\recipes\redstone\akashic_bookshelf.json +664ce1a38c9b1c9ec21b7e078631e181fc0b2498 data\hexcasting\recipes\staff\edified.json +a85cfbd7988f5df0b18d160591605aea8e6808d2 data\hexcasting\recipes\trinket.json +4a803e049915fd3c7144155ae3a1b05a917ea290 data\hexcasting\recipes\pride_colorizer_pansexual.json +b300f7729e75614fce412457f6717686680f81da data\hexcasting\recipes\sub_sandwich.json +170af3c83a45f9550827cc48e4bb5a621d06d685 data\hexcasting\advancements\recipes\misc\pride_colorizer_transgender.json +fb486df96798724da2fcc0df5706f19bc1ff94dc data\hexcasting\advancements\recipes\misc\dye_colorizer_light_blue.json +903cbe4d4c4e5abcd5e006f9d0237e8c596228ba data\hexcasting\recipes\edified_tile.json +db5ae3a2fda235cf1c83fd83e0026a262e668217 data\hexcasting\advancements\recipes\building_blocks\edified_slab.json +5fab1b9c93304a53a4c305b511704458e4593444 data\hexcasting\recipes\pride_colorizer_demigirl.json +d6b7a9392320c11866b3f139f97977dc9f55bc47 data\hexcasting\recipes\scroll_small.json +7522be58b09554a3f1a54d5b2343c3eab01447a3 data\hexcasting\recipes\dye_colorizer_magenta.json +233aeedc73173427e7b2287772a4f914f97b072c data\hexcasting\recipes\dye_colorizer_red.json +68ab70e0b4e432a3492767c5597ecd836f106714 data\hexcasting\advancements\recipes\tools\staff\mindsplice.json +1b092acfc3115702c74e141492e649d58512f259 data\hexcasting\recipes\staff\oak.json +410bfde90cb977db3f13814e94484fa11fca7cfc data\hexcasting\recipes\thought_knot.json +a72a0fcc0f3a81d31b30a7a626aef537796ca73b data\hexcasting\advancements\recipes\tools\staff\quenched.json +23eff6111b0385b66d3ad5fbabfc625f426517a6 data\hexcasting\advancements\recipes\brainsweep\brainsweep\directrix_redstone.json +bc729ac7cf84d29a99cd34d50c152c0b9d20bd7a data\hexcasting\advancements\recipes\brainsweep\brainsweep\akashic_record.json +011f8daf15148d4b77686c6d382d8f5c288a333d data\hexcasting\advancements\recipes\building_blocks\ancient_scroll_paper.json +92bdf87687d8823036fae6bd01782c653831286b data\hexcasting\recipes\brainsweep\impetus_look.json +f482a4349786388cc8f11d5550548f7d60265438 data\hexcasting\recipes\staff\mangrove.json +8c52917fc7041c483fb6dfe8d16c90f096f2beaf data\hexcasting\recipes\compat\farmersdelight\cutting\edified_log_amethyst.json +5e98cec2084f0cfbb959c3ec39bd85a3369f443b data\hexcasting\advancements\recipes\tools\abacus.json +f1bae034d27d218bf262a8c777b787d232489f16 data\hexcasting\recipes\lens.json +ef96ae9709ec931ce6b6af8a539f9bc483236449 data\hexcasting\recipes\scroll_medium.json +4d941fc399c6b7a470513a572ecd88982823da84 data\hexcasting\advancements\recipes\building_blocks\edified_wood.json +b6e762c198b9632defd7f8b11287702abecd681d data\hexcasting\recipes\staff\mindsplice.json +e691130641b11c0a030a51c71dee0ba356f3b5bd data\hexcasting\recipes\compat\farmersdelight\cutting\edified_log_aventurine.json +ce9d0b976f7cc8ad4a0815bbea6c43115addb90f data\hexcasting\advancements\recipes\building_blocks\scroll_paper.json +faaa9c39dbcdd131c5fbec9ac6a26d6dc5e72053 data\hexcasting\advancements\recipes\misc\dye_colorizer_light_gray.json +e0609202271e402d8ae58e4f8eaf11dcdda10a9e data\hexcasting\recipes\brainsweep\akashic_record.json +2aa7d74e29a7c5ee4f1b8835cf7c6109eed81d77 data\hexcasting\recipes\brainsweep\quench_allay.json +4003f297be29810cebde4995fb2838c2c68a25ea data\hexcasting\recipes\pride_colorizer_lesbian.json +775560efa36581389c0319435bda035be262ed4f data\hexcasting\advancements\recipes\building_blocks\edified_stairs.json +f347f4ce869207e62a7887df1252505a3432e12a data\hexcasting\recipes\pride_colorizer_genderfluid.json +6f2634e5588aede8e29157ecc859652d8a9f4065 data\hexcasting\advancements\recipes\misc\dye_colorizer_orange.json +0bd7c9f4a9bf29c1b63b2f9378f0a7e2f594b7b7 data\hexcasting\recipes\pride_colorizer_nonbinary.json +a366ea3750adc0d336ab8f318c40baed3f9c3eb7 data\hexcasting\recipes\brainsweep\impetus_storedplayer.json +36d26f34d0405ff2d1e728e5b5174502686e3590 data\hexcasting\advancements\recipes\brainsweep\brainsweep\budding_amethyst.json +55ea553a96e1d6a54385890f7c48fe7b2bed6871 data\hexcasting\advancements\recipes\tools\trinket.json +499c5c09e3772989350f9ab3264b8692449a6dea data\hexcasting\advancements\recipes\misc\pride_colorizer_gay.json +afb422ad4a918ee0161bf077f09475bb1da2b4eb data\hexcasting\recipes\amethyst_dust_unpacking.json +8c043c7f6a7911b67324e2fd42f0b3b19a792af3 data\hexcasting\recipes\ancient_scroll_paper_lantern.json +1a9dd55a24f56a4e9467f1117e0898f7e71ade67 data\hexcasting\advancements\recipes\decorations\amethyst_sconce.json +2fff80cd3dabd2bc1744eecd72b2364b0f91c7c1 data\hexcasting\advancements\recipes\misc\dye_colorizer_yellow.json +61e53f02baefd31308e99407d56403dfc18e36e1 data\hexcasting\recipes\akashic_connector.json +3bf96944a8eed8b8d3f5d96b609297727c078cb7 data\hexcasting\advancements\recipes\misc\dye_colorizer_purple.json +2c292e12b5e85b1701740c222e5c5465799ad1dc data\hexcasting\recipes\pride_colorizer_aroace.json +ad647a2078099344ea7f9836a68e1bf8e8119277 data\hexcasting\advancements\recipes\misc\dye_colorizer_brown.json +17a1adf747b99848381ca8e7c5e2cd9dd96c014f data\hexcasting\advancements\recipes\misc\default_colorizer.json +0aaf55492e850d2bb1ec2f9986406ca61fde4cfd data\hexcasting\recipes\dye_colorizer_lime.json +8815ea5d8d7379062e050adc5736cc579c3bdd9e data\hexcasting\recipes\edified_stairs.json +923e7cd200518042f11474713eca9ccad126dab7 data\hexcasting\recipes\staff\spruce.json +095aeb2882c6849f10fb6536e7c780790778e5e7 data\hexcasting\recipes\staff\jungle.json diff --git a/Fabric/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json b/Fabric/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json index afdfee5143..76ab3105e8 100644 --- a/Fabric/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json +++ b/Fabric/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json @@ -3,6 +3,7 @@ "values": [ "hexcasting:amethyst_dust", "minecraft:amethyst_shard", - "hexcasting:charged_amethyst" + "hexcasting:charged_amethyst", + "hexcasting:creative_unlocker" ] } \ No newline at end of file diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java index 4680f8c1a1..a49ab760f3 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java @@ -18,6 +18,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.Level; +import java.util.ArrayList; import java.util.List; import static at.petrak.hexcasting.api.mod.HexConfig.anyMatchResLoc; @@ -199,7 +200,12 @@ public static final class Server implements HexConfig.ServerConfigAccess, Config // TODO: hook this up to the config, change Jankery, test, also test scroll injects on fabric @ConfigEntry.Gui.Tooltip - private List loreInjections = HexLootHandler.DEFAULT_LORE_INJECTS; + private List loreInjectionsRaw = HexLootHandler.DEFAULT_LORE_INJECTS + .stream() + .map(ResourceLocation::toString) + .toList(); + @ConfigEntry.Gui.Excluded + private transient List loreInjections; @ConfigEntry.Gui.Tooltip private double loreChance = HexLootHandler.DEFAULT_LORE_CHANCE; @@ -222,6 +228,16 @@ public void validatePostLoad() throws ValidationException { throw new ValidationException("Bad parsing of scroll injects", e); } + this.loreInjections = new ArrayList<>(); + try { + for (var table : this.loreInjectionsRaw) { + ResourceLocation loc = new ResourceLocation(table); + this.loreInjections.add(loc); + } + } catch (Exception e) { + throw new ValidationException("Bad parsing of lore injects", e); + } + this.loreChance = Mth.clamp(this.loreChance, 0.0, 1.0); } diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java index 3f27fff2ea..da699de7a9 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java @@ -1,19 +1,18 @@ package at.petrak.hexcasting.fabric.interop.emi; -import at.petrak.hexcasting.api.casting.math.HexCoord; +import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.api.utils.HexUtils; -import at.petrak.hexcasting.interop.utils.PatternDrawingUtil; -import at.petrak.hexcasting.interop.utils.PatternEntry; +import at.petrak.hexcasting.client.render.PatternColors; +import at.petrak.hexcasting.client.render.PatternRenderer; +import at.petrak.hexcasting.client.render.PatternSettings; +import at.petrak.hexcasting.client.render.PatternSettings.PositionSettings; +import at.petrak.hexcasting.client.render.PatternSettings.StrokeSettings; +import at.petrak.hexcasting.client.render.PatternSettings.ZappySettings; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; import dev.emi.emi.api.render.EmiRenderable; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec2; - -import java.util.List; public class PatternRendererEMI implements EmiRenderable { @@ -25,19 +24,21 @@ public class PatternRendererEMI implements EmiRenderable { private boolean strokeOrder; - private final List patterns; - private final List pathfinderDots; + private final HexPattern pat; + private PatternSettings patSets; public PatternRendererEMI(ResourceLocation pattern, int w, int h) { var regi = IXplatAbstractions.INSTANCE.getActionRegistry(); var entry = regi.get(pattern); this.strokeOrder = HexUtils.isOfTag(regi, pattern, HexTags.Actions.PER_WORLD_PATTERN); - var data = PatternDrawingUtil.loadPatterns(List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin())), 0f, - 1f); - this.patterns = data.patterns(); - this.pathfinderDots = data.pathfinderDots(); + this.pat = entry.prototype(); this.width = w; this.height = h; + this.patSets = new PatternSettings("pattern_drawable_" + w + "_" + h, + new PositionSettings(width, height, 0, 0, + PatternSettings.AxisAlignment.CENTER_FIT, PatternSettings.AxisAlignment.CENTER_FIT, Math.max(width, height), 0, 0), + StrokeSettings.fromStroke(0.075 * Math.min(width, height)), + ZappySettings.READABLE); } public PatternRendererEMI shift(int x, int y) { @@ -47,6 +48,13 @@ public PatternRendererEMI shift(int x, int y) { } public PatternRendererEMI strokeOrder(boolean order) { + if(order != strokeOrder){ + patSets = new PatternSettings("pattern_drawable_" + width + "_" + height + (order ? "" : "nostroke"), + patSets.posSets, + patSets.strokeSets, + order ? ZappySettings.READABLE : ZappySettings.STATIC + ); + } strokeOrder = order; return this; } @@ -55,10 +63,11 @@ public PatternRendererEMI strokeOrder(boolean order) { public void render(GuiGraphics graphics, int x, int y, float delta) { var ps = graphics.pose(); ps.pushPose(); - ps.translate(xOffset + x - 0.5f + width / 2f, yOffset + y + 1 + height / 2f, 0); - ps.scale(width / 64f, height / 64f, 1f); - PatternDrawingUtil.drawPattern(graphics, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, - 0xff_333030, 0xff_191818, 0xc8_0c0a0c, 0x80_666363); + ps.translate(xOffset + x, yOffset + y + 1, 0); + PatternRenderer.renderPattern(pat, graphics.pose(), patSets, + new PatternColors(0xc8_0c0a0c, 0xff_333030).withDotColors(0x80_666363, 0), + 0, 10 + ); ps.popPose(); } } diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 4468af2380..85a8965ace 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -57,7 +57,8 @@ "cardinal-components-block": "~5.2.1", "paucal": ">=0.6.0-pre <0.7.0", "cloth-config": "11.1.*", - "patchouli": ">=1.20.1-80" + "patchouli": ">=1.20.1-80", + "inline": ">=1.20.1-1.0.1" }, "suggests": { "pehkui": ">=3.7.6", diff --git a/Forge/build.gradle b/Forge/build.gradle index c1942d6013..78be55d9aa 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -59,6 +59,8 @@ repositories { url = 'https://thedarkcolour.github.io/KotlinForForge/' content { includeGroup "thedarkcolour" } } + + maven { url "https://maven.shedaniel.me/" } } dependencies { @@ -80,6 +82,11 @@ dependencies { implementation fg.deobf("top.theillusivec4.caelus:caelus-forge:$caelusVersion") + implementation fg.deobf("com.samsthenerd.inline:inline-forge:$minecraftVersion-$inlineVersion") + + // needed for inline to run + runtimeOnly fg.deobf("me.shedaniel.cloth:cloth-config-forge:$clothConfigVersion") + // Optional interop compileOnly fg.deobf("mezz.jei:jei-$minecraftVersion-common-api:$jeiVersion") diff --git a/Forge/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 b/Forge/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 index e6f171cf36..664e17383b 100644 --- a/Forge/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 +++ b/Forge/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 @@ -1,11 +1,11 @@ -// 1.20.1 2023-12-24T17:58:56.8930247 Tags for minecraft:item mod id vanilla +// 1.20.1 2024-10-01T23:18:04.2255382 Tags for minecraft:item mod id vanilla 2f5c5bd21580004c998765215166adaa72e0d96b data/forge/tags/items/dusts/amethyst.json 873bab891e0827973ebfe9fedd352c95778d7fbe data/forge/tags/items/gems.json c5aac196bf97183b43d794c6aac8e206f4b71e37 data/hexcasting/tags/items/brainswept_circle_components.json abaec2d0102fef5865ac638cf7c528a4d5b2a69b data/hexcasting/tags/items/directrices.json 7e27f819889d2f0bca863b1cdb6d7d640ea21986 data/hexcasting/tags/items/edified_logs.json 86828f8056bfdfdd2aff10d7a9dbc6c269c25b8a data/hexcasting/tags/items/edified_planks.json -03bd3a58ae7367d6a21eb3acbbd70fe65a41b8f6 data/hexcasting/tags/items/grants_root_advancement.json +5b19052261719f95e2faedcb483d4c338e349524 data/hexcasting/tags/items/grants_root_advancement.json 7f71f33b0bc9fde24deef080ab64707df38adfd6 data/hexcasting/tags/items/impeti.json 7f7d5f6cc9b5cfb39d240fc901c4ae2d2037ec14 data/hexcasting/tags/items/phial_base.json d878c230cd5cb1b54fbe6e53f3ef71379d080c6f data/hexcasting/tags/items/seal_materials.json diff --git a/Forge/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json b/Forge/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json index f5c26b0762..1f7070a707 100644 --- a/Forge/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json +++ b/Forge/src/generated/resources/data/hexcasting/tags/items/grants_root_advancement.json @@ -2,6 +2,7 @@ "values": [ "hexcasting:amethyst_dust", "minecraft:amethyst_shard", - "hexcasting:charged_amethyst" + "hexcasting:charged_amethyst", + "hexcasting:creative_unlocker" ] } \ No newline at end of file diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java index 62417e5e28..bf96781a00 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java @@ -1,40 +1,40 @@ package at.petrak.hexcasting.forge.interop.jei; -import at.petrak.hexcasting.api.casting.math.HexCoord; +import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.api.utils.HexUtils; -import at.petrak.hexcasting.interop.utils.PatternDrawingUtil; -import at.petrak.hexcasting.interop.utils.PatternEntry; +import at.petrak.hexcasting.client.render.PatternColors; +import at.petrak.hexcasting.client.render.PatternRenderer; +import at.petrak.hexcasting.client.render.PatternSettings; +import at.petrak.hexcasting.client.render.PatternSettings.PositionSettings; +import at.petrak.hexcasting.client.render.PatternSettings.StrokeSettings; +import at.petrak.hexcasting.client.render.PatternSettings.ZappySettings; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import com.mojang.datafixers.util.Pair; import mezz.jei.api.gui.drawable.IDrawable; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec2; - -import java.util.List; public class PatternDrawable implements IDrawable { private final int width; private final int height; private boolean strokeOrder; + private final HexPattern pat; - private final List patterns; - private final List pathfinderDots; + private PatternSettings patSets; public PatternDrawable(ResourceLocation pattern, int w, int h) { var regi = IXplatAbstractions.INSTANCE.getActionRegistry(); var entry = regi.get(pattern); this.strokeOrder = !HexUtils.isOfTag(regi, pattern, HexTags.Actions.PER_WORLD_PATTERN); - var data = PatternDrawingUtil.loadPatterns( - List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin())), - 0f, - 1f); - this.patterns = data.patterns(); - this.pathfinderDots = data.pathfinderDots(); + this.pat = entry.prototype(); this.width = w; this.height = h; + this.patSets = new PatternSettings("pattern_drawable_" + w + "_" + h, + new PositionSettings(width, height, 0, 0, + PatternSettings.AxisAlignment.CENTER_FIT, PatternSettings.AxisAlignment.CENTER_FIT, Math.max(width, height), 0, 0), + StrokeSettings.fromStroke(0.075 * Math.min(width, height)), + ZappySettings.READABLE); } @Override @@ -48,18 +48,26 @@ public int getHeight() { } public PatternDrawable strokeOrder(boolean order) { + if(order != strokeOrder){ + patSets = new PatternSettings("pattern_drawable_" + width + "_" + height + (order ? "" : "nostroke"), + patSets.posSets, + patSets.strokeSets, + order ? ZappySettings.READABLE : ZappySettings.STATIC + ); + } strokeOrder = order; return this; } @Override - public void draw(GuiGraphics guiGraphics, int xOffset, int yOffset) { - var ps = guiGraphics.pose(); + public void draw(GuiGraphics graphics, int x, int y) { + var ps = graphics.pose(); ps.pushPose(); - ps.translate(xOffset - 0.5f + width / 2f, yOffset + height / 2f, 0); - ps.scale(width / 64f, height / 64f, 1f); - PatternDrawingUtil.drawPattern(guiGraphics, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, - 0xff_333030, 0xff_191818, 0xc8_0c0a0c, 0x80_666363); + ps.translate(x, y + 1, 0); + PatternRenderer.renderPattern(pat, graphics.pose(), patSets, + new PatternColors(0xc8_0c0a0c, 0xff_333030).withDotColors(0x80_666363, 0), + 0, 10 + ); ps.popPose(); } } diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index 252e3f9273..d3d478bb21 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -48,3 +48,10 @@ mandatory = true versionRange = "[3.1.0+1.20,)" ordering = "NONE" side = "BOTH" + +[[dependencies.hexcasting]] +modId = "inline" +mandatory = true +versionRange = "[1.20.1-1.0.1,)" +ordering = "NONE" +side = "BOTH" \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 88d13e374a..015fb53ab5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,6 @@ patchouliVersion=83 jeiVersion=15.0.0.12 pehkuiVersion=3.7.7 + +inlineVersion=1.0.1 +clothConfigVersion=11.1.106 \ No newline at end of file