|
1 | 1 | package org.embeddedt.modernfix.common.mixin.perf.deduplicate_wall_shapes; |
2 | 2 |
|
| 3 | +import com.google.common.collect.ImmutableList; |
3 | 4 | import com.google.common.collect.ImmutableMap; |
| 5 | +import com.mojang.datafixers.util.Pair; |
4 | 6 | import net.minecraft.world.level.block.Block; |
5 | 7 | import net.minecraft.world.level.block.WallBlock; |
6 | 8 | import net.minecraft.world.level.block.state.BlockState; |
|
12 | 14 | import org.spongepowered.asm.mixin.injection.Inject; |
13 | 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; |
14 | 16 |
|
15 | | -import java.util.Arrays; |
16 | 17 | import java.util.HashMap; |
17 | 18 | import java.util.Map; |
18 | 19 |
|
| 20 | +/** |
| 21 | + * Most wall blocks use the default set of vanilla properties, and the default sizes for their shapes. This means |
| 22 | + * there is no need to reconstruct a separate VoxelShape instance for each wall, we can just repurpose the |
| 23 | + * same shape instances. To do this we can cache a mapping between a state (represented only as its prop->value map) |
| 24 | + * and the desired shape, and generate the BlockState->VoxelShape map from this for each block. |
| 25 | + */ |
19 | 26 | @Mixin(WallBlock.class) |
20 | 27 | public abstract class WallBlockMixin extends Block { |
21 | | - private static Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape> CACHE_BY_PROPERTIES = new HashMap<>(); |
22 | | - private static StateDefinition<Block, BlockState> CACHED_DEFINITION = null; |
23 | | - private static float[] CACHED_FLOATS = null; |
| 28 | + private static Map<ImmutableList<Float>, Pair<Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape>, StateDefinition<Block, BlockState>>> CACHE_BY_SHAPE_VALS = new HashMap<>(); |
24 | 29 |
|
25 | 30 | public WallBlockMixin(Properties properties) { |
26 | 31 | super(properties); |
27 | 32 | } |
28 | 33 |
|
29 | 34 | @Inject(method = "makeShapes", at = @At("HEAD"), cancellable = true) |
30 | 35 | private synchronized void useCachedShapeMap(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) { |
31 | | - if(CACHED_DEFINITION != null) { |
32 | | - // check if this state container's properties exactly match the one we used for the cache |
33 | | - if(CACHED_DEFINITION.getProperties().equals(this.stateDefinition.getProperties()) && Arrays.equals(CACHED_FLOATS, new float[] { f1, f2, f3, f4, f5, f6 })) { |
34 | | - ImmutableMap.Builder<BlockState, VoxelShape> builder = ImmutableMap.builder(); |
35 | | - for(BlockState state : this.stateDefinition.getPossibleStates()) { |
36 | | - builder.put(state, CACHE_BY_PROPERTIES.get(state.getValues())); |
37 | | - } |
38 | | - cir.setReturnValue(builder.build()); |
39 | | - } |
| 36 | + ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6); |
| 37 | + Pair<Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape>, StateDefinition<Block, BlockState>> cache = CACHE_BY_SHAPE_VALS.get(key); |
| 38 | + // require the properties to be identical |
| 39 | + if(cache == null || !cache.getSecond().getProperties().equals(this.stateDefinition.getProperties())) |
| 40 | + return; |
| 41 | + ImmutableMap.Builder<BlockState, VoxelShape> builder = ImmutableMap.builder(); |
| 42 | + for(BlockState state : this.stateDefinition.getPossibleStates()) { |
| 43 | + builder.put(state, cache.getFirst().get(state.getValues())); |
40 | 44 | } |
| 45 | + cir.setReturnValue(builder.build()); |
41 | 46 | } |
42 | 47 |
|
43 | 48 | @Inject(method = "makeShapes", at = @At("RETURN")) |
44 | 49 | private synchronized void storeCachedShapesByProperty(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) { |
45 | | - if(CACHE_BY_PROPERTIES.size() == 0) { |
| 50 | + ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6); |
| 51 | + if(!CACHE_BY_SHAPE_VALS.containsKey(key)) { |
| 52 | + Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape> cacheByProperties = new HashMap<>(); |
46 | 53 | Map<BlockState, VoxelShape> shapeMap = cir.getReturnValue(); |
47 | 54 | for(Map.Entry<BlockState, VoxelShape> entry : shapeMap.entrySet()) { |
48 | | - CACHE_BY_PROPERTIES.put(entry.getKey().getValues(), entry.getValue()); |
| 55 | + cacheByProperties.put(entry.getKey().getValues(), entry.getValue()); |
49 | 56 | } |
50 | | - CACHED_FLOATS = new float[] { f1, f2, f3, f4, f5, f6 }; |
51 | | - CACHED_DEFINITION = this.stateDefinition; |
| 57 | + CACHE_BY_SHAPE_VALS.put(key, Pair.of(cacheByProperties, this.stateDefinition)); |
52 | 58 | } |
53 | 59 | } |
54 | 60 | } |
0 commit comments