1919
2020package com .sk89q .worldedit .world .block ;
2121
22- import com .google .common .collect .ImmutableList ;
23- import com .google .common .collect .ImmutableMap ;
24- import com .google .common .collect .Lists ;
25- import com .google .common .collect .Table ;
26- import com .google .common .collect .Tables ;
27- import com .sk89q .worldedit .WorldEdit ;
28- import com .sk89q .worldedit .extension .platform .Capability ;
29- import com .sk89q .worldedit .extension .platform .Watchdog ;
3022import com .sk89q .worldedit .internal .block .BlockStateIdAccess ;
3123import com .sk89q .worldedit .registry .state .Property ;
3224import com .sk89q .worldedit .util .concurrency .LazyReference ;
33- import it .unimi .dsi .fastutil .objects .Reference2ObjectArrayMap ;
3425import org .enginehub .linbus .tree .LinCompoundTag ;
3526
36- import java .util .Collections ;
3727import java .util .HashSet ;
38- import java .util .List ;
3928import java .util .Map ;
4029import java .util .Objects ;
4130import java .util .Set ;
@@ -62,141 +51,46 @@ public void setInternalId(BlockState blockState, int internalId) {
6251
6352 private final BlockType blockType ;
6453 private final Map <Property <?>, Object > values ;
54+ private final int stateListIndex ;
6555
6656 private final BaseBlock emptyBaseBlock ;
6757 private final LazyReference <String > lazyStringRepresentation ;
6858
69- // Neighbouring state table.
70- private Table <Property <?>, Object , BlockState > states ;
71-
7259 /**
7360 * The internal ID of the block state.
7461 */
7562 private volatile int internalId = BlockStateIdAccess .invalidId ();
7663
77- BlockState (BlockType blockType ) {
78- this (blockType , Collections .emptyMap ());
79- }
80-
81- BlockState (BlockType blockType , Map <Property <?>, Object > values ) {
64+ BlockState (BlockType blockType , Map <Property <?>, Object > values , int stateListIndex ) {
8265 this .blockType = blockType ;
8366 this .values = values ;
67+ this .stateListIndex = stateListIndex ;
8468 this .emptyBaseBlock = new BaseBlock (this );
8569 this .lazyStringRepresentation = LazyReference .from (BlockStateHolder .super ::getAsString );
8670 }
8771
88- /**
89- * Generates a map of all possible states for a block type.
90- *
91- * @param blockType The block type
92- * @return The map of states
93- */
94- static Map <Map <Property <?>, Object >, BlockState > generateStateMap (BlockType blockType ) {
95- List <? extends Property <?>> properties = blockType .getProperties ();
96- ImmutableMap .Builder <Map <Property <?>, Object >, BlockState > stateMapBuilder = null ;
97-
98- if (!properties .isEmpty ()) {
99- // Create a list of lists of values, with a copy of the underlying lists
100- List <List <Object >> separatedValues = Lists .newArrayListWithCapacity (properties .size ());
101- for (Property <?> prop : properties ) {
102- separatedValues .add (ImmutableList .copyOf (prop .values ()));
103- }
104-
105- List <List <Object >> valueLists = Lists .cartesianProduct (separatedValues );
106- stateMapBuilder = ImmutableMap .builderWithExpectedSize (valueLists .size ());
107- for (List <Object > valueList : valueLists ) {
108- int valueCount = valueList .size ();
109- Map <Property <?>, Object > valueMap = new Reference2ObjectArrayMap <>(valueCount );
110- for (int i = 0 ; i < valueCount ; i ++) {
111- Property <?> property = properties .get (i );
112- Object value = valueList .get (i );
113- valueMap .put (property , value );
114- }
115- valueMap = Collections .unmodifiableMap (valueMap );
116- stateMapBuilder .put (valueMap , new BlockState (blockType , valueMap ));
117- }
118- }
119-
120- ImmutableMap <Map <Property <?>, Object >, BlockState > stateMap ;
121-
122- if (stateMapBuilder == null ) {
123- // No properties.
124- stateMap = ImmutableMap .of (ImmutableMap .of (), new BlockState (blockType ));
125- } else {
126- stateMap = stateMapBuilder .build ();
127- }
128-
129- Watchdog watchdog = WorldEdit .getInstance ().getPlatformManager ().queryCapability (Capability .GAME_HOOKS )
130- .getWatchdog ();
131- long startTime = System .currentTimeMillis ();
132-
133- for (BlockState state : stateMap .values ()) {
134- state .populate (stateMap );
135-
136- // Sometimes loading can take a while. This is the perfect spot to let MC know we're working.
137- if (watchdog != null ) {
138- watchdog .tick ();
139- }
140- }
141- long timeTaken = System .currentTimeMillis () - startTime ;
142- if (timeTaken > 5000 ) {
143- WorldEdit .logger .warn ("Took more than 5 seconds to generate complete state map for " + blockType .id () + ". This block is likely improperly using properties. State count: " + stateMap .size () + ". " + timeTaken + "ms elapsed." );
144- }
145-
146- return stateMap ;
147- }
148-
149- /**
150- * Creates the underlying state table for object lookups.
151- *
152- * @param stateMap The state map to generate the table from
153- */
154- private void populate (Map <Map <Property <?>, Object >, BlockState > stateMap ) {
155- Table <Property <?>, Object , BlockState > table = Tables .newCustomTable (
156- new Reference2ObjectArrayMap <>(this .values .size ()),
157- Reference2ObjectArrayMap ::new
158- );
159-
160- for (final Map .Entry <Property <?>, Object > entry : this .values .entrySet ()) {
161- final Property <Object > property = (Property <Object >) entry .getKey ();
162-
163- for (Object value : property .values ()) {
164- if (value != entry .getValue ()) {
165- BlockState modifiedState = stateMap .get (this .withValue (property , value ));
166- if (modifiedState != null ) {
167- table .put (property , value , modifiedState );
168- } else {
169- WorldEdit .logger .warn (stateMap );
170- WorldEdit .logger .warn ("Found a null state at " + this .withValue (property , value ));
171- }
172- }
173- }
174- }
175-
176- this .states = Tables .unmodifiableTable (table );
177- }
178-
179- private <V > Map <Property <?>, Object > withValue (final Property <V > property , final V value ) {
180- final Map <Property <?>, Object > values = new Reference2ObjectArrayMap <>(this .values .size ());
181- for (Map .Entry <Property <?>, Object > entry : this .values .entrySet ()) {
182- if (entry .getKey ().equals (property )) {
183- values .put (entry .getKey (), value );
184- } else {
185- values .put (entry .getKey (), entry .getValue ());
186- }
187- }
188- return Collections .unmodifiableMap (values );
189- }
190-
19172 @ Override
19273 public BlockType getBlockType () {
19374 return this .blockType ;
19475 }
19576
19677 @ Override
19778 public <V > BlockState with (final Property <V > property , final V value ) {
198- BlockState result = states .get (property , value );
199- return result == null ? this : result ;
79+ if (this .stateListIndex == -1 ) {
80+ return this ;
81+ }
82+ Object currentValue = this .values .get (property );
83+ if (Objects .equals (currentValue , value )) {
84+ return this ;
85+ }
86+
87+ int newIndex = blockType .getInternalStateList ().updateIndexOrInvalid (
88+ this .stateListIndex , property , currentValue , value
89+ );
90+ if (newIndex == -1 ) {
91+ return this ;
92+ }
93+ return blockType .getInternalStateList ().get (newIndex );
20094 }
20195
20296 @ Override
0 commit comments