Skip to content

Commit d1c88ea

Browse files
committed
Refactor matrix bootstrapping to use RegistryFreezeMixin
1 parent 6b8e9f2 commit d1c88ea

6 files changed

Lines changed: 100 additions & 37 deletions

File tree

‎src/main/java/net/f3rr3/reshaped/Reshaped.java‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import net.f3rr3.reshaped.interaction.BlockInteractionService;
1616
import net.f3rr3.reshaped.matrix.BlockMatrix;
1717
import net.f3rr3.reshaped.matrix.BlockRegistryScanner;
18-
import net.f3rr3.reshaped.matrix.MatrixRebuilder;
1918
import net.f3rr3.reshaped.network.NetworkHandler;
2019
import net.fabricmc.api.ModInitializer;
2120
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
@@ -122,12 +121,7 @@ public void onInitialize() {
122121

123122
BlockInteractionService.register();
124123

125-
// Primary bootstrap: Catch all blocks already in the registry.
126-
// If some modded blocks haven't registered yet, they will be caught by
127-
// the late-sync triggers in ReshapedModelLoadingPlugin or SERVER_STARTING.
128-
MatrixRebuilder.bootstrap(MATRIX, false);
129-
130-
LOGGER.info("Reshaping complete - Block matrix is now reactive.");
124+
LOGGER.info("Reshaping complete - awaiting block registry freeze.");
131125
}
132126
}
133127

‎src/main/java/net/f3rr3/reshaped/client/ReshapedModelLoadingPlugin.java‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ private static String toBitMask(int value, int length) {
8686

8787
@Override
8888
public void onInitializeModelLoader(Context context) {
89-
// Late-sync: Ensure the matrix is bootstrapped before we start resolving models.
90-
MatrixRebuilder.bootstrap(net.f3rr3.reshaped.Reshaped.MATRIX, true);
89+
MatrixRebuilder.prepareForRegistryFreeze(Reshaped.MATRIX);
9190
context.addModels(new Identifier(Reshaped.MOD_ID, "block/mixed_placeholder"));
9291

9392
// Register block state resolvers for all reshaped blocks currently in registry

‎src/main/java/net/f3rr3/reshaped/matrix/BlockRegistryScanner.java‎

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,14 @@
22

33
import net.f3rr3.reshaped.Reshaped;
44
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
5-
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
6-
import net.minecraft.block.Block;
7-
import net.minecraft.registry.Registries;
85

96
public class BlockRegistryScanner {
107
public static void init(BlockMatrix matrix) {
118
Reshaped.LOGGER.info("[BlockRegistryScanner] init() called on thread: {}", Thread.currentThread().getName());
129

13-
// We no longer bootstrap unconditionally in init(), as mod load order
14-
// is non-deterministic. Instead, we register triggers for late-lifecycle
15-
// points where all mods have likely finished registering their blocks.
16-
17-
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
18-
Reshaped.LOGGER.info("[BlockRegistryScanner] SERVER_STARTING triggered. Ensuring matrix is bootstrapped...");
19-
MatrixRebuilder.bootstrap(matrix, true);
20-
});
10+
// Registry writes are now centralized in a pre-freeze mixin pass.
11+
// Server lifecycle rebuilds remain for recipe-based enrichment and
12+
// datapack reload handling after startup.
2113

2214
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
2315
Reshaped.LOGGER.info("[BlockRegistryScanner] SERVER_STARTED triggered on thread: {}", Thread.currentThread().getName());
@@ -31,21 +23,5 @@ public static void init(BlockMatrix matrix) {
3123
MatrixRebuilder.rebuild(matrix, server);
3224
}
3325
});
34-
35-
RegistryEntryAddedCallback.event(Registries.BLOCK).register((rawId, id, block) -> {
36-
if (MatrixRebuilder.isSuppressed()) return;
37-
MatrixRebuilder.bootstrapAddedBlock(matrix, block);
38-
});
39-
40-
RegistryEntryAddedCallback.event(Registries.ITEM).register((rawId, id, item) -> {
41-
if (MatrixRebuilder.isSuppressed()) return;
42-
43-
// Check if this item registration completes a modded block candidate.
44-
// Many mods register Block then Item; we need both for BaseBlockFilter to pass.
45-
Block block = Registries.BLOCK.get(id);
46-
if (block != net.minecraft.block.Blocks.AIR) {
47-
MatrixRebuilder.bootstrapAddedBlock(matrix, block);
48-
}
49-
});
5026
}
5127
}

‎src/main/java/net/f3rr3/reshaped/matrix/MatrixRebuilder.java‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
public final class MatrixRebuilder {
1818
private static final AtomicBoolean REBUILDING = new AtomicBoolean(false);
19+
private static final AtomicBoolean PRE_FREEZE_PREPARED = new AtomicBoolean(false);
1920
private static final AtomicBoolean PENDING_REBUILD = new AtomicBoolean(false);
2021
private static final AtomicInteger BOOTSTRAP_ADD_CALLS = new AtomicInteger(0);
2122
private static final AtomicInteger BOOTSTRAP_ADD_SKIPPED_BUSY = new AtomicInteger(0);
@@ -63,6 +64,77 @@ public static void bootstrap(BlockMatrix matrix, boolean forceFullScan) {
6364
}
6465
}
6566

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+
66138
private static void doBootstrap(BlockMatrix matrix) {
67139
if (matrix == null) return;
68140

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package net.f3rr3.reshaped.mixin;
2+
3+
import net.f3rr3.reshaped.Reshaped;
4+
import net.f3rr3.reshaped.matrix.MatrixRebuilder;
5+
import net.minecraft.registry.Registries;
6+
import net.minecraft.registry.SimpleRegistry;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.injection.At;
9+
import org.spongepowered.asm.mixin.injection.Inject;
10+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
11+
12+
@Mixin(SimpleRegistry.class)
13+
public class RegistryFreezeMixin {
14+
@Inject(method = "freeze", at = @At("HEAD"))
15+
private void reshaped$prepareMatrixBeforeBlockRegistryFreeze(CallbackInfoReturnable<SimpleRegistry<?>> cir) {
16+
if ((Object) this == Registries.BLOCK) {
17+
Reshaped.LOGGER.info("[RegistryFreezeMixin] Block registry freeze intercepted. Preparing matrix...");
18+
MatrixRebuilder.prepareForRegistryFreeze(Reshaped.MATRIX);
19+
}
20+
}
21+
}

‎src/main/resources/reshaped.mixins.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"BlockShouldDrawSideMixin",
99
"AxeItemAccessor",
1010
"HoneycombItemAccessor",
11-
"ItemStackMixin"
11+
"ItemStackMixin",
12+
"RegistryFreezeMixin"
1213
],
1314
"injectors": {
1415
"defaultRequire": 1

0 commit comments

Comments
 (0)