mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-25 19:45:21 +01:00
Lots of small and less small blockconnection optimization
- blockConnections.json data is now stored more compact and with direct block state ids in blockConnections.nbt - For PacketBlockConnectionProvider, the server now longer spams unnecessary block change packets if the connectable block did not actually change - Some other, small optimizations within the individual connection handlers
This commit is contained in:
parent
9781b7962f
commit
72197ddca8
@ -21,29 +21,33 @@ import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class AbstractFenceConnectionHandler extends ConnectionHandler {
|
||||
private static final StairConnectionHandler STAIR_CONNECTION_HANDLER = new StairConnectionHandler();
|
||||
private final String blockConnections;
|
||||
private final Set<Integer> blockStates = new HashSet<>();
|
||||
private final Map<Byte, Integer> connectedBlockStates = new HashMap<>();
|
||||
private final IntSet blockStates = new IntOpenHashSet();
|
||||
private final int[] connectedBlockStates = new int[statesSize()];
|
||||
private final int blockConnectionsTypeId;
|
||||
|
||||
protected AbstractFenceConnectionHandler(String blockConnections) {
|
||||
this.blockConnections = blockConnections;
|
||||
this.blockConnectionsTypeId = blockConnections != null ? BlockData.connectionTypeId(blockConnections) : -1;
|
||||
Arrays.fill(connectedBlockStates, -1);
|
||||
}
|
||||
|
||||
public ConnectionData.ConnectorInitAction getInitAction(final String key) {
|
||||
final AbstractFenceConnectionHandler handler = this;
|
||||
return blockData -> {
|
||||
if (key.equals(blockData.getMinecraftKey())) {
|
||||
if (blockData.hasData("waterlogged") && blockData.getValue("waterlogged").equals("true")) return;
|
||||
if (blockData.hasData("waterlogged") && blockData.getValue("waterlogged").equals("true")) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockStates.add(blockData.getSavedBlockStateId());
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler);
|
||||
connectedBlockStates.put(getStates(blockData), blockData.getSavedBlockStateId());
|
||||
byte internalStateId = getStates(blockData);
|
||||
connectedBlockStates[internalStateId] = blockData.getSavedBlockStateId();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -67,6 +71,10 @@ public abstract class AbstractFenceConnectionHandler extends ConnectionHandler {
|
||||
return states;
|
||||
}
|
||||
|
||||
protected byte statesSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockData(UserConnection user, Position position) {
|
||||
return STAIR_CONNECTION_HANDLER.connect(user, position, super.getBlockData(user, position));
|
||||
@ -74,19 +82,19 @@ public abstract class AbstractFenceConnectionHandler extends ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
final Integer newBlockState = connectedBlockStates.get(getStates(user, position, blockState));
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
final int newBlockState = connectedBlockStates[getStates(user, position, blockState)];
|
||||
return newBlockState == -1 ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
protected boolean connects(BlockFace side, int blockState, boolean pre1_12) {
|
||||
if (blockStates.contains(blockState)) return true;
|
||||
if (blockConnections == null) return false;
|
||||
if (blockConnectionsTypeId == -1) return false;
|
||||
|
||||
BlockData blockData = ConnectionData.blockConnectionData.get(blockState);
|
||||
return blockData != null && blockData.connectsTo(blockConnections, side.opposite(), pre1_12);
|
||||
return blockData != null && blockData.connectsTo(blockConnectionsTypeId, side.opposite(), pre1_12);
|
||||
}
|
||||
|
||||
public Set<Integer> getBlockStates() {
|
||||
public IntSet getBlockStates() {
|
||||
return blockStates;
|
||||
}
|
||||
}
|
||||
|
@ -20,17 +20,17 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractStempConnectionHandler extends ConnectionHandler {
|
||||
private static final BlockFace[] BLOCK_FACES = {BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST};
|
||||
|
||||
private final IntSet blockId = new IntOpenHashSet();
|
||||
private final int baseStateId;
|
||||
private final Set<Integer> blockId = new HashSet<>();
|
||||
|
||||
private final Map<BlockFace, Integer> stemps = new EnumMap<>(BlockFace.class);
|
||||
|
||||
|
@ -24,12 +24,12 @@ public class BasicFenceConnectionHandler extends AbstractFenceConnectionHandler
|
||||
|
||||
static List<ConnectionData.ConnectorInitAction> init() {
|
||||
List<ConnectionData.ConnectorInitAction> actions = new ArrayList<>();
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:oak_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:birch_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:jungle_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:dark_oak_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:acacia_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fenceConnections").getInitAction("minecraft:spruce_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:oak_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:birch_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:jungle_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:dark_oak_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:acacia_fence"));
|
||||
actions.add(new BasicFenceConnectionHandler("fence").getInitAction("minecraft:spruce_fence"));
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -17,25 +17,34 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockData {
|
||||
private final Map<String, boolean[]> connectData = new HashMap<>();
|
||||
public final class BlockData {
|
||||
private static final List<String> CONNECTION_TYPES = Arrays.asList("fence", "netherFence", "pane", "cobbleWall", "redstone", "allFalseIfStairPre1_12");
|
||||
private static final int MAGIC_STAIRS_ID = connectionTypeId("allFalseIfStairPre1_12");
|
||||
private final Int2ObjectMap<boolean[]> connectData = new Int2ObjectArrayMap<>();
|
||||
|
||||
public void put(String key, boolean[] booleans) {
|
||||
connectData.put(key, booleans);
|
||||
public void put(final int blockConnectionTypeId, final boolean[] booleans) {
|
||||
connectData.put(blockConnectionTypeId, booleans);
|
||||
}
|
||||
|
||||
public boolean connectsTo(String blockConnection, BlockFace face, boolean pre1_12AbstractFence) {
|
||||
boolean[] booleans = null;
|
||||
if (pre1_12AbstractFence) {
|
||||
booleans = connectData.get("allFalseIfStairPre1_12"); // https://minecraft.gamepedia.com/Java_Edition_1.12
|
||||
}
|
||||
if (booleans == null) {
|
||||
booleans = connectData.get(blockConnection);
|
||||
public boolean connectsTo(final int blockConnectionTypeId, final BlockFace face, final boolean pre1_12AbstractFence) {
|
||||
if (pre1_12AbstractFence && connectData.containsKey(MAGIC_STAIRS_ID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean[] booleans = connectData.get(blockConnectionTypeId);
|
||||
return booleans != null && booleans[face.ordinal()];
|
||||
}
|
||||
|
||||
public static int connectionTypeId(final String blockConnection) {
|
||||
final int connectionTypeId = CONNECTION_TYPES.indexOf(blockConnection);
|
||||
Preconditions.checkArgument(connectionTypeId != -1, "Unknown connection type: " + blockConnection);
|
||||
return connectionTypeId;
|
||||
}
|
||||
}
|
||||
|
@ -20,28 +20,33 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class ChestConnectionHandler extends ConnectionHandler {
|
||||
private static final Map<Integer, BlockFace> chestFacings = new HashMap<>();
|
||||
private static final Map<Byte, Integer> connectedStates = new HashMap<>();
|
||||
private static final Set<Integer> trappedChests = new HashSet<>();
|
||||
private static final Int2ObjectMap<BlockFace> CHEST_FACINGS = new Int2ObjectOpenHashMap<>();
|
||||
private static final int[] CONNECTED_STATES = new int[32];
|
||||
private static final IntSet TRAPPED_CHESTS = new IntOpenHashSet();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
Arrays.fill(CONNECTED_STATES, -1);
|
||||
final ChestConnectionHandler connectionHandler = new ChestConnectionHandler();
|
||||
return blockData -> {
|
||||
if (!blockData.getMinecraftKey().equals("minecraft:chest") && !blockData.getMinecraftKey().equals("minecraft:trapped_chest"))
|
||||
if (!blockData.getMinecraftKey().equals("minecraft:chest") && !blockData.getMinecraftKey().equals("minecraft:trapped_chest")) {
|
||||
return;
|
||||
if (blockData.getValue("waterlogged").equals("true")) return;
|
||||
chestFacings.put(blockData.getSavedBlockStateId(), BlockFace.valueOf(blockData.getValue("facing").toUpperCase(Locale.ROOT)));
|
||||
if (blockData.getMinecraftKey().equalsIgnoreCase("minecraft:trapped_chest")) {
|
||||
trappedChests.add(blockData.getSavedBlockStateId());
|
||||
}
|
||||
connectedStates.put(getStates(blockData), blockData.getSavedBlockStateId());
|
||||
if (blockData.getValue("waterlogged").equals("true")) {
|
||||
return;
|
||||
}
|
||||
CHEST_FACINGS.put(blockData.getSavedBlockStateId(), BlockFace.valueOf(blockData.getValue("facing").toUpperCase(Locale.ROOT)));
|
||||
if (blockData.getMinecraftKey().equalsIgnoreCase("minecraft:trapped_chest")) {
|
||||
TRAPPED_CHESTS.add(blockData.getSavedBlockStateId());
|
||||
}
|
||||
CONNECTED_STATES[getStates(blockData)] = blockData.getSavedBlockStateId();
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), connectionHandler);
|
||||
};
|
||||
}
|
||||
@ -58,22 +63,27 @@ class ChestConnectionHandler extends ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
BlockFace facing = chestFacings.get(blockState);
|
||||
BlockFace facing = CHEST_FACINGS.get(blockState);
|
||||
byte states = 0;
|
||||
states |= (facing.ordinal() << 2);
|
||||
boolean trapped = trappedChests.contains(blockState);
|
||||
if (trapped) states |= 16;
|
||||
|
||||
boolean trapped = TRAPPED_CHESTS.contains(blockState);
|
||||
if (trapped) {
|
||||
states |= 16;
|
||||
}
|
||||
|
||||
int relative;
|
||||
if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.NORTH))) && trapped == trappedChests.contains(relative)) {
|
||||
if (CHEST_FACINGS.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.NORTH))) && trapped == TRAPPED_CHESTS.contains(relative)) {
|
||||
states |= facing == BlockFace.WEST ? 1 : 2;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.SOUTH))) && trapped == trappedChests.contains(relative)) {
|
||||
} else if (CHEST_FACINGS.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.SOUTH))) && trapped == TRAPPED_CHESTS.contains(relative)) {
|
||||
states |= facing == BlockFace.EAST ? 1 : 2;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.WEST))) && trapped == trappedChests.contains(relative)) {
|
||||
} else if (CHEST_FACINGS.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.WEST))) && trapped == TRAPPED_CHESTS.contains(relative)) {
|
||||
states |= facing == BlockFace.NORTH ? 2 : 1;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.EAST))) && trapped == trappedChests.contains(relative)) {
|
||||
} else if (CHEST_FACINGS.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.EAST))) && trapped == TRAPPED_CHESTS.contains(relative)) {
|
||||
states |= facing == BlockFace.SOUTH ? 2 : 1;
|
||||
}
|
||||
Integer newBlockState = connectedStates.get(states);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
|
||||
int newBlockState = CONNECTED_STATES[states];
|
||||
return newBlockState == -1 ? blockState : newBlockState;
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,11 @@ public class ChorusPlantConnectionHandler extends AbstractFenceConnectionHandler
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte statesSize() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = super.getStates(user, position, blockState);
|
||||
|
@ -17,9 +17,12 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
@ -46,17 +49,19 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public final class ConnectionData {
|
||||
private static final BlockChangeRecord1_8[] EMPTY_RECORDS = new BlockChangeRecord1_8[0];
|
||||
public static BlockConnectionProvider blockConnectionProvider;
|
||||
static Int2ObjectMap<String> idToKey = new Int2ObjectOpenHashMap<>(8582, .99F);
|
||||
static Object2IntMap<String> keyToId = new Object2IntOpenHashMap<>(8582, .99F);
|
||||
static Int2ObjectMap<ConnectionHandler> connectionHandlerMap = new Int2ObjectOpenHashMap<>(1);
|
||||
static Int2ObjectMap<BlockData> blockConnectionData = new Int2ObjectOpenHashMap<>(1);
|
||||
static IntSet occludingStates = new IntOpenHashSet(377, .99F);
|
||||
static final Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>(8582, .99F);
|
||||
static final IntSet OCCLUDING_STATES = new IntOpenHashSet(377, .99F);
|
||||
static Int2ObjectMap<ConnectionHandler> connectionHandlerMap = new Int2ObjectOpenHashMap<>();
|
||||
static Int2ObjectMap<BlockData> blockConnectionData = new Int2ObjectOpenHashMap<>();
|
||||
private static final BlockChangeRecord1_8[] EMPTY_RECORDS = new BlockChangeRecord1_8[0];
|
||||
|
||||
static {
|
||||
KEY_TO_ID.defaultReturnValue(-1);
|
||||
}
|
||||
|
||||
public static void update(UserConnection user, Position position) throws Exception {
|
||||
for (BlockFace face : BlockFace.values()) {
|
||||
@ -68,10 +73,12 @@ public final class ConnectionData {
|
||||
}
|
||||
|
||||
int newBlockState = handler.connect(user, pos, blockState);
|
||||
if (newBlockState == blockState) {
|
||||
if (newBlockState == blockState && blockConnectionProvider.storesBlocks()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateBlockStorage(user, pos.x(), pos.y(), pos.z(), newBlockState);
|
||||
|
||||
PacketWrapper blockUpdatePacket = PacketWrapper.create(ClientboundPackets1_13.BLOCK_CHANGE, null, user);
|
||||
blockUpdatePacket.write(Type.POSITION, pos);
|
||||
blockUpdatePacket.write(Type.VAR_INT, newBlockState);
|
||||
@ -103,7 +110,10 @@ public final class ConnectionData {
|
||||
|
||||
for (int s = 0; s < chunk.getSections().length; s++) {
|
||||
ChunkSection section = chunk.getSections()[s];
|
||||
if (section == null) continue;
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DataPalette blocks = section.palette(PaletteType.BLOCKS);
|
||||
|
||||
boolean willConnect = false;
|
||||
@ -114,16 +124,25 @@ public final class ConnectionData {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willConnect) continue;
|
||||
if (!willConnect) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int yOff = s << 4;
|
||||
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
ConnectionHandler handler = ConnectionData.getConnectionHandler(id);
|
||||
if (handler == null) continue;
|
||||
id = handler.connect(user, new Position(xOff + ChunkSection.xFromIndex(idx), yOff + ChunkSection.yFromIndex(idx), zOff + ChunkSection.zFromIndex(idx)), id);
|
||||
blocks.setIdAt(idx, id);
|
||||
if (handler == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Position position = new Position(xOff + ChunkSection.xFromIndex(idx), yOff + ChunkSection.yFromIndex(idx), zOff + ChunkSection.zFromIndex(idx));
|
||||
int connectedId = handler.connect(user, position, id);
|
||||
if (connectedId != id) {
|
||||
blocks.setIdAt(idx, connectedId);
|
||||
updateBlockStorage(user, position.x(), position.y(), position.z(), connectedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,39 +156,49 @@ public final class ConnectionData {
|
||||
ListTag blockStates = MappingDataLoader.loadNBT("blockstates-1.13.nbt").get("blockstates");
|
||||
for (int id = 0; id < blockStates.size(); id++) {
|
||||
String key = (String) blockStates.get(id).getValue();
|
||||
idToKey.put(id, key);
|
||||
keyToId.put(key, id);
|
||||
KEY_TO_ID.put(key, id);
|
||||
}
|
||||
|
||||
connectionHandlerMap = new Int2ObjectOpenHashMap<>(3650, .99F);
|
||||
|
||||
if (!Via.getConfig().isReduceBlockStorageMemory()) {
|
||||
blockConnectionData = new Int2ObjectOpenHashMap<>(1146, .99F);
|
||||
JsonObject mappingBlockConnections = MappingDataLoader.loadData("blockConnections.json");
|
||||
for (Entry<String, JsonElement> entry : mappingBlockConnections.entrySet()) {
|
||||
int id = keyToId.getInt(entry.getKey());
|
||||
blockConnectionData = new Int2ObjectOpenHashMap<>(2048);
|
||||
|
||||
ListTag blockConnectionMappings = MappingDataLoader.loadNBT("blockConnections.nbt").get("data");
|
||||
for (Tag blockTag : blockConnectionMappings) {
|
||||
CompoundTag blockCompoundTag = (CompoundTag) blockTag;
|
||||
BlockData blockData = new BlockData();
|
||||
for (Entry<String, JsonElement> type : entry.getValue().getAsJsonObject().entrySet()) {
|
||||
String name = type.getKey();
|
||||
JsonObject object = type.getValue().getAsJsonObject();
|
||||
boolean[] data = new boolean[6];
|
||||
for (BlockFace value : BlockFace.values()) {
|
||||
String face = value.toString().toLowerCase(Locale.ROOT);
|
||||
if (object.has(face)) {
|
||||
data[value.ordinal()] = object.getAsJsonPrimitive(face).getAsBoolean();
|
||||
}
|
||||
for (Entry<String, Tag> entry : blockCompoundTag.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.equals("id") || key.equals("ids")) {
|
||||
continue;
|
||||
}
|
||||
blockData.put(name, data);
|
||||
|
||||
|
||||
boolean[] attachingFaces = new boolean[4];
|
||||
ByteArrayTag connections = (ByteArrayTag) entry.getValue();
|
||||
for (byte blockFaceId : connections.getValue()) {
|
||||
attachingFaces[blockFaceId] = true;
|
||||
}
|
||||
|
||||
int connectionTypeId = Integer.parseInt(key);
|
||||
blockData.put(connectionTypeId, attachingFaces);
|
||||
}
|
||||
if (entry.getKey().contains("stairs")) {
|
||||
blockData.put("allFalseIfStairPre1_12", new boolean[6]);
|
||||
|
||||
NumberTag idTag = blockCompoundTag.get("id");
|
||||
if (idTag != null) {
|
||||
blockConnectionData.put(idTag.asInt(), blockData);
|
||||
} else {
|
||||
IntArrayTag idsTag = blockCompoundTag.get("ids");
|
||||
for (int id : idsTag.getValue()) {
|
||||
blockConnectionData.put(id, blockData);
|
||||
}
|
||||
}
|
||||
blockConnectionData.put(id, blockData);
|
||||
}
|
||||
}
|
||||
|
||||
for (String state : occludingBlockStates()) {
|
||||
occludingStates.add(keyToId.getInt(state));
|
||||
OCCLUDING_STATES.add(KEY_TO_ID.getInt(state));
|
||||
}
|
||||
|
||||
List<ConnectorInitAction> initActions = new ArrayList<>();
|
||||
@ -192,7 +221,7 @@ public final class ConnectionData {
|
||||
initActions.add(VineConnectionHandler.init());
|
||||
}
|
||||
|
||||
for (String key : keyToId.keySet()) {
|
||||
for (String key : KEY_TO_ID.keySet()) {
|
||||
WrappedBlockData wrappedBlockData = WrappedBlockData.fromString(key);
|
||||
for (ConnectorInitAction action : initActions) {
|
||||
action.check(wrappedBlockData);
|
||||
@ -223,11 +252,7 @@ public final class ConnectionData {
|
||||
}
|
||||
|
||||
public static int getId(String key) {
|
||||
return keyToId.getOrDefault(Key.stripMinecraftNamespace(key), -1);
|
||||
}
|
||||
|
||||
public static String getKey(int id) {
|
||||
return idToKey.get(id);
|
||||
return KEY_TO_ID.getOrDefault(Key.stripMinecraftNamespace(key), -1);
|
||||
}
|
||||
|
||||
private static String[] occludingBlockStates() {
|
||||
@ -619,10 +644,10 @@ public final class ConnectionData {
|
||||
}
|
||||
|
||||
public static Object2IntMap<String> getKeyToId() {
|
||||
return keyToId;
|
||||
return KEY_TO_ID;
|
||||
}
|
||||
|
||||
public static class NeighbourUpdater {
|
||||
public static final class NeighbourUpdater {
|
||||
private final UserConnection user;
|
||||
private final UserBlockData userBlockData;
|
||||
|
||||
@ -701,8 +726,9 @@ public final class ConnectionData {
|
||||
|
||||
Position pos = new Position(x, y, z);
|
||||
int newBlockState = handler.connect(user, pos, blockState);
|
||||
if (blockState != newBlockState) {
|
||||
if (blockState != newBlockState || !blockConnectionProvider.storesBlocks()) {
|
||||
records.add(new BlockChangeRecord1_8(x & 0xF, y, z & 0xF, newBlockState));
|
||||
updateBlockStorage(user, x, y, z, newBlockState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,14 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
|
||||
public abstract class ConnectionHandler {
|
||||
|
||||
public abstract int connect(UserConnection user, Position position, int blockState);
|
||||
|
||||
public int getBlockData(UserConnection user, Position position) {
|
||||
return Via.getManager().getProviders().get(BlockConnectionProvider.class).getBlockData(user, position.x(), position.y(), position.z());
|
||||
return ConnectionData.blockConnectionProvider.getBlockData(user, position.x(), position.y(), position.z());
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -27,8 +29,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class DoorConnectionHandler extends ConnectionHandler {
|
||||
private static final Map<Integer, DoorData> doorDataMap = new HashMap<>();
|
||||
private static final Map<Short, Integer> connectedStates = new HashMap<>();
|
||||
private static final Int2ObjectMap<DoorData> DOOR_DATA_MAP = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<Short, Integer> CONNECTED_STATES = new HashMap<>();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final List<String> baseDoors = new LinkedList<>();
|
||||
@ -56,9 +58,9 @@ public class DoorConnectionHandler extends ConnectionHandler {
|
||||
type
|
||||
);
|
||||
|
||||
doorDataMap.put(id, doorData);
|
||||
DOOR_DATA_MAP.put(id, doorData);
|
||||
|
||||
connectedStates.put(getStates(doorData), id);
|
||||
CONNECTED_STATES.put(getStates(doorData), id);
|
||||
|
||||
ConnectionData.connectionHandlerMap.put(id, connectionHandler);
|
||||
};
|
||||
@ -77,12 +79,12 @@ public class DoorConnectionHandler extends ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
DoorData doorData = doorDataMap.get(blockState);
|
||||
DoorData doorData = DOOR_DATA_MAP.get(blockState);
|
||||
if (doorData == null) return blockState;
|
||||
short s = 0;
|
||||
s |= (doorData.getType() & 0x7) << 6;
|
||||
if (doorData.isLower()) {
|
||||
DoorData upperHalf = doorDataMap.get(getBlockData(user, position.getRelative(BlockFace.TOP)));
|
||||
DoorData upperHalf = DOOR_DATA_MAP.get(getBlockData(user, position.getRelative(BlockFace.TOP)));
|
||||
if (upperHalf == null) return blockState;
|
||||
s |= 1;
|
||||
if (doorData.isOpen()) s |= 2;
|
||||
@ -90,7 +92,7 @@ public class DoorConnectionHandler extends ConnectionHandler {
|
||||
if (upperHalf.isRightHinge()) s |= 8;
|
||||
s |= doorData.getFacing().ordinal() << 4;
|
||||
} else {
|
||||
DoorData lowerHalf = doorDataMap.get(getBlockData(user, position.getRelative(BlockFace.BOTTOM)));
|
||||
DoorData lowerHalf = DOOR_DATA_MAP.get(getBlockData(user, position.getRelative(BlockFace.BOTTOM)));
|
||||
if (lowerHalf == null) return blockState;
|
||||
if (lowerHalf.isOpen()) s |= 2;
|
||||
if (doorData.isPowered()) s |= 4;
|
||||
@ -98,7 +100,7 @@ public class DoorConnectionHandler extends ConnectionHandler {
|
||||
s |= lowerHalf.getFacing().ordinal() << 4;
|
||||
}
|
||||
|
||||
Integer newBlockState = connectedStates.get(s);
|
||||
Integer newBlockState = CONNECTED_STATES.get(s);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
|
@ -20,15 +20,15 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import java.util.HashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class FireConnectionHandler extends ConnectionHandler {
|
||||
private static final String[] WOOD_TYPES = {"oak", "spruce", "birch", "jungle", "acacia", "dark_oak"};
|
||||
private static final Map<Byte, Integer> connectedBlocks = new HashMap<>();
|
||||
private static final Set<Integer> flammableBlocks = new HashSet<>();
|
||||
private static final int[] CONNECTED_BLOCKS = new int[32];
|
||||
private static final IntSet FLAMMABLE_BLOCKS = new IntOpenHashSet();
|
||||
|
||||
private static void addWoodTypes(Set<String> set, String suffix) {
|
||||
for (String woodType : WOOD_TYPES) {
|
||||
@ -55,10 +55,10 @@ public class FireConnectionHandler extends ConnectionHandler {
|
||||
return blockData -> {
|
||||
String key = blockData.getMinecraftKey();
|
||||
if (key.contains("_wool") || key.contains("_carpet") || flammabeIds.contains(key)) {
|
||||
flammableBlocks.add(blockData.getSavedBlockStateId());
|
||||
FLAMMABLE_BLOCKS.add(blockData.getSavedBlockStateId());
|
||||
} else if (key.equals("minecraft:fire")) {
|
||||
int id = blockData.getSavedBlockStateId();
|
||||
connectedBlocks.put(getStates(blockData), id);
|
||||
CONNECTED_BLOCKS[getStates(blockData)] = id;
|
||||
ConnectionData.connectionHandlerMap.put(id, connectionHandler);
|
||||
}
|
||||
};
|
||||
@ -77,11 +77,11 @@ public class FireConnectionHandler extends ConnectionHandler {
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
byte states = 0;
|
||||
if (flammableBlocks.contains(getBlockData(user, position.getRelative(BlockFace.EAST)))) states |= 1;
|
||||
if (flammableBlocks.contains(getBlockData(user, position.getRelative(BlockFace.NORTH)))) states |= 2;
|
||||
if (flammableBlocks.contains(getBlockData(user, position.getRelative(BlockFace.SOUTH)))) states |= 4;
|
||||
if (flammableBlocks.contains(getBlockData(user, position.getRelative(BlockFace.TOP)))) states |= 8;
|
||||
if (flammableBlocks.contains(getBlockData(user, position.getRelative(BlockFace.WEST)))) states |= 16;
|
||||
return connectedBlocks.get(states);
|
||||
if (FLAMMABLE_BLOCKS.contains(getBlockData(user, position.getRelative(BlockFace.EAST)))) states |= 1;
|
||||
if (FLAMMABLE_BLOCKS.contains(getBlockData(user, position.getRelative(BlockFace.NORTH)))) states |= 2;
|
||||
if (FLAMMABLE_BLOCKS.contains(getBlockData(user, position.getRelative(BlockFace.SOUTH)))) states |= 4;
|
||||
if (FLAMMABLE_BLOCKS.contains(getBlockData(user, position.getRelative(BlockFace.TOP)))) states |= 8;
|
||||
if (FLAMMABLE_BLOCKS.contains(getBlockData(user, position.getRelative(BlockFace.WEST)))) states |= 16;
|
||||
return CONNECTED_BLOCKS[states];
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import java.util.Set;
|
||||
|
||||
|
||||
public class FlowerConnectionHandler extends ConnectionHandler {
|
||||
private static final Int2IntMap flowers = new Int2IntOpenHashMap();
|
||||
private static final Int2IntMap FLOWERS = new Int2IntOpenHashMap();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final Set<String> baseFlower = new HashSet<>();
|
||||
@ -45,7 +45,7 @@ public class FlowerConnectionHandler extends ConnectionHandler {
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler);
|
||||
if (blockData.getValue("half").equals("lower")) {
|
||||
blockData.set("half", "upper");
|
||||
flowers.put(blockData.getSavedBlockStateId(), blockData.getBlockStateId());
|
||||
FLOWERS.put(blockData.getSavedBlockStateId(), blockData.getBlockStateId());
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -54,14 +54,14 @@ public class FlowerConnectionHandler extends ConnectionHandler {
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
int blockBelowId = getBlockData(user, position.getRelative(BlockFace.BOTTOM));
|
||||
int connectBelow = flowers.get(blockBelowId);
|
||||
int connectBelow = FLOWERS.get(blockBelowId);
|
||||
if (connectBelow != 0) {
|
||||
int blockAboveId = getBlockData(user, position.getRelative(BlockFace.TOP));
|
||||
if (Via.getConfig().isStemWhenBlockAbove()) {
|
||||
if (blockAboveId == 0) {
|
||||
return connectBelow;
|
||||
}
|
||||
} else if (!flowers.containsKey(blockAboveId)) {
|
||||
} else if (!FLOWERS.containsKey(blockAboveId)) {
|
||||
return connectBelow;
|
||||
}
|
||||
}
|
||||
|
@ -27,24 +27,24 @@ public class GlassConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static List<ConnectionData.ConnectorInitAction> init() {
|
||||
List<ConnectionData.ConnectorInitAction> actions = new ArrayList<>(18);
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:white_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:orange_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:magenta_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:light_blue_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:yellow_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:lime_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:pink_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:gray_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:light_gray_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:cyan_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:purple_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:blue_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:brown_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:green_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:red_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:black_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("paneConnections").getInitAction("minecraft:iron_bars"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:white_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:orange_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:magenta_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:light_blue_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:yellow_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:lime_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:pink_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:gray_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:light_gray_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:cyan_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:purple_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:blue_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:brown_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:green_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:red_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:black_stained_glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:glass_pane"));
|
||||
actions.add(new GlassConnectionHandler("pane").getInitAction("minecraft:iron_bars"));
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
public class NetherFenceConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
return new NetherFenceConnectionHandler("netherFenceConnections").getInitAction("minecraft:nether_brick_fence");
|
||||
return new NetherFenceConnectionHandler("netherFence").getInitAction("minecraft:nether_brick_fence");
|
||||
}
|
||||
|
||||
public NetherFenceConnectionHandler(String blockConnections) {
|
||||
|
@ -22,23 +22,27 @@ import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
public class RedstoneConnectionHandler extends ConnectionHandler {
|
||||
private static final Set<Integer> redstone = new HashSet<>();
|
||||
private static final Int2IntMap connectedBlockStates = new Int2IntOpenHashMap(1296);
|
||||
private static final Int2IntMap powerMappings = new Int2IntOpenHashMap(1296);
|
||||
private static final IntSet REDSTONE = new IntOpenHashSet();
|
||||
private static final Int2IntMap CONNECTED_BLOCK_STATES = new Int2IntOpenHashMap(1296);
|
||||
private static final Int2IntMap POWER_MAPPINGS = new Int2IntOpenHashMap(1296);
|
||||
private static final int BLOCK_CONNECTION_TYPE_ID = BlockData.connectionTypeId("redstone");
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final RedstoneConnectionHandler connectionHandler = new RedstoneConnectionHandler();
|
||||
final String redstoneKey = "minecraft:redstone_wire";
|
||||
return blockData -> {
|
||||
if (!redstoneKey.equals(blockData.getMinecraftKey())) return;
|
||||
redstone.add(blockData.getSavedBlockStateId());
|
||||
if (!redstoneKey.equals(blockData.getMinecraftKey())) {
|
||||
return;
|
||||
}
|
||||
|
||||
REDSTONE.add(blockData.getSavedBlockStateId());
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), connectionHandler);
|
||||
connectedBlockStates.put(getStates(blockData), blockData.getSavedBlockStateId());
|
||||
powerMappings.put(blockData.getSavedBlockStateId(), Integer.parseInt(blockData.getValue("power")));
|
||||
CONNECTED_BLOCK_STATES.put(getStates(blockData), blockData.getSavedBlockStateId());
|
||||
POWER_MAPPINGS.put(blockData.getSavedBlockStateId(), Integer.parseInt(blockData.getValue("power")));
|
||||
};
|
||||
}
|
||||
|
||||
@ -72,8 +76,8 @@ public class RedstoneConnectionHandler extends ConnectionHandler {
|
||||
b |= connects(user, position, BlockFace.NORTH) << 2;
|
||||
b |= connects(user, position, BlockFace.SOUTH) << 4;
|
||||
b |= connects(user, position, BlockFace.WEST) << 6;
|
||||
b |= powerMappings.get(blockState) << 8;
|
||||
return connectedBlockStates.getOrDefault(b, blockState);
|
||||
b |= POWER_MAPPINGS.get(blockState) << 8;
|
||||
return CONNECTED_BLOCK_STATES.getOrDefault(b, blockState);
|
||||
}
|
||||
|
||||
private int connects(UserConnection user, Position position, BlockFace side) {
|
||||
@ -83,11 +87,11 @@ public class RedstoneConnectionHandler extends ConnectionHandler {
|
||||
return 1; //side
|
||||
}
|
||||
int up = getBlockData(user, relative.getRelative(BlockFace.TOP));
|
||||
if (redstone.contains(up) && !ConnectionData.occludingStates.contains(getBlockData(user, position.getRelative(BlockFace.TOP)))) {
|
||||
if (REDSTONE.contains(up) && !ConnectionData.OCCLUDING_STATES.contains(getBlockData(user, position.getRelative(BlockFace.TOP)))) {
|
||||
return 2; //"up"
|
||||
}
|
||||
int down = getBlockData(user, relative.getRelative(BlockFace.BOTTOM));
|
||||
if (redstone.contains(down) && !ConnectionData.occludingStates.contains(getBlockData(user, relative))) {
|
||||
if (REDSTONE.contains(down) && !ConnectionData.OCCLUDING_STATES.contains(getBlockData(user, relative))) {
|
||||
return 1; //side
|
||||
}
|
||||
return 0; //none
|
||||
@ -95,6 +99,6 @@ public class RedstoneConnectionHandler extends ConnectionHandler {
|
||||
|
||||
private boolean connects(BlockFace side, int blockState) {
|
||||
final BlockData blockData = ConnectionData.blockConnectionData.get(blockState);
|
||||
return blockData != null && blockData.connectsTo("redstoneConnections", side.opposite(), false);
|
||||
return blockData != null && blockData.connectsTo(BLOCK_CONNECTION_TYPE_ID, side.opposite(), false);
|
||||
}
|
||||
}
|
||||
|
@ -20,15 +20,16 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import java.util.HashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SnowyGrassConnectionHandler extends ConnectionHandler {
|
||||
private static final Map<Pair<Integer, Boolean>, Integer> grassBlocks = new HashMap<>();
|
||||
private static final Set<Integer> snows = new HashSet<>();
|
||||
private static final Object2IntMap<GrassBlock> GRASS_BLOCKS = new Object2IntOpenHashMap<>();
|
||||
private static final IntSet SNOWY_GRASS_BLOCKS = new IntOpenHashSet();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final Set<String> snowyGrassBlocks = new HashSet<>();
|
||||
@ -36,18 +37,19 @@ public class SnowyGrassConnectionHandler extends ConnectionHandler {
|
||||
snowyGrassBlocks.add("minecraft:podzol");
|
||||
snowyGrassBlocks.add("minecraft:mycelium");
|
||||
|
||||
GRASS_BLOCKS.defaultReturnValue(-1);
|
||||
final SnowyGrassConnectionHandler handler = new SnowyGrassConnectionHandler();
|
||||
return blockData -> {
|
||||
if (snowyGrassBlocks.contains(blockData.getMinecraftKey())) {
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler);
|
||||
blockData.set("snowy", "true");
|
||||
grassBlocks.put(new Pair<>(blockData.getSavedBlockStateId(), true), blockData.getBlockStateId());
|
||||
GRASS_BLOCKS.put(new GrassBlock(blockData.getSavedBlockStateId(), true), blockData.getBlockStateId());
|
||||
blockData.set("snowy", "false");
|
||||
grassBlocks.put(new Pair<>(blockData.getSavedBlockStateId(), false), blockData.getBlockStateId());
|
||||
GRASS_BLOCKS.put(new GrassBlock(blockData.getSavedBlockStateId(), false), blockData.getBlockStateId());
|
||||
}
|
||||
if (blockData.getMinecraftKey().equals("minecraft:snow") || blockData.getMinecraftKey().equals("minecraft:snow_block")) {
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler);
|
||||
snows.add(blockData.getSavedBlockStateId());
|
||||
SnowyGrassConnectionHandler.SNOWY_GRASS_BLOCKS.add(blockData.getSavedBlockStateId());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -55,10 +57,33 @@ public class SnowyGrassConnectionHandler extends ConnectionHandler {
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
int blockUpId = getBlockData(user, position.getRelative(BlockFace.TOP));
|
||||
Integer newId = grassBlocks.get(new Pair<>(blockState, snows.contains(blockUpId)));
|
||||
if (newId != null) {
|
||||
return newId;
|
||||
int newId = GRASS_BLOCKS.getInt(new GrassBlock(blockState, SNOWY_GRASS_BLOCKS.contains(blockUpId)));
|
||||
return newId != -1 ? newId : blockState;
|
||||
}
|
||||
|
||||
private static final class GrassBlock {
|
||||
private final int blockStateId;
|
||||
private final boolean snowy;
|
||||
|
||||
private GrassBlock(final int blockStateId, final boolean snowy) {
|
||||
this.blockStateId = blockStateId;
|
||||
this.snowy = snowy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final GrassBlock that = (GrassBlock) o;
|
||||
if (blockStateId != that.blockStateId) return false;
|
||||
return snowy == that.snowy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = blockStateId;
|
||||
result = 31 * result + (snowy ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -27,8 +29,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class StairConnectionHandler extends ConnectionHandler {
|
||||
private static final Map<Integer, StairData> stairDataMap = new HashMap<>();
|
||||
private static final Map<Short, Integer> connectedBlocks = new HashMap<>();
|
||||
private static final Int2ObjectMap<StairData> STAIR_DATA_MAP = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<Short, Integer> CONNECTED_BLOCKS = new HashMap<>();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final List<String> baseStairs = new LinkedList<>();
|
||||
@ -84,8 +86,8 @@ public class StairConnectionHandler extends ConnectionHandler {
|
||||
BlockFace.valueOf(blockData.getValue("facing").toUpperCase(Locale.ROOT))
|
||||
);
|
||||
|
||||
stairDataMap.put(blockData.getSavedBlockStateId(), stairData);
|
||||
connectedBlocks.put(getStates(stairData), blockData.getSavedBlockStateId());
|
||||
STAIR_DATA_MAP.put(blockData.getSavedBlockStateId(), stairData);
|
||||
CONNECTED_BLOCKS.put(getStates(stairData), blockData.getSavedBlockStateId());
|
||||
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), connectionHandler);
|
||||
};
|
||||
@ -102,7 +104,7 @@ public class StairConnectionHandler extends ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
StairData stairData = stairDataMap.get(blockState);
|
||||
StairData stairData = STAIR_DATA_MAP.get(blockState);
|
||||
if (stairData == null) return blockState;
|
||||
|
||||
short s = 0;
|
||||
@ -111,14 +113,14 @@ public class StairConnectionHandler extends ConnectionHandler {
|
||||
s |= stairData.getType() << 4;
|
||||
s |= stairData.getFacing().ordinal() << 9;
|
||||
|
||||
Integer newBlockState = connectedBlocks.get(s);
|
||||
Integer newBlockState = CONNECTED_BLOCKS.get(s);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
private int getShape(UserConnection user, Position position, StairData stair) {
|
||||
BlockFace facing = stair.getFacing();
|
||||
|
||||
StairData relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(facing)));
|
||||
StairData relativeStair = STAIR_DATA_MAP.get(getBlockData(user, position.getRelative(facing)));
|
||||
if (relativeStair != null && relativeStair.isBottom() == stair.isBottom()) {
|
||||
BlockFace facing2 = relativeStair.getFacing();
|
||||
if (facing.axis() != facing2.axis() && checkOpposite(user, stair, position, facing2.opposite())) {
|
||||
@ -126,7 +128,7 @@ public class StairConnectionHandler extends ConnectionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(facing.opposite())));
|
||||
relativeStair = STAIR_DATA_MAP.get(getBlockData(user, position.getRelative(facing.opposite())));
|
||||
if (relativeStair != null && relativeStair.isBottom() == stair.isBottom()) {
|
||||
BlockFace facing2 = relativeStair.getFacing();
|
||||
if (facing.axis() != facing2.axis() && checkOpposite(user, stair, position, facing2)) {
|
||||
@ -138,7 +140,7 @@ public class StairConnectionHandler extends ConnectionHandler {
|
||||
}
|
||||
|
||||
private boolean checkOpposite(UserConnection user, StairData stair, Position position, BlockFace face) {
|
||||
StairData relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(face)));
|
||||
StairData relativeStair = STAIR_DATA_MAP.get(getBlockData(user, position.getRelative(face)));
|
||||
return relativeStair == null || relativeStair.getFacing() != stair.getFacing() || relativeStair.isBottom() != stair.isBottom();
|
||||
}
|
||||
|
||||
|
@ -20,20 +20,23 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import java.util.HashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class TripwireConnectionHandler extends ConnectionHandler {
|
||||
private static final Map<Integer, TripwireData> tripwireDataMap = new HashMap<>();
|
||||
private static final Map<Byte, Integer> connectedBlocks = new HashMap<>();
|
||||
private static final Map<Integer, BlockFace> tripwireHooks = new HashMap<>();
|
||||
private static final Int2ObjectMap<TripwireData> TRIPWIRE_DATA_MAP = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<BlockFace> TRIPWIRE_HOOKS = new Int2ObjectArrayMap<>();
|
||||
private static final int[] CONNECTED_BLOCKS = new int[128];
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
Arrays.fill(CONNECTED_BLOCKS, -1);
|
||||
final TripwireConnectionHandler connectionHandler = new TripwireConnectionHandler();
|
||||
return blockData -> {
|
||||
if (blockData.getMinecraftKey().equals("minecraft:tripwire_hook")) {
|
||||
tripwireHooks.put(blockData.getSavedBlockStateId(), BlockFace.valueOf(blockData.getValue("facing").toUpperCase(Locale.ROOT)));
|
||||
TRIPWIRE_HOOKS.put(blockData.getSavedBlockStateId(), BlockFace.valueOf(blockData.getValue("facing").toUpperCase(Locale.ROOT)));
|
||||
} else if (blockData.getMinecraftKey().equals("minecraft:tripwire")) {
|
||||
TripwireData tripwireData = new TripwireData(
|
||||
blockData.getValue("attached").equals("true"),
|
||||
@ -41,8 +44,8 @@ public class TripwireConnectionHandler extends ConnectionHandler {
|
||||
blockData.getValue("powered").equals("true")
|
||||
);
|
||||
|
||||
tripwireDataMap.put(blockData.getSavedBlockStateId(), tripwireData);
|
||||
connectedBlocks.put(getStates(blockData), blockData.getSavedBlockStateId());
|
||||
TRIPWIRE_DATA_MAP.put(blockData.getSavedBlockStateId(), tripwireData);
|
||||
CONNECTED_BLOCKS[getStates(blockData)] = blockData.getSavedBlockStateId();
|
||||
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), connectionHandler);
|
||||
}
|
||||
@ -63,7 +66,7 @@ public class TripwireConnectionHandler extends ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
TripwireData tripwireData = tripwireDataMap.get(blockState);
|
||||
TripwireData tripwireData = TRIPWIRE_DATA_MAP.get(blockState);
|
||||
if (tripwireData == null) return blockState;
|
||||
byte b = 0;
|
||||
if (tripwireData.isAttached()) b |= 1;
|
||||
@ -75,21 +78,21 @@ public class TripwireConnectionHandler extends ConnectionHandler {
|
||||
int south = getBlockData(user, position.getRelative(BlockFace.SOUTH));
|
||||
int west = getBlockData(user, position.getRelative(BlockFace.WEST));
|
||||
|
||||
if (tripwireDataMap.containsKey(east) || tripwireHooks.get(east) == BlockFace.WEST) {
|
||||
if (TRIPWIRE_DATA_MAP.containsKey(east) || TRIPWIRE_HOOKS.get(east) == BlockFace.WEST) {
|
||||
b |= 8;
|
||||
}
|
||||
if (tripwireDataMap.containsKey(north) || tripwireHooks.get(north) == BlockFace.SOUTH) {
|
||||
if (TRIPWIRE_DATA_MAP.containsKey(north) || TRIPWIRE_HOOKS.get(north) == BlockFace.SOUTH) {
|
||||
b |= 16;
|
||||
}
|
||||
if (tripwireDataMap.containsKey(south) || tripwireHooks.get(south) == BlockFace.NORTH) {
|
||||
if (TRIPWIRE_DATA_MAP.containsKey(south) || TRIPWIRE_HOOKS.get(south) == BlockFace.NORTH) {
|
||||
b |= 32;
|
||||
}
|
||||
if (tripwireDataMap.containsKey(west) || tripwireHooks.get(west) == BlockFace.EAST) {
|
||||
if (TRIPWIRE_DATA_MAP.containsKey(west) || TRIPWIRE_HOOKS.get(west) == BlockFace.EAST) {
|
||||
b |= 64;
|
||||
}
|
||||
|
||||
Integer newBlockState = connectedBlocks.get(b);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
int newBlockState = CONNECTED_BLOCKS[b];
|
||||
return newBlockState == -1 ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
private static final class TripwireData {
|
||||
|
@ -20,18 +20,18 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnection
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
class VineConnectionHandler extends ConnectionHandler {
|
||||
private static final Set<Integer> vines = new HashSet<>();
|
||||
private static final IntSet VINES = new IntOpenHashSet();
|
||||
|
||||
static ConnectionData.ConnectorInitAction init() {
|
||||
final VineConnectionHandler connectionHandler = new VineConnectionHandler();
|
||||
return blockData -> {
|
||||
if (!blockData.getMinecraftKey().equals("minecraft:vine")) return;
|
||||
|
||||
vines.add(blockData.getSavedBlockStateId());
|
||||
VINES.add(blockData.getSavedBlockStateId());
|
||||
ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), connectionHandler);
|
||||
};
|
||||
}
|
||||
@ -42,7 +42,7 @@ class VineConnectionHandler extends ConnectionHandler {
|
||||
|
||||
Position upperPos = position.getRelative(BlockFace.TOP);
|
||||
int upperBlock = getBlockData(user, upperPos);
|
||||
if (vines.contains(upperBlock) && isAttachedToBlock(user, upperPos)) return blockState;
|
||||
if (VINES.contains(upperBlock) && isAttachedToBlock(user, upperPos)) return blockState;
|
||||
|
||||
// Map to air if not attached to block, and upper block is also not a vine attached to a block
|
||||
return 0;
|
||||
@ -56,6 +56,6 @@ class VineConnectionHandler extends ConnectionHandler {
|
||||
}
|
||||
|
||||
private boolean isAttachedToBlock(UserConnection user, Position position, BlockFace blockFace) {
|
||||
return ConnectionData.occludingStates.contains(getBlockData(user, position.getRelative(blockFace)));
|
||||
return ConnectionData.OCCLUDING_STATES.contains(getBlockData(user, position.getRelative(blockFace)));
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static List<ConnectionData.ConnectorInitAction> init() {
|
||||
List<ConnectionData.ConnectorInitAction> actions = new ArrayList<>(2);
|
||||
actions.add(new WallConnectionHandler("cobbleWallConnections").getInitAction("minecraft:cobblestone_wall"));
|
||||
actions.add(new WallConnectionHandler("cobbleWallConnections").getInitAction("minecraft:mossy_cobblestone_wall"));
|
||||
actions.add(new WallConnectionHandler("cobbleWall").getInitAction("minecraft:cobblestone_wall"));
|
||||
actions.add(new WallConnectionHandler("cobbleWall").getInitAction("minecraft:mossy_cobblestone_wall"));
|
||||
return actions;
|
||||
}
|
||||
|
||||
@ -46,12 +46,18 @@ public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = super.getStates(user, position, blockState);
|
||||
if (up(user, position)) states |= 16;
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte statesSize() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
public boolean up(UserConnection user, Position position) {
|
||||
if (isWall(getBlockData(user, position.getRelative(BlockFace.BOTTOM))) || isWall(getBlockData(user, position.getRelative(BlockFace.TOP))))
|
||||
return true;
|
||||
|
@ -17,15 +17,14 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class WrappedBlockData {
|
||||
public final class WrappedBlockData {
|
||||
private final LinkedHashMap<String, String> blockData = new LinkedHashMap<>();
|
||||
private final String minecraftKey;
|
||||
private final int savedBlockStateId;
|
||||
private final LinkedHashMap<String, String> blockData = new LinkedHashMap<>();
|
||||
|
||||
public static WrappedBlockData fromString(String s) {
|
||||
String[] array = s.split("\\[");
|
||||
@ -43,15 +42,6 @@ public class WrappedBlockData {
|
||||
return wrappedBlockdata;
|
||||
}
|
||||
|
||||
public static WrappedBlockData fromStateId(int id) {
|
||||
String blockData = ConnectionData.getKey(id);
|
||||
if (blockData != null) {
|
||||
return fromString(blockData);
|
||||
}
|
||||
Via.getPlatform().getLogger().info("Unable to get blockdata from " + id);
|
||||
return fromString("minecraft:air");
|
||||
}
|
||||
|
||||
private WrappedBlockData(String minecraftKey, int savedBlockStateId) {
|
||||
this.minecraftKey = Key.namespaced(minecraftKey);
|
||||
this.savedBlockStateId = savedBlockStateId;
|
||||
|
@ -59,6 +59,7 @@ public class PacketBlockConnectionProvider extends BlockConnectionProvider {
|
||||
|
||||
@Override
|
||||
public UserBlockData forUser(UserConnection connection) {
|
||||
return connection.get(BlockConnectionStorage.class)::get;
|
||||
final BlockConnectionStorage storage = connection.get(BlockConnectionStorage.class);
|
||||
return (x, y, z) -> storage.get(x, y, z);
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface UserBlockData {
|
||||
|
||||
int getBlockData(int x, int y, int z);
|
||||
|
||||
}
|
||||
|
@ -183,18 +183,18 @@ public class WorldPackets {
|
||||
|
||||
UserConnection userConnection = wrapper.user();
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newId);
|
||||
newId = ConnectionData.connect(userConnection, position, newId);
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newId);
|
||||
}
|
||||
|
||||
wrapper.set(Type.VAR_INT, 0, checkStorage(wrapper.user(), position, newId));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -214,14 +214,14 @@ public class WorldPackets {
|
||||
for (BlockChangeRecord record : records) {
|
||||
int newBlock = toNewId(record.getBlockId());
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getSectionX() + (chunkX << 4),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
record.getSectionZ() + (chunkZ << 4));
|
||||
|
||||
record.setBlockId(checkStorage(wrapper.user(), position, newBlock));
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newBlock);
|
||||
}
|
||||
record.setBlockId(checkStorage(wrapper.user(), position, newBlock));
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
@ -237,8 +237,10 @@ public class WorldPackets {
|
||||
if (handler != null) {
|
||||
blockState = handler.connect(userConnection, position, blockState);
|
||||
record.setBlockId(blockState);
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), blockState);
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
@ -251,7 +253,6 @@ public class WorldPackets {
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -358,22 +359,25 @@ public class WorldPackets {
|
||||
}
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
Position position = new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4));
|
||||
if (storage.isWelcome(id)) {
|
||||
storage.store(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)), id);
|
||||
storage.store(position, id);
|
||||
} else if (!chunk.isFullChunk()) { // Update
|
||||
storage.remove(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)));
|
||||
storage.remove(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save_connections:
|
||||
{
|
||||
if (!Via.getConfig().isServersideBlockConnections() || !ConnectionData.needStoreBlocks())
|
||||
if (!Via.getConfig().isServersideBlockConnections() || !ConnectionData.needStoreBlocks()) {
|
||||
break save_connections;
|
||||
}
|
||||
|
||||
if (!chunk.isFullChunk()) { // Update
|
||||
ConnectionData.blockConnectionProvider.unloadChunkSection(wrapper.user(), chunk.getX(), s, chunk.getZ());
|
||||
}
|
||||
|
||||
boolean willSave = false;
|
||||
for (int p = 0; p < blocks.size(); p++) {
|
||||
if (ConnectionData.isWelcome(blocks.idByIndex(p))) {
|
||||
@ -381,7 +385,9 @@ public class WorldPackets {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willSave) break save_connections;
|
||||
if (!willSave) {
|
||||
break save_connections;
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
|
@ -19,18 +19,13 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.StorableObject;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets.WorldPackets;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BlockConnectionStorage implements StorableObject {
|
||||
private static final short[] REVERSE_BLOCK_MAPPINGS = new short[8582];
|
||||
private static Constructor<?> fastUtilLongObjectHashMap;
|
||||
|
||||
private final Map<Long, SectionData> blockStorage = createLongObjectMap();
|
||||
@ -47,68 +42,50 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
Via.getPlatform().getLogger().info("Using FastUtil Long2ObjectOpenHashMap for block connections");
|
||||
} catch (ClassNotFoundException | NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
Arrays.fill(REVERSE_BLOCK_MAPPINGS, (short) -1);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
int newBlock = Protocol1_13To1_12_2.MAPPINGS.getBlockMappings().getNewId(i);
|
||||
if (newBlock != -1) {
|
||||
REVERSE_BLOCK_MAPPINGS[newBlock] = (short) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
public void store(int x, int y, int z, int blockState) {
|
||||
short mapping = REVERSE_BLOCK_MAPPINGS[blockState];
|
||||
if (mapping == -1) return;
|
||||
long index = getChunkSectionIndex(x, y, z);
|
||||
SectionData section = getSection(index);
|
||||
if (section == null) {
|
||||
if (blockState == 0) {
|
||||
// No need to store empty sections
|
||||
return;
|
||||
}
|
||||
|
||||
blockState = mapping;
|
||||
long pair = getChunkSectionIndex(x, y, z);
|
||||
SectionData map = getChunkSection(pair, (blockState & 0xF) != 0);
|
||||
int blockIndex = encodeBlockPos(x, y, z);
|
||||
map.blockIds()[blockIndex] = (byte) (blockState >> 4);
|
||||
NibbleArray nibbleArray = map.nibbleArray();
|
||||
if (nibbleArray != null) {
|
||||
nibbleArray.set(blockIndex, blockState);
|
||||
blockStorage.put(index, section = new SectionData());
|
||||
lastSection = section;
|
||||
lastIndex = index;
|
||||
}
|
||||
|
||||
section.setBlockAt(x, y, z, blockState);
|
||||
}
|
||||
|
||||
public int get(int x, int y, int z) {
|
||||
long pair = getChunkSectionIndex(x, y, z);
|
||||
SectionData map = getSection(pair);
|
||||
if (map == null) return 0;
|
||||
short blockPosition = encodeBlockPos(x, y, z);
|
||||
NibbleArray nibbleArray = map.nibbleArray();
|
||||
return WorldPackets.toNewId(
|
||||
((map.blockIds()[blockPosition] & 0xFF) << 4)
|
||||
| (nibbleArray == null ? 0 : nibbleArray.get(blockPosition))
|
||||
);
|
||||
SectionData section = getSection(pair);
|
||||
if (section == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return section.blockAt(x, y, z);
|
||||
}
|
||||
|
||||
public void remove(int x, int y, int z) {
|
||||
long pair = getChunkSectionIndex(x, y, z);
|
||||
SectionData map = getSection(pair);
|
||||
if (map == null) return;
|
||||
int blockIndex = encodeBlockPos(x, y, z);
|
||||
NibbleArray nibbleArray = map.nibbleArray();
|
||||
if (nibbleArray != null) {
|
||||
nibbleArray.set(blockIndex, 0);
|
||||
boolean allZero = true;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (nibbleArray.get(i) != 0) {
|
||||
allZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allZero) map.setNibbleArray(null);
|
||||
long index = getChunkSectionIndex(x, y, z);
|
||||
SectionData section = getSection(index);
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
map.blockIds()[blockIndex] = 0;
|
||||
for (short entry : map.blockIds()) {
|
||||
if (entry != 0) return;
|
||||
|
||||
section.setBlockAt(x, y, z, 0);
|
||||
|
||||
if (section.nonEmptyBlocks() == 0) {
|
||||
removeSection(index);
|
||||
}
|
||||
removeSection(pair);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -127,21 +104,7 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
removeSection(getChunkSectionIndex(x << 4, y << 4, z << 4));
|
||||
}
|
||||
|
||||
private SectionData getChunkSection(long index, boolean requireNibbleArray) {
|
||||
SectionData map = getSection(index);
|
||||
if (map == null) {
|
||||
map = new SectionData(new byte[4096]);
|
||||
blockStorage.put(index, map);
|
||||
lastSection = map;
|
||||
lastIndex = index;
|
||||
}
|
||||
if (map.nibbleArray() == null && requireNibbleArray) {
|
||||
map.setNibbleArray(new NibbleArray(4096));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private SectionData getSection(long index) {
|
||||
private @Nullable SectionData getSection(long index) {
|
||||
if (lastIndex != null && lastIndex == index) {
|
||||
return lastSection;
|
||||
}
|
||||
@ -157,17 +120,14 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private long getChunkSectionIndex(int x, int y, int z) {
|
||||
private static long getChunkSectionIndex(int x, int y, int z) {
|
||||
return (((x >> 4) & 0x3FFFFFFL) << 38) | (((y >> 4) & 0xFFFL) << 26) | ((z >> 4) & 0x3FFFFFFL);
|
||||
}
|
||||
|
||||
private short encodeBlockPos(int x, int y, int z) {
|
||||
return (short) (((y & 0xF) << 8) | ((x & 0xF) << 4) | (z & 0xF));
|
||||
}
|
||||
|
||||
private <T> Map<Long, T> createLongObjectMap() {
|
||||
if (fastUtilLongObjectHashMap != null) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (Map<Long, T>) fastUtilLongObjectHashMap.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
@ -177,23 +137,33 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
}
|
||||
|
||||
private static final class SectionData {
|
||||
private final byte[] blockIds;
|
||||
private NibbleArray nibbleArray;
|
||||
private final short[] blockStates = new short[4096];
|
||||
private short nonEmptyBlocks;
|
||||
|
||||
private SectionData(byte[] blockIds) {
|
||||
this.blockIds = blockIds;
|
||||
public int blockAt(int x, int y, int z) {
|
||||
return blockStates[encodeBlockPos(x, y, z)];
|
||||
}
|
||||
|
||||
public byte[] blockIds() {
|
||||
return blockIds;
|
||||
public void setBlockAt(int x, int y, int z, int blockState) {
|
||||
int index = encodeBlockPos(x, y, z);
|
||||
if (blockState == blockStates[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockStates[index] = (short) blockState;
|
||||
if (blockState == 0) {
|
||||
nonEmptyBlocks--;
|
||||
} else {
|
||||
nonEmptyBlocks++;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable NibbleArray nibbleArray() {
|
||||
return nibbleArray;
|
||||
public short nonEmptyBlocks() {
|
||||
return nonEmptyBlocks;
|
||||
}
|
||||
|
||||
public void setNibbleArray(@Nullable NibbleArray nibbleArray) {
|
||||
this.nibbleArray = nibbleArray;
|
||||
private static int encodeBlockPos(int x, int y, int z) {
|
||||
return ((y & 0xF) << 8) | ((x & 0xF) << 4) | (z & 0xF);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in New Issue
Block a user