mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-26 03:55:28 +01:00
Optimize block connections on neighbour chunk calculation (#3228)
This commit is contained in:
parent
3ced95903a
commit
68d1843496
@ -18,7 +18,6 @@
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
@ -37,6 +36,7 @@ import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPacke
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.PacketBlockConnectionProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.UserBlockData;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
@ -77,80 +77,6 @@ public final class ConnectionData {
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateChunkSectionNeighbours(UserConnection user, int chunkX, int chunkZ, int chunkSectionY) {
|
||||
int chunkMinY = chunkSectionY << 4;
|
||||
List<BlockChangeRecord1_8> updates = new ArrayList<>();
|
||||
for (int chunkDeltaX = -1; chunkDeltaX <= 1; chunkDeltaX++) {
|
||||
for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) {
|
||||
int distance = Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ);
|
||||
if (distance == 0) continue;
|
||||
|
||||
int chunkMinX = (chunkX + chunkDeltaX) << 4;
|
||||
int chunkMinZ = (chunkZ + chunkDeltaZ) << 4;
|
||||
if (distance == 2) { // Corner
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int blockPosX = chunkDeltaX == 1 ? 0 : 15;
|
||||
int blockPosZ = chunkDeltaZ == 1 ? 0 : 15;
|
||||
updateBlock(user, new Position(chunkMinX + blockPosX, blockY, chunkMinZ + blockPosZ), updates);
|
||||
}
|
||||
} else {
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int xStart, xEnd;
|
||||
int zStart, zEnd;
|
||||
if (chunkDeltaX == 1) {
|
||||
xStart = 0;
|
||||
xEnd = 2;
|
||||
zStart = 0;
|
||||
zEnd = 16;
|
||||
} else if (chunkDeltaX == -1) {
|
||||
xStart = 14;
|
||||
xEnd = 16;
|
||||
zStart = 0;
|
||||
zEnd = 16;
|
||||
} else if (chunkDeltaZ == 1) {
|
||||
xStart = 0;
|
||||
xEnd = 16;
|
||||
zStart = 0;
|
||||
zEnd = 2;
|
||||
} else {
|
||||
xStart = 0;
|
||||
xEnd = 16;
|
||||
zStart = 14;
|
||||
zEnd = 16;
|
||||
}
|
||||
for (int blockX = xStart; blockX < xEnd; blockX++) {
|
||||
for (int blockZ = zStart; blockZ < zEnd; blockZ++) {
|
||||
updateBlock(user, new Position(chunkMinX + blockX, blockY, chunkMinZ + blockZ), updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_13.MULTI_BLOCK_CHANGE, null, user);
|
||||
wrapper.write(Type.INT, chunkX + chunkDeltaX);
|
||||
wrapper.write(Type.INT, chunkZ + chunkDeltaZ);
|
||||
wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, updates.toArray(EMPTY_RECORDS));
|
||||
try {
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
updates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateBlock(UserConnection user, Position pos, List<BlockChangeRecord1_8> records) {
|
||||
int blockState = blockConnectionProvider.getBlockData(user, pos.x(), pos.y(), pos.z());
|
||||
ConnectionHandler handler = getConnectionHandler(blockState);
|
||||
if (handler == null) return;
|
||||
|
||||
int newBlockState = handler.connect(user, pos, blockState);
|
||||
records.add(new BlockChangeRecord1_8(pos.x() & 0xF, pos.y(), pos.z() & 0xF, newBlockState));
|
||||
}
|
||||
|
||||
public static void updateBlockStorage(UserConnection userConnection, int x, int y, int z, int blockState) {
|
||||
if (!needStoreBlocks()) return;
|
||||
if (ConnectionData.isWelcome(blockState)) {
|
||||
@ -693,4 +619,85 @@ public final class ConnectionData {
|
||||
public static Object2IntMap<String> getKeyToId() {
|
||||
return keyToId;
|
||||
}
|
||||
|
||||
public static class NeighbourUpdater {
|
||||
private final UserConnection user;
|
||||
private final UserBlockData userBlockData;
|
||||
|
||||
public NeighbourUpdater(UserConnection user) {
|
||||
this.user = user;
|
||||
this.userBlockData = blockConnectionProvider.forUser(user);
|
||||
}
|
||||
|
||||
public void updateChunkSectionNeighbours(int chunkX, int chunkZ, int chunkSectionY) throws Exception {
|
||||
int chunkMinY = chunkSectionY << 4;
|
||||
List<BlockChangeRecord1_8> updates = new ArrayList<>();
|
||||
for (int chunkDeltaX = -1; chunkDeltaX <= 1; chunkDeltaX++) {
|
||||
for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) {
|
||||
int distance = Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ);
|
||||
if (distance == 0) continue;
|
||||
|
||||
int chunkMinX = (chunkX + chunkDeltaX) << 4;
|
||||
int chunkMinZ = (chunkZ + chunkDeltaZ) << 4;
|
||||
if (distance == 2) { // Corner
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int blockPosX = chunkDeltaX == 1 ? 0 : 15;
|
||||
int blockPosZ = chunkDeltaZ == 1 ? 0 : 15;
|
||||
updateBlock(chunkMinX + blockPosX, blockY, chunkMinZ + blockPosZ, updates);
|
||||
}
|
||||
} else {
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int xStart, xEnd;
|
||||
int zStart, zEnd;
|
||||
if (chunkDeltaX == 1) {
|
||||
xStart = 0;
|
||||
xEnd = 2;
|
||||
zStart = 0;
|
||||
zEnd = 16;
|
||||
} else if (chunkDeltaX == -1) {
|
||||
xStart = 14;
|
||||
xEnd = 16;
|
||||
zStart = 0;
|
||||
zEnd = 16;
|
||||
} else if (chunkDeltaZ == 1) {
|
||||
xStart = 0;
|
||||
xEnd = 16;
|
||||
zStart = 0;
|
||||
zEnd = 2;
|
||||
} else {
|
||||
xStart = 0;
|
||||
xEnd = 16;
|
||||
zStart = 14;
|
||||
zEnd = 16;
|
||||
}
|
||||
for (int blockX = xStart; blockX < xEnd; blockX++) {
|
||||
for (int blockZ = zStart; blockZ < zEnd; blockZ++) {
|
||||
updateBlock(chunkMinX + blockX, blockY, chunkMinZ + blockZ, updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_13.MULTI_BLOCK_CHANGE, null, user);
|
||||
wrapper.write(Type.INT, chunkX + chunkDeltaX);
|
||||
wrapper.write(Type.INT, chunkZ + chunkDeltaZ);
|
||||
wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, updates.toArray(EMPTY_RECORDS));
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
updates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBlock(int x, int y, int z, List<BlockChangeRecord1_8> records) {
|
||||
int blockState = userBlockData.getBlockData(x, y, z);
|
||||
ConnectionHandler handler = getConnectionHandler(blockState);
|
||||
if (handler == null) return;
|
||||
|
||||
Position pos = new Position(x, y, z);
|
||||
int newBlockState = handler.connect(user, pos, blockState);
|
||||
records.add(new BlockChangeRecord1_8(pos.x() & 0xF, pos.y(), pos.z() & 0xF, newBlockState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,4 +55,9 @@ public class BlockConnectionProvider implements Provider {
|
||||
public boolean storesBlocks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public UserBlockData forUser(UserConnection connection) {
|
||||
return (x, y, z) -> getBlockData(connection, x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,4 +56,9 @@ public class PacketBlockConnectionProvider extends BlockConnectionProvider {
|
||||
public boolean storesBlocks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserBlockData forUser(UserConnection connection) {
|
||||
return connection.get(BlockConnectionStorage.class)::get;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2023 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers;
|
||||
|
||||
public interface UserBlockData {
|
||||
|
||||
int getBlockData(int x, int y, int z);
|
||||
|
||||
}
|
@ -448,10 +448,11 @@ public class WorldPackets {
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
ConnectionData.NeighbourUpdater updater = new ConnectionData.NeighbourUpdater(wrapper.user());
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null) continue;
|
||||
ConnectionData.updateChunkSectionNeighbours(wrapper.user(), chunk.getX(), chunk.getZ(), i);
|
||||
updater.updateChunkSectionNeighbours(chunk.getX(), chunk.getZ(), i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -35,6 +35,10 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
|
||||
private final Map<Long, SectionData> blockStorage = createLongObjectMap();
|
||||
|
||||
// Cache to retrieve section quicker
|
||||
private Long lastIndex;
|
||||
private SectionData lastSection;
|
||||
|
||||
static {
|
||||
try {
|
||||
//noinspection StringBufferReplaceableByString - prevent relocation
|
||||
@ -73,7 +77,7 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
|
||||
public int get(int x, int y, int z) {
|
||||
long pair = getChunkSectionIndex(x, y, z);
|
||||
SectionData map = blockStorage.get(pair);
|
||||
SectionData map = getSection(pair);
|
||||
if (map == null) return 0;
|
||||
short blockPosition = encodeBlockPos(x, y, z);
|
||||
NibbleArray nibbleArray = map.nibbleArray();
|
||||
@ -85,7 +89,7 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
|
||||
public void remove(int x, int y, int z) {
|
||||
long pair = getChunkSectionIndex(x, y, z);
|
||||
SectionData map = blockStorage.get(pair);
|
||||
SectionData map = getSection(pair);
|
||||
if (map == null) return;
|
||||
int blockIndex = encodeBlockPos(x, y, z);
|
||||
NibbleArray nibbleArray = map.nibbleArray();
|
||||
@ -104,11 +108,13 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
for (short entry : map.blockIds()) {
|
||||
if (entry != 0) return;
|
||||
}
|
||||
blockStorage.remove(pair);
|
||||
removeSection(pair);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
blockStorage.clear();
|
||||
lastSection = null;
|
||||
lastIndex = null;
|
||||
}
|
||||
|
||||
public void unloadChunk(int x, int z) {
|
||||
@ -118,14 +124,16 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
}
|
||||
|
||||
public void unloadSection(int x, int y, int z) {
|
||||
blockStorage.remove(getChunkSectionIndex(x << 4, y << 4, z << 4));
|
||||
removeSection(getChunkSectionIndex(x << 4, y << 4, z << 4));
|
||||
}
|
||||
|
||||
private SectionData getChunkSection(long index, boolean requireNibbleArray) {
|
||||
SectionData map = blockStorage.get(index);
|
||||
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));
|
||||
@ -133,6 +141,22 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
return map;
|
||||
}
|
||||
|
||||
private SectionData getSection(long index) {
|
||||
if (lastIndex != null && lastIndex == index) {
|
||||
return lastSection;
|
||||
}
|
||||
lastIndex = index;
|
||||
return lastSection = blockStorage.get(index);
|
||||
}
|
||||
|
||||
private void removeSection(long index) {
|
||||
blockStorage.remove(index);
|
||||
if (lastIndex != null && lastIndex == index) {
|
||||
lastIndex = null;
|
||||
lastSection = null;
|
||||
}
|
||||
}
|
||||
|
||||
private long getChunkSectionIndex(int x, int y, int z) {
|
||||
return (((x >> 4) & 0x3FFFFFFL) << 38) | (((y >> 4) & 0xFFFL) << 26) | ((z >> 4) & 0x3FFFFFFL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user