Skip to content

Commit a8785e6

Browse files
committed
Reimplement optimized lookup map for block state models
1 parent 10b665c commit a8785e6

File tree

4 files changed

+138
-5
lines changed

4 files changed

+138
-5
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
2+
3+
import net.minecraft.client.renderer.block.model.BlockStateModel;
4+
import net.minecraft.world.level.block.state.BlockBehaviour;
5+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
6+
import org.embeddedt.modernfix.duck.IModelHoldingBlockState;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
9+
import java.lang.ref.SoftReference;
10+
11+
@Mixin(BlockBehaviour.BlockStateBase.class)
12+
@ClientOnlyMixin
13+
public class MixinBlockState implements IModelHoldingBlockState {
14+
private volatile SoftReference<BlockStateModel> mfix$model;
15+
16+
@Override
17+
public BlockStateModel mfix$getModel() {
18+
var ref = mfix$model;
19+
return ref != null ? ref.get() : null;
20+
}
21+
22+
@Override
23+
public void mfix$setModel(BlockStateModel model) {
24+
mfix$model = model != null ? new SoftReference<>(model) : null;
25+
}
26+
}

src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import net.minecraft.server.packs.resources.Resource;
1313
import net.minecraft.world.level.block.state.BlockState;
1414
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
15+
import org.embeddedt.modernfix.dynresources.BlockStateModelMap;
1516
import org.embeddedt.modernfix.dynresources.DynamicModelSystem;
1617
import org.spongepowered.asm.mixin.Mixin;
1718
import org.spongepowered.asm.mixin.Overwrite;
@@ -62,8 +63,7 @@ private static Object2IntMap<BlockState> buildModelGroups(BlockColors blockColor
6263
*/
6364
@Overwrite
6465
private static Map<BlockState, BlockStateModel> createBlockStateToModelDispatch(Map<BlockState, BlockStateModel> blockStateModels, BlockStateModel missingModel) {
65-
return Maps.asMap(DynamicModelSystem.getAllBlockStates(), state -> {
66-
return blockStateModels.getOrDefault(state, missingModel);
67-
});
66+
BlockStateModelMap.resetCache();
67+
return new BlockStateModelMap(blockStateModels, missingModel);
6868
}
6969
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.embeddedt.modernfix.dynresources;
2+
3+
import net.minecraft.client.renderer.block.model.BlockStateModel;
4+
import net.minecraft.world.level.block.Block;
5+
import net.minecraft.world.level.block.state.BlockState;
6+
import org.embeddedt.modernfix.duck.IModelHoldingBlockState;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.util.Collection;
11+
import java.util.Map;
12+
import java.util.Set;
13+
14+
/**
15+
* Optimized blockstate->model dispatch map that stores the models directly on the block state objects using a helper
16+
* field. This relies on the fact that Minecraft should only have one model map in flight at a time.
17+
*/
18+
public record BlockStateModelMap(Map<BlockState, BlockStateModel> modelMap,
19+
BlockStateModel fallbackModel) implements Map<BlockState, BlockStateModel> {
20+
21+
@Override
22+
public int size() {
23+
return Block.BLOCK_STATE_REGISTRY.size();
24+
}
25+
26+
@Override
27+
public boolean isEmpty() {
28+
return false;
29+
}
30+
31+
@Override
32+
public boolean containsKey(Object o) {
33+
return o instanceof BlockState;
34+
}
35+
36+
@Override
37+
public boolean containsValue(Object o) {
38+
return modelMap.containsValue(o);
39+
}
40+
41+
@Override
42+
public BlockStateModel get(Object o) {
43+
if (o instanceof IModelHoldingBlockState modelHolder) {
44+
BlockStateModel model = modelHolder.mfix$getModel();
45+
46+
if(model != null) {
47+
return model;
48+
}
49+
50+
model = modelMap.getOrDefault(o, fallbackModel);
51+
modelHolder.mfix$setModel(model);
52+
return model;
53+
} else {
54+
return modelMap.getOrDefault(o, fallbackModel);
55+
}
56+
}
57+
58+
@Override
59+
public @Nullable BlockStateModel put(BlockState blockState, BlockStateModel blockStateModel) {
60+
var oldModel = modelMap.put(blockState, blockStateModel);
61+
((IModelHoldingBlockState)blockState).mfix$setModel(null);
62+
return oldModel;
63+
}
64+
65+
@Override
66+
public BlockStateModel remove(Object o) {
67+
var old = modelMap.remove(o);
68+
if (o instanceof IModelHoldingBlockState holder) {
69+
holder.mfix$setModel(null);
70+
}
71+
return old;
72+
}
73+
74+
@Override
75+
public void putAll(@NotNull Map<? extends BlockState, ? extends BlockStateModel> map) {
76+
map.forEach(this::put);
77+
}
78+
79+
@Override
80+
public void clear() {
81+
modelMap.clear();
82+
resetCache();
83+
}
84+
85+
@Override
86+
public @NotNull Set<BlockState> keySet() {
87+
return modelMap.keySet();
88+
}
89+
90+
@Override
91+
public @NotNull Collection<BlockStateModel> values() {
92+
return modelMap.values();
93+
}
94+
95+
@Override
96+
public @NotNull Set<Entry<BlockState, BlockStateModel>> entrySet() {
97+
return modelMap.entrySet();
98+
}
99+
100+
public static void resetCache() {
101+
for (var state : Block.BLOCK_STATE_REGISTRY) {
102+
((IModelHoldingBlockState) state).mfix$setModel(null);
103+
}
104+
}
105+
}

src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import it.unimi.dsi.fastutil.objects.ObjectSets;
1212
import it.unimi.dsi.fastutil.objects.ReferenceSets;
1313
import net.minecraft.client.color.block.BlockColors;
14+
import net.minecraft.client.renderer.block.model.BlockStateModel;
1415
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
1516
import net.minecraft.client.resources.model.BlockStateModelLoader;
1617
import net.minecraft.client.resources.model.ClientItemInfoLoader;
@@ -35,6 +36,7 @@
3536
import java.util.Map;
3637
import java.util.Set;
3738
import java.util.function.BiFunction;
39+
import java.util.function.Function;
3840
import java.util.stream.Collectors;
3941

4042
public class DynamicModelSystem {
@@ -172,13 +174,13 @@ public Object load(K key) throws Exception {
172174
}
173175
}
174176
});
175-
return new DynamicRegistryMap<>(input.keySet(),k -> {
177+
return new DynamicRegistryMap<>(input.keySet(), k -> {
176178
if (k != null) {
177179
Object value = bakedCache.getUnchecked(k);
178180
if (value == NULL_BAKED) {
179181
value = null;
180182
}
181-
return (V)value;
183+
return (V) value;
182184
} else {
183185
return null;
184186
}

0 commit comments

Comments
 (0)