|
16 | 16 |
|
17 | 17 | public final class MatrixRebuilder { |
18 | 18 | private static final AtomicBoolean REBUILDING = new AtomicBoolean(false); |
| 19 | + private static final AtomicBoolean PRE_FREEZE_PREPARED = new AtomicBoolean(false); |
19 | 20 | private static final AtomicBoolean PENDING_REBUILD = new AtomicBoolean(false); |
20 | 21 | private static final AtomicInteger BOOTSTRAP_ADD_CALLS = new AtomicInteger(0); |
21 | 22 | private static final AtomicInteger BOOTSTRAP_ADD_SKIPPED_BUSY = new AtomicInteger(0); |
@@ -63,6 +64,77 @@ public static void bootstrap(BlockMatrix matrix, boolean forceFullScan) { |
63 | 64 | } |
64 | 65 | } |
65 | 66 |
|
| 67 | + /** |
| 68 | + * Performs a single deterministic pre-freeze pass: |
| 69 | + * 1. Collect base blocks from the current block registry |
| 70 | + * 2. Adopt existing variants and register missing ones while the registry is still writable |
| 71 | + * 3. Publish the final immutable matrix snapshot |
| 72 | + * |
| 73 | + * This pass intentionally does not depend on recipes, because the final |
| 74 | + * datapack-backed recipe manager is not available yet at block-registry freeze time. |
| 75 | + */ |
| 76 | + public static void prepareForRegistryFreeze(BlockMatrix matrix) { |
| 77 | + if (matrix == null) return; |
| 78 | + if (!PRE_FREEZE_PREPARED.compareAndSet(false, true)) { |
| 79 | + Reshaped.LOGGER.debug("[MatrixRebuilder] prepareForRegistryFreeze() ignored - already prepared."); |
| 80 | + return; |
| 81 | + } |
| 82 | + |
| 83 | + Reshaped.LOGGER.info("[MatrixRebuilder] Preparing block matrix before block registry freeze..."); |
| 84 | + |
| 85 | + if (!REBUILDING.compareAndSet(false, true)) { |
| 86 | + Reshaped.LOGGER.warn("[MatrixRebuilder] prepareForRegistryFreeze() skipped - REBUILDING already true"); |
| 87 | + return; |
| 88 | + } |
| 89 | + |
| 90 | + try { |
| 91 | + matrix.clear(); |
| 92 | + |
| 93 | + Set<Block> baseCandidates = BaseBlockFilter.collectBaseCandidates(); |
| 94 | + Reshaped.LOGGER.info("[MatrixRebuilder] pre-freeze: collected {} base candidates", baseCandidates.size()); |
| 95 | + |
| 96 | + for (Block base : baseCandidates) { |
| 97 | + matrix.addColumn(base, List.of(), false); |
| 98 | + matrix.setReason(base, "Base block selected by state-based filter"); |
| 99 | + } |
| 100 | + |
| 101 | + suppressCallback = true; |
| 102 | + try { |
| 103 | + List<Block> bases = new ArrayList<>(matrix.getMutableMatrix().keySet()); |
| 104 | + int completed = 0; |
| 105 | + |
| 106 | + for (Block base : bases) { |
| 107 | + try { |
| 108 | + VariantCompleter.completeVariant(base, matrix); |
| 109 | + VariantRegistry.registerAll(base, matrix); |
| 110 | + completed++; |
| 111 | + } catch (Exception e) { |
| 112 | + Reshaped.LOGGER.warn("[MatrixRebuilder] pre-freeze: variant processing FAILED for base {} ({})", |
| 113 | + Registries.BLOCK.getId(base), e.getMessage(), e); |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + Reshaped.LOGGER.info("[MatrixRebuilder] pre-freeze: completed variant registration for {}/{} bases", completed, bases.size()); |
| 118 | + } finally { |
| 119 | + suppressCallback = false; |
| 120 | + } |
| 121 | + |
| 122 | + matrix.refresh(); |
| 123 | + HAS_BOOTSTRAPPED.set(true); |
| 124 | + Reshaped.LOGGER.info( |
| 125 | + "[MatrixRebuilder] Pre-freeze matrix prepared: {} bases, {} columns (snapshot: {})", |
| 126 | + baseCandidates.size(), |
| 127 | + matrix.getMutableMatrix().size(), |
| 128 | + matrix.getMatrix().size() |
| 129 | + ); |
| 130 | + } catch (Exception e) { |
| 131 | + PRE_FREEZE_PREPARED.set(false); |
| 132 | + Reshaped.LOGGER.error("[MatrixRebuilder] Failed to prepare matrix before registry freeze", e); |
| 133 | + } finally { |
| 134 | + REBUILDING.set(false); |
| 135 | + } |
| 136 | + } |
| 137 | + |
66 | 138 | private static void doBootstrap(BlockMatrix matrix) { |
67 | 139 | if (matrix == null) return; |
68 | 140 |
|
|
0 commit comments