diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 222323b25..067cba4e0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,6 +14,8 @@ concurrency: env: MODRINTH_PROJECT_ID: z3Aj5eOl CURSEFORGE_PROJECT_ID: '1592400' + MODRINTH_DEPENDENCIES: 'MhqIcygN(incompatible)' + CURSEFORGE_DEPENDENCIES: '421463(incompatible)' PUBLISH_DELAY_SECONDS: '60' jobs: @@ -175,10 +177,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -202,10 +206,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -229,10 +235,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -256,10 +264,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -283,10 +293,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -310,10 +322,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} @@ -337,10 +351,12 @@ jobs: modrinth-id: ${{ env.MODRINTH_PROJECT_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-changelog: ${{ github.event.release.body }} + modrinth-dependencies: ${{ env.MODRINTH_DEPENDENCIES }} curseforge-id: ${{ env.CURSEFORGE_PROJECT_ID }} curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} curseforge-changelog: ${{ github.event.release.body }} + curseforge-dependencies: ${{ env.CURSEFORGE_DEPENDENCIES }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.event.release.tag_name }} diff --git a/build-all.sh b/build-all.sh old mode 100644 new mode 100755 diff --git a/build-config/materialized-baselines/26.1.2-neoforge.json b/build-config/materialized-baselines/26.1.2-neoforge.json index 34f737130..1c17b668b 100644 --- a/build-config/materialized-baselines/26.1.2-neoforge.json +++ b/build-config/materialized-baselines/26.1.2-neoforge.json @@ -731,7 +731,7 @@ "src/main/java/buildcraft/lib/client/model/ModelItemSimple.java": "302900ed8a0885342b7565247b8851babb774809d7963e047b5c0be0fd2a831b", "src/main/java/buildcraft/lib/client/model/ModelPluggableItem.java": "659ef6ae89fede46746d2e98d9c5791704008fada417834b52ab515ef1b8400f", "src/main/java/buildcraft/lib/client/model/ModelUtil.java": "46fe239a6eedbe3f7ba833dc46087aca2aa75e46cd0a2e3ff379a6d0d9e59396", - "src/main/java/buildcraft/lib/client/model/MutableQuad.java": "10177c465c344b3599c821382d7a344f634b84f4e885712b91df21ea00b9638c", + "src/main/java/buildcraft/lib/client/model/MutableQuad.java": "830f4db888a195a63fa12d15301db414eb778a464ca404e8cb326fae07be61e6", "src/main/java/buildcraft/lib/client/model/MutableVertex.java": "4ed3d5ec9f237d631293f5a1e50809eef0299cc51308ad543c2247c52f697e43", "src/main/java/buildcraft/lib/client/model/ResourceLoaderContext.java": "15aff8cccb231bea7a2cf43d6336c332c46794fa452aebc2b3443b6f5c4ba4a8", "src/main/java/buildcraft/lib/client/model/json/JsonModel.java": "7c3fdc075249650a04a6b2c21617c52e16448471ab0355da599e367445fd4f15", @@ -1335,6 +1335,7 @@ "src/main/java/buildcraft/lib/misc/CapUtil.java": "665787a78e4283f816327e012906382c695d113de6c2e4edd5e19939325b3cbd", "src/main/java/buildcraft/lib/misc/ChunkUtil.java": "c9a6d7e9f7e282b181a5c0439cfb6d679e49a17f1458b710186cabf52174fdbc", "src/main/java/buildcraft/lib/misc/ColourUtil.java": "f0d6335988a11a201f45b61959440f41e0c70ac4024449ac216b430764062a31", + "src/main/java/buildcraft/lib/misc/DirectionCompat.java": "8d2109c79536345f8142d124077c942dc271e407b5898ae97b4da1465f18d778", "src/main/java/buildcraft/lib/misc/EntityUtil.java": "dd31965d68747bb29dff08d67646a7339a2c1c846c7cc5c861dc1f80acccc192", "src/main/java/buildcraft/lib/misc/ExpressionCompat.java": "73e41a63a3ca26083d88924c75e1959e5461316d99fc44354bbbf9ca798e2217", "src/main/java/buildcraft/lib/misc/FakePlayerProvider.java": "bbe884c4a4a73a8c32a91fc4904f1cda587ba5981fb5c6589cd0b45b0e834e9b", @@ -1915,7 +1916,7 @@ "src/main/java/buildcraft/transport/wire/WireSystem.java": "5dfeec4c6bfc17a518ce75f6e06125aa1e47d251643c8420c23fd192453451c0", "src/main/java/buildcraft/transport/wire/WorldSavedDataWireSystems.java": "42358a27b37bd166025e0ab7f1a5b6fa4f87eb8202c3b701900ed0d427ef3b88", "src/main/resources/META-INF/accesstransformer.cfg": "6a8bc5f8e508aca0d569368af8153ecc5d8b11cbecfc77f00d7c7e1e04194211", - "src/main/resources/META-INF/neoforge.mods.toml": "cc86db91af5147525b7bcb13007852047c06b9be69db825dde8f1e5b110ef079", + "src/main/resources/META-INF/neoforge.mods.toml": "83f56797ba54e3f22eadf7f9dd84e9c1e61cefc6d7b11bbca3b11c2887ad872e", "src/main/resources/META-INF/services/buildcraft.api.v2.ApiRuntime": "fb22961a1d2185b0384fd48bf8dd1bcc7446a30b222bbb6d4f5f13cbf3345295", "src/main/resources/assets/buildcraft/guide/gui/icons.png": "5d5bb85942b9b404d072ea0e66486ccd882a52ec90906e91f11a1459df64eae1", "src/main/resources/assets/buildcraft/guide/gui/left_page.png": "e4259f875c7a7cc8efa35f03a92d0eb5596d8d223a56bf4bc7b8733d21aac827", @@ -3511,7 +3512,7 @@ "src/main/resources/assets/buildcrafttransport/models/item/wood_fluid.json": "c66e3c1ef7e9c4ab5574d1bee15d83a1b2a395bbfd75dbe445c0d12113473cc9", "src/main/resources/assets/buildcrafttransport/models/item/wood_item.json": "4cd666e93f76298f4dff4dc8f0f86efc59bd0d53bbb3f97a50285e8935f51457", "src/main/resources/assets/buildcrafttransport/models/item/wood_power.json": "7235b5342089895fc725554a391e463dd257e46213a57ba2ce21e90ac7c93662", - "src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json": "013325898629484ca7d1f04a6b61997778dbf12169b23ab02a343d6936935cfc", + "src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json": "749bc0fbcf4037c60a37e436a1e5d5d9ba0a7a204ae0c485b315220f3c8bda00", "src/main/resources/assets/buildcrafttransport/models/plugs/power_adapter.json": "7abf689fc26577a01b8d84d7caa6efea6944c2c44c905f808eddc2f6ded8789f", "src/main/resources/assets/buildcrafttransport/textures/blocks/filtered_buffer/default.png": "08110ad6d8bbe66b1666b7630fd27f6aec3e801b3f7013357d0ceb9ebf826a98", "src/main/resources/assets/buildcrafttransport/textures/blocks/pipes/pipe_lens_clear_overlay.png": "70ef610d9253692d8be498fe15ea97f4909e0f35301178a118d2d621e6e6de07", @@ -4333,6 +4334,7 @@ "src/test/java/buildcraft/core/BoxTester.java": "74f65df8ad822f5c3915a0f93d790b2efa234508d43a2f079e1e069d0220217e", "src/test/java/buildcraft/lib/client/guide/GuideDocumentInlineCodeTester.java": "1e60130990ccd6a181a9d3a2698841aad4d409461e109b2f330bc3bdbe9b9187", "src/test/java/buildcraft/lib/client/guide/OriginalGuideResourcesTester.java": "db59bfb52567c37c525c98dc9b5a49af9bdf6f57c023914acdb998836c5c0f03", + "src/test/java/buildcraft/lib/client/model/MutableQuadRotateTester.java": "34fde78cc2d2fbed29410b2ef0915a597104d314a16b5d0a031160b6e137e6e3", "src/test/java/buildcraft/lib/expression/ExpressionTester.java": "dc3eb322a85931896c36ae1e9994c760c57ed393d576f7bf37efef40115a56c7", "src/test/java/buildcraft/lib/internal/api/v2/DataDomainRegistryImplTester.java": "452cfa208ffe3654399d9b8c8344113c0583b9e3ce38b4f53da527854ae8f110", "src/test/java/buildcraft/lib/internal/api/v2/EnergyFluidRegistryImplTester.java": "3a6f1737d39daaa09345bf1c5731d7d5b6bdac9ac0b0a489a66f210d4178f9af", diff --git a/builds/1.21.X/gradlew b/builds/1.21.X/gradlew old mode 100644 new mode 100755 diff --git a/builds/26.X/gradlew b/builds/26.X/gradlew old mode 100644 new mode 100755 diff --git a/builds/old/gradlew b/builds/old/gradlew old mode 100644 new mode 100755 diff --git a/scripts/tests/test_pr64_facade_geometry.py b/scripts/tests/test_pr64_facade_geometry.py new file mode 100644 index 000000000..068aa8ac4 --- /dev/null +++ b/scripts/tests/test_pr64_facade_geometry.py @@ -0,0 +1,88 @@ +"""Independent six-direction rotation contract and materialization coverage for PR #64.""" +from __future__ import annotations + +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +VECTORS = { + 'DOWN': (0, -1, 0), 'UP': (0, 1, 0), + 'NORTH': (0, 0, -1), 'SOUTH': (0, 0, 1), + 'WEST': (-1, 0, 0), 'EAST': (1, 0, 0), +} + + +def rotate(vec, source, target): + """The axis/quarter-turn mapping of MutableQuad.rotate and MutableVertex.rotate*_90.""" + if source == target: + return vec + x, y, z = vec + sx, sy, sz = VECTORS[source] + tx, ty, tz = VECTORS[target] + axis_s = next(i for i, component in enumerate((sx, sy, sz)) if component) + axis_t = next(i for i, component in enumerate((tx, ty, tz)) if component) + if axis_s == axis_t: + if axis_s == 0 or axis_s == 2: + return (-x, y, -z) + return (-x, -y, z) + if axis_s == 0 and axis_t == 1: + k = sx * ty + return (-k * y, k * x, z) + if axis_s == 0 and axis_t == 2: + k = sx * tz + return (-k * z, y, k * x) + if axis_s == 1 and axis_t == 0: + k = -sy * tx + return (-k * y, k * x, z) + if axis_s == 1 and axis_t == 2: + k = sy * tz + return (x, -k * z, k * y) + if axis_s == 2 and axis_t == 0: + k = -sz * tx + return (-k * z, y, k * x) + if axis_s == 2 and axis_t == 1: + k = -sz * ty + return (x, -k * z, k * y) + raise AssertionError((source, target)) + + +class FacadeRotationPort(unittest.TestCase): + def test_all_36_direction_pairs(self): + for src, vector in VECTORS.items(): + for dst, target in VECTORS.items(): + with self.subTest(src=src, dst=dst): + self.assertEqual(target, rotate(vector, src, dst)) + + def test_216_face_rotations_remain_cardinal(self): + for face, vector in VECTORS.items(): + for src in VECTORS: + for dst in VECTORS: + with self.subTest(face=face, src=src, dst=dst): + self.assertIn(rotate(vector, src, dst), VECTORS.values()) + + def test_materialized_sources_cover_all_targets(self): + paths = [ + 'source-families/old/src/main/java/buildcraft/lib/client/model/MutableQuad.java', + 'source-families/1.21.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java', + 'source-families/26.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java', + 'source-downports/26.X/26.1.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java', + 'source-downports/26.X/26.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java', + ] + for rel in paths: + with self.subTest(rel=rel): + code = (ROOT / rel).read_text(encoding='utf-8') + self.assertIn('face = rotateFace(face, from, to)', code) + self.assertIn('probe.rotate(from, to, 0, 0, 0)', code) + self.assertIn('if (face != null)', code) + self.assertIn('DirectionCompat.nearest(', code) + self.assertIn('Direction.getNearest(', ( + ROOT / 'source-downports/1.21.X/1.21.1/family/src/main/java/buildcraft/lib/misc/DirectionCompat.java' + ).read_text()) + + def test_blocker_uv_fix(self): + code = (ROOT / 'source-shared/src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json').read_text() + self.assertIn('"north": { "uv": [ 4, 4, 2, 12 ]', code) + + +if __name__ == '__main__': + unittest.main() diff --git a/scripts/validate-fe-compat.py b/scripts/validate-fe-compat.py index 37c0f1654..e24c6abb5 100644 --- a/scripts/validate-fe-compat.py +++ b/scripts/validate-fe-compat.py @@ -4,7 +4,6 @@ from pathlib import Path import json -import re import sys ROOT = Path(__file__).resolve().parents[1] @@ -372,12 +371,15 @@ def require_any(path: str, *needles: str) -> None: require("README.md", "- [x] Add Forge Energy (FE) compatibility") -# Public/new naming is FE. The only old _rf strings permitted are persistence aliases. +# Public identifiers use FE. Legitimate third-party names and RF migration diagnostics +# must not be rejected; guard actual deprecated identifiers and migration aliases. allowed_rf_files = { ROOT / "source-families/old/src/main/java/buildcraft/transport/BCTransportPipes.java", ROOT / "source-families/1.21.X/src/main/java/buildcraft/transport/BCTransportPipes.java", + ROOT / "source-families/26.X/src/main/java/buildcraft/transport/BCTransportPipes.java", ROOT / "source-shared/src/main/java/buildcraft/transport/statements/ActionPowerLimit.java", } +legacy_rf_identifiers = ("rf_battery", "rf_limit") for base in (ROOT / "source-shared", ROOT / "source-families", ROOT / "source-platforms", ROOT / "source-family-platforms", ROOT / "version-src"): for p in base.rglob("*"): if not p.is_file() or "build" in p.parts: @@ -386,8 +388,9 @@ def require_any(path: str, *needles: str) -> None: data = p.read_text(encoding="utf-8") except UnicodeDecodeError: continue - if re.search(r"\bRF\b|Redstone Flux|redstone flux|rf_battery|rf_limit", data): - fail(f"user-facing/implementation RF branding remains: {p.relative_to(ROOT)}") + for identifier in legacy_rf_identifiers: + if identifier in data: + fail(f"unexpected legacy RF identifier {identifier!r}: {p.relative_to(ROOT)}") if "_rf" in data and p not in allowed_rf_files: fail(f"unexpected old _rf identifier outside migration aliases: {p.relative_to(ROOT)}") diff --git a/source-downports/1.21.X/1.21.1/family/src/main/java/buildcraft/lib/misc/DirectionCompat.java b/source-downports/1.21.X/1.21.1/family/src/main/java/buildcraft/lib/misc/DirectionCompat.java new file mode 100644 index 000000000..0032bf6f8 --- /dev/null +++ b/source-downports/1.21.X/1.21.1/family/src/main/java/buildcraft/lib/misc/DirectionCompat.java @@ -0,0 +1,12 @@ +package buildcraft.lib.misc; + +import net.minecraft.core.Direction; + +/** Direction lookups across Minecraft versions with different method names. */ +public final class DirectionCompat { + private DirectionCompat() {} + + public static Direction nearest(float x, float y, float z) { + return Direction.getNearest(x, y, z); + } +} diff --git a/source-downports/26.X/26.1.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java b/source-downports/26.X/26.1.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java index be0e0a179..8d35cb1f2 100644 --- a/source-downports/26.X/26.1.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java +++ b/source-downports/26.X/26.1.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java @@ -19,6 +19,8 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; +import buildcraft.lib.misc.DirectionCompat; + /** Holds all of the information necessary to make a {@link BakedQuad}. This provides a variety of methods to quickly * set or get different elements. This currently holds 4 {@link MutableVertex}. */ public class MutableQuad { @@ -684,9 +686,44 @@ public MutableQuad rotate(Direction from, Direction to, float ox, float oy, floa } // @formatter:on translatef(ox, oy, oz); + if (face != null) { + face = rotateFace(face, from, to); + } return this; } + /** Keep the culling/shading face synchronized with the rotated vertex positions. + * The lookup table mirrors the existing geometry rotation (including its roll for + * same-axis flips), rather than guessing from the destination direction alone. */ + private static Direction rotateFace(Direction face, Direction from, Direction to) { + return ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()]; + } + + private static final Direction[] ROTATED_FACES = new Direction[6 * 6 * 6]; + + static { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + for (Direction face : Direction.values()) { + ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()] = + probeRotatedFace(face, from, to); + } + } + } + } + + /** Probe the actual rotation path with an unlabeled unit vector. + * Keeping the probe unlabeled avoids recursive table initialization. */ + private static Direction probeRotatedFace(Direction face, Direction from, Direction to) { + MutableQuad probe = new MutableQuad(); + for (MutableVertex vertex : probe.vertexs) { + vertex.positionf(face.getStepX(), face.getStepY(), face.getStepZ()); + } + probe.rotate(from, to, 0, 0, 0); + MutableVertex moved = probe.vertex_0; + return DirectionCompat.nearest(moved.position_x, moved.position_y, moved.position_z); + } + public MutableQuad rotateX_90(float scale) { vertex_0.rotateX_90(scale); vertex_1.rotateX_90(scale); diff --git a/source-downports/26.X/26.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java b/source-downports/26.X/26.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java index be0e0a179..8d35cb1f2 100644 --- a/source-downports/26.X/26.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java +++ b/source-downports/26.X/26.2/neoforge/src/main/java/buildcraft/lib/client/model/MutableQuad.java @@ -19,6 +19,8 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; +import buildcraft.lib.misc.DirectionCompat; + /** Holds all of the information necessary to make a {@link BakedQuad}. This provides a variety of methods to quickly * set or get different elements. This currently holds 4 {@link MutableVertex}. */ public class MutableQuad { @@ -684,9 +686,44 @@ public MutableQuad rotate(Direction from, Direction to, float ox, float oy, floa } // @formatter:on translatef(ox, oy, oz); + if (face != null) { + face = rotateFace(face, from, to); + } return this; } + /** Keep the culling/shading face synchronized with the rotated vertex positions. + * The lookup table mirrors the existing geometry rotation (including its roll for + * same-axis flips), rather than guessing from the destination direction alone. */ + private static Direction rotateFace(Direction face, Direction from, Direction to) { + return ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()]; + } + + private static final Direction[] ROTATED_FACES = new Direction[6 * 6 * 6]; + + static { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + for (Direction face : Direction.values()) { + ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()] = + probeRotatedFace(face, from, to); + } + } + } + } + + /** Probe the actual rotation path with an unlabeled unit vector. + * Keeping the probe unlabeled avoids recursive table initialization. */ + private static Direction probeRotatedFace(Direction face, Direction from, Direction to) { + MutableQuad probe = new MutableQuad(); + for (MutableVertex vertex : probe.vertexs) { + vertex.positionf(face.getStepX(), face.getStepY(), face.getStepZ()); + } + probe.rotate(from, to, 0, 0, 0); + MutableVertex moved = probe.vertex_0; + return DirectionCompat.nearest(moved.position_x, moved.position_y, moved.position_z); + } + public MutableQuad rotateX_90(float scale) { vertex_0.rotateX_90(scale); vertex_1.rotateX_90(scale); diff --git a/source-families/1.21.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java b/source-families/1.21.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java index d2c76ea2e..bde27d1df 100644 --- a/source-families/1.21.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java +++ b/source-families/1.21.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java @@ -19,6 +19,8 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; +import buildcraft.lib.misc.DirectionCompat; + /** Holds all of the information necessary to make a {@link BakedQuad}. This provides a variety of methods to quickly * set or get different elements. This currently holds 4 {@link MutableVertex}. */ public class MutableQuad { @@ -684,9 +686,44 @@ public MutableQuad rotate(Direction from, Direction to, float ox, float oy, floa } // @formatter:on translatef(ox, oy, oz); + if (face != null) { + face = rotateFace(face, from, to); + } return this; } + /** Keep the culling/shading face synchronized with the rotated vertex positions. + * The lookup table mirrors the existing geometry rotation (including its roll for + * same-axis flips), rather than guessing from the destination direction alone. */ + private static Direction rotateFace(Direction face, Direction from, Direction to) { + return ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()]; + } + + private static final Direction[] ROTATED_FACES = new Direction[6 * 6 * 6]; + + static { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + for (Direction face : Direction.values()) { + ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()] = + probeRotatedFace(face, from, to); + } + } + } + } + + /** Probe the actual rotation path with an unlabeled unit vector. + * Keeping the probe unlabeled avoids recursive table initialization. */ + private static Direction probeRotatedFace(Direction face, Direction from, Direction to) { + MutableQuad probe = new MutableQuad(); + for (MutableVertex vertex : probe.vertexs) { + vertex.positionf(face.getStepX(), face.getStepY(), face.getStepZ()); + } + probe.rotate(from, to, 0, 0, 0); + MutableVertex moved = probe.vertex_0; + return DirectionCompat.nearest(moved.position_x, moved.position_y, moved.position_z); + } + public MutableQuad rotateX_90(float scale) { vertex_0.rotateX_90(scale); vertex_1.rotateX_90(scale); diff --git a/source-families/1.21.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java b/source-families/1.21.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java new file mode 100644 index 000000000..643165f6d --- /dev/null +++ b/source-families/1.21.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java @@ -0,0 +1,12 @@ +package buildcraft.lib.misc; + +import net.minecraft.core.Direction; + +/** Direction lookups across Minecraft versions with different method names. */ +public final class DirectionCompat { + private DirectionCompat() {} + + public static Direction nearest(float x, float y, float z) { + return Direction.getApproximateNearest(x, y, z); + } +} diff --git a/source-families/26.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java b/source-families/26.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java index be0e0a179..8d35cb1f2 100644 --- a/source-families/26.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java +++ b/source-families/26.X/src/main/java/buildcraft/lib/client/model/MutableQuad.java @@ -19,6 +19,8 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; +import buildcraft.lib.misc.DirectionCompat; + /** Holds all of the information necessary to make a {@link BakedQuad}. This provides a variety of methods to quickly * set or get different elements. This currently holds 4 {@link MutableVertex}. */ public class MutableQuad { @@ -684,9 +686,44 @@ public MutableQuad rotate(Direction from, Direction to, float ox, float oy, floa } // @formatter:on translatef(ox, oy, oz); + if (face != null) { + face = rotateFace(face, from, to); + } return this; } + /** Keep the culling/shading face synchronized with the rotated vertex positions. + * The lookup table mirrors the existing geometry rotation (including its roll for + * same-axis flips), rather than guessing from the destination direction alone. */ + private static Direction rotateFace(Direction face, Direction from, Direction to) { + return ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()]; + } + + private static final Direction[] ROTATED_FACES = new Direction[6 * 6 * 6]; + + static { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + for (Direction face : Direction.values()) { + ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()] = + probeRotatedFace(face, from, to); + } + } + } + } + + /** Probe the actual rotation path with an unlabeled unit vector. + * Keeping the probe unlabeled avoids recursive table initialization. */ + private static Direction probeRotatedFace(Direction face, Direction from, Direction to) { + MutableQuad probe = new MutableQuad(); + for (MutableVertex vertex : probe.vertexs) { + vertex.positionf(face.getStepX(), face.getStepY(), face.getStepZ()); + } + probe.rotate(from, to, 0, 0, 0); + MutableVertex moved = probe.vertex_0; + return DirectionCompat.nearest(moved.position_x, moved.position_y, moved.position_z); + } + public MutableQuad rotateX_90(float scale) { vertex_0.rotateX_90(scale); vertex_1.rotateX_90(scale); diff --git a/source-families/26.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java b/source-families/26.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java new file mode 100644 index 000000000..643165f6d --- /dev/null +++ b/source-families/26.X/src/main/java/buildcraft/lib/misc/DirectionCompat.java @@ -0,0 +1,12 @@ +package buildcraft.lib.misc; + +import net.minecraft.core.Direction; + +/** Direction lookups across Minecraft versions with different method names. */ +public final class DirectionCompat { + private DirectionCompat() {} + + public static Direction nearest(float x, float y, float z) { + return Direction.getApproximateNearest(x, y, z); + } +} diff --git a/source-families/old/src/main/java/buildcraft/lib/client/model/MutableQuad.java b/source-families/old/src/main/java/buildcraft/lib/client/model/MutableQuad.java index 8bcc05a15..27f850248 100644 --- a/source-families/old/src/main/java/buildcraft/lib/client/model/MutableQuad.java +++ b/source-families/old/src/main/java/buildcraft/lib/client/model/MutableQuad.java @@ -28,6 +28,8 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; +import buildcraft.lib.misc.DirectionCompat; + /** Holds all of the information necessary to make a {@link BakedQuad}. This provides a variety of methods to quickly * set or get different elements. This currently holds 4 {@link MutableVertex}. */ public class MutableQuad { @@ -705,9 +707,44 @@ public MutableQuad rotate(Direction from, Direction to, float ox, float oy, floa } // @formatter:on translatef(ox, oy, oz); + if (face != null) { + face = rotateFace(face, from, to); + } return this; } + /** Keep the culling/shading face synchronized with the rotated vertex positions. + * The lookup table mirrors the existing geometry rotation (including its roll for + * same-axis flips), rather than guessing from the destination direction alone. */ + private static Direction rotateFace(Direction face, Direction from, Direction to) { + return ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()]; + } + + private static final Direction[] ROTATED_FACES = new Direction[6 * 6 * 6]; + + static { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + for (Direction face : Direction.values()) { + ROTATED_FACES[(from.ordinal() * 6 + to.ordinal()) * 6 + face.ordinal()] = + probeRotatedFace(face, from, to); + } + } + } + } + + /** Probe the actual rotation path with an unlabeled unit vector. + * Keeping the probe unlabeled avoids recursive table initialization. */ + private static Direction probeRotatedFace(Direction face, Direction from, Direction to) { + MutableQuad probe = new MutableQuad(); + for (MutableVertex vertex : probe.vertexs) { + vertex.positionf(face.getStepX(), face.getStepY(), face.getStepZ()); + } + probe.rotate(from, to, 0, 0, 0); + MutableVertex moved = probe.vertex_0; + return DirectionCompat.nearest(moved.position_x, moved.position_y, moved.position_z); + } + public MutableQuad rotateX_90(float scale) { vertex_0.rotateX_90(scale); vertex_1.rotateX_90(scale); diff --git a/source-families/old/src/main/java/buildcraft/lib/misc/DirectionCompat.java b/source-families/old/src/main/java/buildcraft/lib/misc/DirectionCompat.java new file mode 100644 index 000000000..0032bf6f8 --- /dev/null +++ b/source-families/old/src/main/java/buildcraft/lib/misc/DirectionCompat.java @@ -0,0 +1,12 @@ +package buildcraft.lib.misc; + +import net.minecraft.core.Direction; + +/** Direction lookups across Minecraft versions with different method names. */ +public final class DirectionCompat { + private DirectionCompat() {} + + public static Direction nearest(float x, float y, float z) { + return Direction.getNearest(x, y, z); + } +} diff --git a/source-platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/source-platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml index a2aaced22..8ea4f7ba0 100644 --- a/source-platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/source-platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -33,6 +33,13 @@ Shared library code and runtime helpers used by the BuildCraft Community Edition ordering="NONE" side="BOTH" +[[dependencies.buildcraftlib]] + modId="buildcraftrf" + type="incompatible" + reason="BuildCraft RF: ReFluxified targets a different BuildCraft implementation; BCCE already provides native FE compatibility." + ordering="NONE" + side="BOTH" + [[dependencies.buildcraftlib]] modId="jei" type="optional" @@ -324,7 +331,7 @@ Robots, docking stations, redstone boards, zones and robotic automation. modId="buildcraftcompat" version="${mod_version}" displayName="BuildCraft Community Edition - Compat" - credits="Special thanks to the original BuildCraft team and all contributors." + credits="Special thanks to the original BuildCraft and Forestry teams and all contributors." authors="CurativeTree, ShipovskijKorp" description=''' Optional cross-mod integration hooks for BuildCraft Community Edition. Integrations without a compatible NeoForge 1.21.1 dependency remain disabled. diff --git a/source-shared/src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json b/source-shared/src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json index 716907afd..9b3177446 100644 --- a/source-shared/src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json +++ b/source-shared/src/main/resources/assets/buildcrafttransport/models/plugs/blocker.json @@ -44,7 +44,7 @@ "faces": { "down": { "uv": [ 2, 4, 4, 12 ], "texture": "#all" }, "up": { "uv": [ 2, 4, 4, 12 ], "texture": "#all" }, - "north": { "uv": [ 2, 4, 4, 12 ], "texture": "#all" }, + "north": { "uv": [ 4, 4, 2, 12 ], "texture": "#all" }, "south": { "uv": [ 2, 4, 4, 12 ], "texture": "#all" }, "west": { "uv": [ 4, 4, 12, 12 ], "texture": "#all" }, "east": { "uv": [ 4, 4, 12, 12 ], "texture": "#all" } diff --git a/source-shared/src/test/java/buildcraft/lib/client/model/MutableQuadRotateTester.java b/source-shared/src/test/java/buildcraft/lib/client/model/MutableQuadRotateTester.java new file mode 100644 index 000000000..30aa945a3 --- /dev/null +++ b/source-shared/src/test/java/buildcraft/lib/client/model/MutableQuadRotateTester.java @@ -0,0 +1,59 @@ +package buildcraft.lib.client.model; + +import net.minecraft.core.Direction; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import buildcraft.lib.misc.DirectionCompat; + +class MutableQuadRotateTester { + /** Rotated culling face must match the actual geometric face for every direction triple. */ + @Test + void rotatedQuadFaceLabelMatchesGeometry() { + for (Direction face : Direction.values()) { + for (Direction from : Direction.values()) { + for (Direction to : Direction.values()) { + MutableQuad quad = quadOnFace(face); + quad.rotate(from, to, 0.5f, 0.5f, 0.5f); + Assertions.assertEquals(sideOf(quad), quad.getFace(), + "face " + face + " rotated " + from + " -> " + to); + } + } + } + } + + /** Unlabeled geometry is not assigned an arbitrary face on rotation. */ + @Test + void rotatedQuadWithoutFaceStaysUnlabelled() { + MutableQuad quad = quadOnFace(Direction.UP); + quad.setFace(null); + quad.rotate(Direction.UP, Direction.NORTH, 0.5f, 0.5f, 0.5f); + Assertions.assertNull(quad.getFace()); + } + + private static MutableQuad quadOnFace(Direction face) { + MutableQuad quad = new MutableQuad(-1, face); + int axis = face.getAxis().ordinal(); + int a = (axis + 1) % 3; + int b = (axis + 2) % 3; + float plane = face.getAxisDirection() == Direction.AxisDirection.POSITIVE ? 1 : 0; + float[][] corners = { { 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 0 } }; + for (int i = 0; i < 4; i++) { + float[] pos = new float[3]; + pos[axis] = plane; + pos[a] = corners[i][0]; + pos[b] = corners[i][1]; + quad.vertexs[i].positionf(pos[0], pos[1], pos[2]); + } + return quad; + } + + private static Direction sideOf(MutableQuad quad) { + float x = 0, y = 0, z = 0; + for (MutableVertex vertex : quad.vertexs) { + x += vertex.position_x / 4 - 0.125f; + y += vertex.position_y / 4 - 0.125f; + z += vertex.position_z / 4 - 0.125f; + } + return DirectionCompat.nearest(x, y, z); + } +} diff --git a/version-src/1.20.1-forge/src/main/java/buildcraft/lib/BCLib.java b/version-src/1.20.1-forge/src/main/java/buildcraft/lib/BCLib.java index 6eb6174d3..968f0871a 100644 --- a/version-src/1.20.1-forge/src/main/java/buildcraft/lib/BCLib.java +++ b/version-src/1.20.1-forge/src/main/java/buildcraft/lib/BCLib.java @@ -4,6 +4,8 @@ * distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ package buildcraft.lib; +import java.util.List; + import buildcraft.lib.platform.registry.RegistryBinding; import buildcraft.api.v2.BuildCraftApi; import buildcraft.api.v2.BuildCraftServices; @@ -25,6 +27,8 @@ import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoadingException; +import net.minecraftforge.fml.ModLoadingStage; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; @@ -41,9 +45,12 @@ public class BCLib { public static final String GIT_COMMIT_MSG = BuildCraftTarget.GIT_COMMIT_MESSAGE; public static final String GIT_COMMIT_AUTHOR = BuildCraftTarget.GIT_COMMIT_AUTHOR; + private static final List INCOMPATIBLE_MODS = List.of("buildcraftrf"); + public static final boolean DEV = !FMLEnvironment.production || Boolean.getBoolean("buildcraft.dev"); public BCLib() { + rejectIncompatibleMods(); MjApi2PlatformBridge.install(); PlatformApi2Bootstrap.install(); IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); @@ -99,6 +106,24 @@ public BCLib() { } + private static void rejectIncompatibleMods() { + for (String modId : INCOMPATIBLE_MODS) { + if (!ModList.get().isLoaded(modId)) { + continue; + } + String displayName = ModList.get().getModContainerById(modId) + .map(container -> container.getModInfo().getDisplayName()) + .orElse(modId); + throw new ModLoadingException( + ModList.get().getModContainerById(MODID).orElseThrow().getModInfo(), + ModLoadingStage.CONSTRUCT, + "BuildCraft Community Edition is incompatible with " + displayName + " (" + modId + "). " + + "Remove it before starting the game. BCCE already provides native FE compatibility.", + new IllegalStateException("Incompatible mod detected: " + modId) + ); + } + } + public void gatherData(GatherDataEvent event) { var output = event.getGenerator().getPackOutput(); var lookupProvider = event.getLookupProvider();