Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-12-28 00:50:13 +01:00
Optimize block connections on neighbour chunk calculation (#3228)
Dieser Commit ist enthalten in:
Ursprung
3ced95903a
Commit
68d1843496
@ -18,7 +18,6 @@
|
|||||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.viaversion.viaversion.api.Via;
|
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.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.BlockConnectionProvider;
|
||||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.PacketBlockConnectionProvider;
|
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 com.viaversion.viaversion.util.Key;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
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) {
|
public static void updateBlockStorage(UserConnection userConnection, int x, int y, int z, int blockState) {
|
||||||
if (!needStoreBlocks()) return;
|
if (!needStoreBlocks()) return;
|
||||||
if (ConnectionData.isWelcome(blockState)) {
|
if (ConnectionData.isWelcome(blockState)) {
|
||||||
@ -693,4 +619,85 @@ public final class ConnectionData {
|
|||||||
public static Object2IntMap<String> getKeyToId() {
|
public static Object2IntMap<String> getKeyToId() {
|
||||||
return keyToId;
|
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() {
|
public boolean storesBlocks() {
|
||||||
return false;
|
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() {
|
public boolean storesBlocks() {
|
||||||
return true;
|
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
|
// Workaround for packet order issue
|
||||||
wrapper.send(Protocol1_13To1_12_2.class);
|
wrapper.send(Protocol1_13To1_12_2.class);
|
||||||
wrapper.cancel();
|
wrapper.cancel();
|
||||||
|
ConnectionData.NeighbourUpdater updater = new ConnectionData.NeighbourUpdater(wrapper.user());
|
||||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||||
ChunkSection section = chunk.getSections()[i];
|
ChunkSection section = chunk.getSections()[i];
|
||||||
if (section == null) continue;
|
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();
|
private final Map<Long, SectionData> blockStorage = createLongObjectMap();
|
||||||
|
|
||||||
|
// Cache to retrieve section quicker
|
||||||
|
private Long lastIndex;
|
||||||
|
private SectionData lastSection;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
//noinspection StringBufferReplaceableByString - prevent relocation
|
//noinspection StringBufferReplaceableByString - prevent relocation
|
||||||
@ -73,7 +77,7 @@ public class BlockConnectionStorage implements StorableObject {
|
|||||||
|
|
||||||
public int get(int x, int y, int z) {
|
public int get(int x, int y, int z) {
|
||||||
long pair = getChunkSectionIndex(x, y, z);
|
long pair = getChunkSectionIndex(x, y, z);
|
||||||
SectionData map = blockStorage.get(pair);
|
SectionData map = getSection(pair);
|
||||||
if (map == null) return 0;
|
if (map == null) return 0;
|
||||||
short blockPosition = encodeBlockPos(x, y, z);
|
short blockPosition = encodeBlockPos(x, y, z);
|
||||||
NibbleArray nibbleArray = map.nibbleArray();
|
NibbleArray nibbleArray = map.nibbleArray();
|
||||||
@ -85,7 +89,7 @@ public class BlockConnectionStorage implements StorableObject {
|
|||||||
|
|
||||||
public void remove(int x, int y, int z) {
|
public void remove(int x, int y, int z) {
|
||||||
long pair = getChunkSectionIndex(x, y, z);
|
long pair = getChunkSectionIndex(x, y, z);
|
||||||
SectionData map = blockStorage.get(pair);
|
SectionData map = getSection(pair);
|
||||||
if (map == null) return;
|
if (map == null) return;
|
||||||
int blockIndex = encodeBlockPos(x, y, z);
|
int blockIndex = encodeBlockPos(x, y, z);
|
||||||
NibbleArray nibbleArray = map.nibbleArray();
|
NibbleArray nibbleArray = map.nibbleArray();
|
||||||
@ -104,11 +108,13 @@ public class BlockConnectionStorage implements StorableObject {
|
|||||||
for (short entry : map.blockIds()) {
|
for (short entry : map.blockIds()) {
|
||||||
if (entry != 0) return;
|
if (entry != 0) return;
|
||||||
}
|
}
|
||||||
blockStorage.remove(pair);
|
removeSection(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
blockStorage.clear();
|
blockStorage.clear();
|
||||||
|
lastSection = null;
|
||||||
|
lastIndex = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unloadChunk(int x, int z) {
|
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) {
|
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) {
|
private SectionData getChunkSection(long index, boolean requireNibbleArray) {
|
||||||
SectionData map = blockStorage.get(index);
|
SectionData map = getSection(index);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = new SectionData(new byte[4096]);
|
map = new SectionData(new byte[4096]);
|
||||||
blockStorage.put(index, map);
|
blockStorage.put(index, map);
|
||||||
|
lastSection = map;
|
||||||
|
lastIndex = index;
|
||||||
}
|
}
|
||||||
if (map.nibbleArray() == null && requireNibbleArray) {
|
if (map.nibbleArray() == null && requireNibbleArray) {
|
||||||
map.setNibbleArray(new NibbleArray(4096));
|
map.setNibbleArray(new NibbleArray(4096));
|
||||||
@ -133,6 +141,22 @@ public class BlockConnectionStorage implements StorableObject {
|
|||||||
return map;
|
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) {
|
private long getChunkSectionIndex(int x, int y, int z) {
|
||||||
return (((x >> 4) & 0x3FFFFFFL) << 38) | (((y >> 4) & 0xFFFL) << 26) | ((z >> 4) & 0x3FFFFFFL);
|
return (((x >> 4) & 0x3FFFFFFL) << 38) | (((y >> 4) & 0xFFFL) << 26) | ((z >> 4) & 0x3FFFFFFL);
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren