Add back statically-set reserved IDs for air blocks only, make it clear they're "reserved" (#1502)

* Add back statically-set reserved IDs for air blocks only, make it clear they're "reserved"
Also:
 - Ensure that reserved is never returned in GET block operations
 - "empty" thus doesn't exist in the GET update methods; remove the needless checks
 - Allow GET/SET chunks to determine their own default values for non-present blocks/sections

* Add comments
This commit is contained in:
Jordan 2021-12-29 16:17:20 +01:00 committed by GitHub
parent bca3a1b04d
commit 177d731957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 109 additions and 117 deletions

View File

@ -425,7 +425,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
);
return 0;
return BlockTypesCache.ReservedIDs.AIR;
}
}
}

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos;
@ -844,16 +845,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
// Section is null, return empty array
if (section == null) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
return data;
}
if (data != null && data.length != 4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) {
@ -878,8 +879,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char ordinal = adapter.ibdIDToOrdinal(paletteVal);
// Don't read "empty".
data[i] = ordinal == 0 ? 1 : ordinal;
data[i] = ordinal;
}
return data;
}
@ -898,18 +898,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
val = ordinal(palette.valueFor(i), adapter);
paletteToOrdinal[i] = val;
}
// Don't read "empty".
if (val == 0) {
val = 1;
}
data[i] = val;
}
} else {
char ordinal = ordinal(palette.valueFor(0), adapter);
// Don't read "empty".
if (ordinal == 0) {
ordinal = 1;
}
Arrays.fill(data, ordinal);
}
} finally {
@ -929,7 +921,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) {
if (ibd == null) {
return 1;
return BlockTypesCache.ReservedIDs.AIR;
} else {
return adapter.adaptToChar(ibd);
}

View File

@ -420,7 +420,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
);
return 0;
return BlockTypesCache.ReservedIDs.AIR;
}
}
}

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos;
@ -874,16 +875,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
// Section is null, return empty array
if (section == null) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
return data;
}
if (data != null && data.length != 4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) {
@ -915,8 +916,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char ordinal = adapter.ibdIDToOrdinal(paletteVal);
// Don't read "empty".
data[i] = ordinal == 0 ? 1 : ordinal;
data[i] = ordinal;
}
return data;
}
@ -935,18 +935,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
val = ordinal(palette.valueFor(i), adapter);
paletteToOrdinal[i] = val;
}
// Don't read "empty".
if (val == 0) {
val = 1;
}
data[i] = val;
}
} else {
char ordinal = ordinal(palette.valueFor(0), adapter);
// Don't read "empty".
if (ordinal == 0) {
ordinal = 1;
}
Arrays.fill(data, ordinal);
}
} finally {
@ -966,7 +958,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) {
if (ibd == null) {
return 1;
return BlockTypesCache.ReservedIDs.AIR;
} else {
return adapter.adaptToChar(ibd);
}

View File

@ -23,8 +23,8 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
int num_palette = 0;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
if (ordinal == 0) {
ordinal = 1;
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
ordinal = BlockTypesCache.ReservedIDs.AIR;
}
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
@ -48,11 +48,11 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
case 0:
ordinal = 1;
case 1:
case 2:
case 3:
case BlockTypesCache.ReservedIDs.__RESERVED__:
ordinal = BlockTypesCache.ReservedIDs.AIR;
case BlockTypesCache.ReservedIDs.AIR:
case BlockTypesCache.ReservedIDs.CAVE_AIR:
case BlockTypesCache.ReservedIDs.VOID_AIR:
air++;
break;
default:
@ -94,13 +94,13 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
char[] getArr = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
if (ordinal == 0) {
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (getArr == null) {
getArr = get.apply(layer);
}
ordinal = getArr[i];
if (ordinal == 0) {
ordinal = 1;
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
ordinal = BlockTypesCache.ReservedIDs.AIR;
}
}
int palette = blockToPalette[ordinal];
@ -119,24 +119,24 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
}
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
}
char lastOrdinal = 0;
char lastOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean lastticking = false;
boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED;
boolean tick_existing = Settings.settings().EXPERIMENTAL.ALLOW_TICK_EXISTING;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
case 0: {
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
if (getArr == null) {
getArr = get.apply(layer);
}
ordinal = getArr[i];
switch (ordinal) {
case 0:
ordinal = 1;
case 1:
case 2:
case 3:
case BlockTypesCache.ReservedIDs.__RESERVED__:
ordinal = BlockTypesCache.ReservedIDs.AIR;
case BlockTypesCache.ReservedIDs.AIR:
case BlockTypesCache.ReservedIDs.CAVE_AIR:
case BlockTypesCache.ReservedIDs.VOID_AIR:
air++;
break;
default:
@ -151,23 +151,19 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
}
if (ticking) {
BlockState state = BlockState.getFromOrdinal(ordinal);
ticking_blocks
.put(
BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin.getInstance().getBukkitImplAdapter()
.getInternalBlockStateId(state).orElse(0)
);
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBlockStateId(state)
.orElse(0)
);
}
}
}
set[i] = ordinal;
break;
}
case 1:
case 2:
case 3:
air++;
break;
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> air++;
}
if (!fastmode && tick_placed) {
boolean ticking;

View File

@ -30,6 +30,7 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
@ -185,8 +186,8 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
for (int x = 0; x < 16; x++, index++) {
int xx = bx + x;
int from = blocksGet[index];
if (from == 0) {
from = 1;
if (from == BlockTypesCache.ReservedIDs.__RESERVED__) {
from = BlockTypesCache.ReservedIDs.AIR;
}
final int combinedFrom = from;
final int combinedTo = blocksSet[index];

View File

@ -9,6 +9,7 @@ import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import javax.annotation.Nullable;
@ -115,11 +116,11 @@ public interface IBlocks extends Trimable {
for (int i = 0; i < ids.length; i++) {
char ordinal = ids[i];
switch (ordinal) {
case 0:
case 2:
case 3:
ids[i] = 1;
case 1:
case BlockTypesCache.ReservedIDs.__RESERVED__:
case BlockTypesCache.ReservedIDs.CAVE_AIR:
case BlockTypesCache.ReservedIDs.VOID_AIR:
ids[i] = BlockTypesCache.ReservedIDs.AIR;
case BlockTypesCache.ReservedIDs.AIR:
continue;
default:
nonEmpty++;
@ -139,10 +140,10 @@ public interface IBlocks extends Trimable {
for (int i = 0; i < palette.paletteToBlockLength; i++) {
int ordinal = palette.paletteToBlock[i];
switch (ordinal) {
case 0:
case 2:
case 3:
case 1:
case BlockTypesCache.ReservedIDs.__RESERVED__:
case BlockTypesCache.ReservedIDs.AIR:
case BlockTypesCache.ReservedIDs.CAVE_AIR:
case BlockTypesCache.ReservedIDs.VOID_AIR:
sectionWriter.write(0);
break;
default:

View File

@ -9,6 +9,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import javax.annotation.Nullable;
import java.util.Arrays;
@ -59,7 +60,7 @@ public class BitSetBlocks implements IChunkSet {
for (int y = 0, index = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, index++) {
if (data[index] != 0) {
if (data[index] != BlockTypesCache.ReservedIDs.__RESERVED__) {
row.set(null, x, by + y, z, minSectionPosition, maxSectionPosition);
}
}

View File

@ -134,7 +134,7 @@ public abstract class CharBlocks implements IBlocks {
return new char[4096];
}
for (int i = 0; i < 4096; i++) {
data[i] = 0;
data[i] = defaultOrdinal();
}
return data;
}
@ -188,11 +188,16 @@ public abstract class CharBlocks implements IBlocks {
int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;
if (layer > maxSectionPosition || layer < minSectionPosition) {
return 0;
return defaultOrdinal();
}
return get(layer, index);
}
/**
* Default char value to be used when "updating"/resetting data arrays
*/
protected abstract char defaultOrdinal();
// Not synchronized as it refers to a synchronized method and includes nothing that requires synchronization
public void set(int x, int y, int z, char value) {
final int layer = y >> 4;

View File

@ -37,10 +37,15 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
if (data == null) {
data = new char[4096];
}
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
return data;
}
@Override
protected char defaultOrdinal() {
return BlockTypesCache.ReservedIDs.AIR;
}
@Override
public synchronized boolean trim(boolean aggressive, int layer) {
layer -= minSectionPosition;

View File

@ -11,6 +11,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import java.util.Arrays;
import java.util.Collections;
@ -326,6 +327,11 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
return super.load(layer);
}
@Override
protected char defaultOrdinal() {
return BlockTypesCache.ReservedIDs.__RESERVED__;
}
// Checks and updates the various section arrays against the new layer index
private void updateSectionIndexRange(int layer) {
if (layer >= minSectionPosition && layer <= maxSectionPosition) {

View File

@ -13,6 +13,7 @@ import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.worldedit.world.registry.Registries;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -220,55 +221,30 @@ public class BlockTypesCache {
BIT_MASK = ((1 << BIT_OFFSET) - 1);
values = new BlockType[size];
/*Field[] idFields = BlockID.class.getDeclaredFields();
for (Field field : idFields) {
size = Math.max(field.getInt(null) + 1, size);
}
// Register the statically declared ones first
for (Field field : idFields) {
if (field.getType() == int.class) {
int internalId = field.getInt(null);
String id = "minecraft:" + field.getName().toLowerCase(Locale.ROOT);
String defaultState = blockMap.remove(id);
if (defaultState == null) {
if (internalId != 0) {
continue;
}
defaultState = id;
}
if (values[internalId] != null) {
throw new IllegalStateException("Invalid duplicate id for " + field.getName());
}
BlockType type = register(defaultState, internalId, stateList, tickList);
// Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty
values[internalId] = type;
}
}*/
// Register "Reserved". Ensure air/reserved and 0/1/2/3
// Register reserved IDs. Ensure air/reserved are 0/1/2/3
{
int internalId = 0;
for (String id : new String[]{"minecraft:__reserved__", "minecraft:air", "minecraft:cave_air",
"minecraft:void_air"}) {
String defaultState = blockMap.remove(id);
if (defaultState == null) {
defaultState = id;
for (Field field : ReservedIDs.class.getDeclaredFields()) {
if (field.getType() == int.class) {
int internalId = field.getInt(null);
String id = "minecraft:" + field.getName().toLowerCase(Locale.ROOT);
String defaultState = blockMap.remove(id);
if (defaultState == null) {
defaultState = id;
}
if (values[internalId] != null) {
throw new IllegalStateException(String.format(
"Invalid duplicate id for %s! Something has gone very wrong. Are " +
"any plugins shading FAWE?!", id));
}
BlockType type = register(defaultState, internalId, stateList, tickList);
// Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty
values[internalId] = type;
}
if (values[internalId] != null) {
throw new IllegalStateException(
"Invalid duplicate id for __reserved__! Something has gone very wrong. Are " +
"any plugins shading FAWE?!");
}
BlockType type = register(defaultState, internalId, stateList, tickList);
// Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty
values[internalId] = type;
internalId++;
}
}
{ // Register real blocks
int internalId = 1;
int internalId = 0;
for (Map.Entry<String, String> entry : blockMap.entrySet()) {
String defaultState = entry.getValue();
// Skip already registered ids
@ -328,4 +304,15 @@ public class BlockTypesCache {
}
}
/**
* Statically-set reserved IDs. Should be used as minimally as possible, and for IDs that will see frequent use
*/
public static class ReservedIDs {
public static final int __RESERVED__ = 0;
public static final int AIR = 1;
public static final int CAVE_AIR = 2;
public static final int VOID_AIR = 3;
}
}

View File

@ -0,0 +1,6 @@
/**
* The following classes are FAWE additions:
*
* @see com.sk89q.worldedit.world.block.BlockTypesCache
*/
package com.sk89q.worldedit.world.block;