Never place a chevron on the flat bottom threshold
pickChevrons() spaced chevrons evenly starting from whichever ring block the flood-fill happened to discover first - an arbitrary point depending on where the ring was punched, with no relationship to the ring's actual top/bottom. That let spacing land a chevron directly on the bottom row you walk through, which a real Stargate never has. For a vertical ring, chevron spacing is now anchored at the true topmost block and the bottom row is excluded from the candidate list entirely before spacing runs. Horizontal rings are unaffected - they have no "bottom" to avoid, so they still use the full ring.
This commit is contained in:
@@ -36,10 +36,12 @@ doesn't try to flood-fill out through the open air in front of and behind the ga
|
||||
|
||||
Chevrons aren't a separate material you place. When the gate is linked, the plugin
|
||||
flood-fills the ring, walks it in geometric order, and picks `gate.chevron-count`
|
||||
(default 7) blocks evenly spaced around the ring's actual perimeter. Those blocks
|
||||
swap to `gate.chevron-lit-material` (default glowstone) while dialing/open, and
|
||||
revert to whatever they looked like at rest when the gate closes - so a chevron can
|
||||
rest as plain obsidian and blend invisibly into the frame until it lights up.
|
||||
(default 7) blocks evenly spaced around the ring's actual perimeter - anchored at the
|
||||
topmost point for a vertical ring, and never the flat bottom row you walk through,
|
||||
matching a real Stargate. Those blocks swap to `gate.chevron-lit-material` (default
|
||||
glowstone) while dialing/open, and revert to whatever they looked like at rest when
|
||||
the gate closes - so a chevron can rest as plain obsidian and blend invisibly into
|
||||
the frame until it lights up.
|
||||
|
||||
1. Build the ring.
|
||||
2. Optionally place a button directly below where you'll put the sign - this becomes
|
||||
|
||||
+31
-5
@@ -266,6 +266,8 @@ public class GateStructureScanner {
|
||||
* Picks {@code chevronCount} chevrons evenly spaced around the ring's actual geometric
|
||||
* perimeter - walks the ring in order (each frame block should have exactly two ring
|
||||
* neighbours) and takes evenly-spaced indices from that walk, not raw scan-discovery order.
|
||||
* For a vertical ring, spacing is anchored at the topmost point and the flat bottom
|
||||
* threshold row is never a candidate - a real Stargate never has a chevron underfoot.
|
||||
*/
|
||||
private List<GateStructure.ChevronSlot> pickChevrons(List<Block> frameBlocks, BlockFace[] inPlane) {
|
||||
Map<Long, Block> plane = new HashMap<>();
|
||||
@@ -278,16 +280,40 @@ public class GateStructureScanner {
|
||||
List<Block> ordered = walkRing(frameBlocks, plane, inPlane);
|
||||
List<Block> ring = (ordered != null && ordered.size() >= 4) ? ordered : frameBlocks;
|
||||
|
||||
int count = Math.max(0, Math.min(chevronCount, ring.size()));
|
||||
boolean vertical = false;
|
||||
for (BlockFace f : inPlane) if (f == BlockFace.UP || f == BlockFace.DOWN) vertical = true;
|
||||
|
||||
List<Block> candidates;
|
||||
if (vertical) {
|
||||
int n = ring.size();
|
||||
int[] rows = new int[n];
|
||||
int minRow = Integer.MAX_VALUE, maxRow = Integer.MIN_VALUE, topIdx = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
rows[i] = project(ring.get(i), inPlane)[0]; // row is world Y for a vertical ring
|
||||
if (rows[i] < minRow) minRow = rows[i];
|
||||
if (rows[i] > maxRow) { maxRow = rows[i]; topIdx = i; }
|
||||
}
|
||||
candidates = new ArrayList<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
int idx = (topIdx + i) % n;
|
||||
if (rows[idx] == minRow) continue; // skip the flat bottom threshold
|
||||
candidates.add(ring.get(idx));
|
||||
}
|
||||
if (candidates.isEmpty()) candidates = ring; // degenerate shape fallback
|
||||
} else {
|
||||
candidates = ring; // a horizontal ring has no "bottom" to avoid
|
||||
}
|
||||
|
||||
int count = Math.max(0, Math.min(chevronCount, candidates.size()));
|
||||
List<GateStructure.ChevronSlot> slots = new ArrayList<>(count);
|
||||
if (count == 0) return slots;
|
||||
double step = ring.size() / (double) count;
|
||||
double step = candidates.size() / (double) count;
|
||||
Set<Integer> chosen = new HashSet<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int idx = (int) Math.round(i * step) % ring.size();
|
||||
while (chosen.contains(idx)) idx = (idx + 1) % ring.size();
|
||||
int idx = (int) Math.round(i * step) % candidates.size();
|
||||
while (chosen.contains(idx)) idx = (idx + 1) % candidates.size();
|
||||
chosen.add(idx);
|
||||
Block b = ring.get(idx);
|
||||
Block b = candidates.get(idx);
|
||||
slots.add(new GateStructure.ChevronSlot(b, b.getType()));
|
||||
}
|
||||
return slots;
|
||||
|
||||
Reference in New Issue
Block a user