Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 14:30:17 +01:00
Use UpdateSubChunkBlocksPacket
Dieser Commit ist enthalten in:
Ursprung
7801e357fb
Commit
02b2ed1db4
@ -168,6 +168,12 @@ public final class WorldCache {
|
|||||||
ChunkUtils.updateBlock(session, blockState, position);
|
ChunkUtils.updateBlock(session, blockState, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removePrediction(Vector3i position) {
|
||||||
|
if (!this.unverifiedPredictions.isEmpty()) {
|
||||||
|
this.unverifiedPredictions.removeInt(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void endPredictionsUpTo(int sequence) {
|
public void endPredictionsUpTo(int sequence) {
|
||||||
if (this.unverifiedPredictions.isEmpty()) {
|
if (this.unverifiedPredictions.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -25,19 +25,190 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.java.level;
|
package org.geysermc.geyser.translator.protocol.java.level;
|
||||||
|
|
||||||
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateSubChunkBlocksPacket;
|
||||||
|
import org.geysermc.erosion.util.BlockPositionIterator;
|
||||||
|
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||||
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
|
import org.geysermc.geyser.session.cache.SkullCache;
|
||||||
|
import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity;
|
||||||
|
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockChangeEntry;
|
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockChangeEntry;
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSectionBlocksUpdatePacket;
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSectionBlocksUpdatePacket;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID;
|
||||||
|
|
||||||
@Translator(packet = ClientboundSectionBlocksUpdatePacket.class)
|
@Translator(packet = ClientboundSectionBlocksUpdatePacket.class)
|
||||||
public class JavaSectionBlocksUpdateTranslator extends PacketTranslator<ClientboundSectionBlocksUpdatePacket> {
|
public class JavaSectionBlocksUpdateTranslator extends PacketTranslator<ClientboundSectionBlocksUpdatePacket> {
|
||||||
|
private static final int NEIGHBORS_NETWORK_FLAG = (1 << UpdateBlockPacket.Flag.NEIGHBORS.ordinal()) | (1 << UpdateBlockPacket.Flag.NETWORK.ordinal());
|
||||||
|
private static final int NETWORK_FLAG = (1 << UpdateBlockPacket.Flag.NETWORK.ordinal());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundSectionBlocksUpdatePacket packet) {
|
public void translate(GeyserSession session, ClientboundSectionBlocksUpdatePacket packet) {
|
||||||
|
// Send normal block updates if not many changes
|
||||||
|
if (packet.getEntries().length < 32) {
|
||||||
for (BlockChangeEntry entry : packet.getEntries()) {
|
for (BlockChangeEntry entry : packet.getEntries()) {
|
||||||
session.getWorldCache().updateServerCorrectBlockState(entry.getPosition(), entry.getBlock());
|
session.getWorldCache().updateServerCorrectBlockState(entry.getPosition(), entry.getBlock());
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateSubChunkBlocksPacket subChunkBlocksPacket = new UpdateSubChunkBlocksPacket();
|
||||||
|
subChunkBlocksPacket.setChunkX(packet.getChunkX());
|
||||||
|
subChunkBlocksPacket.setChunkY(packet.getChunkY());
|
||||||
|
subChunkBlocksPacket.setChunkZ(packet.getChunkZ());
|
||||||
|
|
||||||
|
// If the entire section is updated, this might be a legacy non-full chunk update
|
||||||
|
// which can contain thousands of unchanged blocks
|
||||||
|
if (packet.getEntries().length == 4096) {
|
||||||
|
// hack - bedrock might ignore the block updates if the chunk was still loading.
|
||||||
|
// sending an UpdateBlockPacket seems to force it
|
||||||
|
BlockChangeEntry firstEntry = packet.getEntries()[0];
|
||||||
|
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||||
|
blockPacket.setBlockPosition(firstEntry.getPosition());
|
||||||
|
blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(firstEntry.getBlock()));
|
||||||
|
blockPacket.setDataLayer(0);
|
||||||
|
session.sendUpstreamPacket(blockPacket);
|
||||||
|
|
||||||
|
// Filter out unchanged blocks
|
||||||
|
Vector3i offset = Vector3i.from(packet.getChunkX() << 4, packet.getChunkY() << 4, packet.getChunkZ() << 4);
|
||||||
|
BlockPositionIterator blockIter = BlockPositionIterator.fromMinMax(
|
||||||
|
offset.getX(), offset.getY(), offset.getZ(),
|
||||||
|
offset.getX() + 15, offset.getY() + 15, offset.getZ() + 15
|
||||||
|
);
|
||||||
|
|
||||||
|
int[] sectionBlocks = session.getGeyser().getWorldManager().getBlocksAt(session, blockIter);
|
||||||
|
BitSet waterlogged = BlockRegistries.WATERLOGGED.get();
|
||||||
|
for (BlockChangeEntry entry : packet.getEntries()) {
|
||||||
|
Vector3i pos = entry.getPosition().sub(offset);
|
||||||
|
int index = pos.getZ() + pos.getX() * 16 + pos.getY() * 256;
|
||||||
|
int oldBlockState = sectionBlocks[index];
|
||||||
|
if (oldBlockState != entry.getBlock()) {
|
||||||
|
// Avoid sending unnecessary waterlogged updates
|
||||||
|
boolean updateWaterlogged = waterlogged.get(oldBlockState) != waterlogged.get(entry.getBlock());
|
||||||
|
applyEntry(session, entry, subChunkBlocksPacket, updateWaterlogged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (BlockChangeEntry entry : packet.getEntries()) {
|
||||||
|
applyEntry(session, entry, subChunkBlocksPacket, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(subChunkBlocksPacket);
|
||||||
|
|
||||||
|
// Post block update
|
||||||
|
for (BlockChangeEntry entry : packet.getEntries()) {
|
||||||
|
session.getWorldCache().removePrediction(entry.getPosition());
|
||||||
|
BlockStateValues.getLecternBookStates().handleBlockChange(session, entry.getBlock(), entry.getPosition());
|
||||||
|
|
||||||
|
// Iterates through all Bedrock-only block entity translators and determines if a manual block entity packet
|
||||||
|
// needs to be sent
|
||||||
|
for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) {
|
||||||
|
if (bedrockOnlyBlockEntity.isBlock(entry.getBlock())) {
|
||||||
|
// Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks
|
||||||
|
bedrockOnlyBlockEntity.updateBlock(session, entry.getBlock(), entry.getPosition());
|
||||||
|
break; //No block will be a part of two classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modified version of ChunkUtils#updateBlockClientSide
|
||||||
|
private static void applyEntry(GeyserSession session, BlockChangeEntry entry, UpdateSubChunkBlocksPacket subChunkBlocksPacket, boolean updateWaterlogged) {
|
||||||
|
Vector3i position = entry.getPosition();
|
||||||
|
int blockState = entry.getBlock();
|
||||||
|
|
||||||
|
session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState);
|
||||||
|
|
||||||
|
// Checks for item frames so they aren't tripped up and removed
|
||||||
|
ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position);
|
||||||
|
if (itemFrameEntity != null) {
|
||||||
|
if (blockState == JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it
|
||||||
|
itemFrameEntity.updateBlock(true);
|
||||||
|
// Still update the chunk cache with the new block if updateBlock is called
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Otherwise, let's still store our reference to the item frame, but let the new block take precedence for now
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDefinition definition = session.getBlockMappings().getBedrockBlock(blockState);
|
||||||
|
|
||||||
|
int skullVariant = BlockStateValues.getSkullVariant(blockState);
|
||||||
|
if (skullVariant == -1) {
|
||||||
|
// Skull is gone
|
||||||
|
session.getSkullCache().removeSkull(position);
|
||||||
|
} else if (skullVariant == 3) {
|
||||||
|
// The changed block was a player skull so check if a custom block was defined for this skull
|
||||||
|
SkullCache.Skull skull = session.getSkullCache().updateSkull(position, blockState);
|
||||||
|
if (skull != null && skull.getBlockDefinition() != null) {
|
||||||
|
definition = skull.getBlockDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent moving_piston from being placed
|
||||||
|
// It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker
|
||||||
|
if (!BlockStateValues.isMovingPiston(blockState)) {
|
||||||
|
subChunkBlocksPacket.getStandardBlocks().add(new org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry(
|
||||||
|
position,
|
||||||
|
definition,
|
||||||
|
NEIGHBORS_NETWORK_FLAG,
|
||||||
|
-1,
|
||||||
|
org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry.MessageType.NONE
|
||||||
|
));
|
||||||
|
|
||||||
|
if (updateWaterlogged) {
|
||||||
|
BlockDefinition waterDefinition = BlockRegistries.WATERLOGGED.get().get(blockState) ?
|
||||||
|
session.getBlockMappings().getBedrockWater() : session.getBlockMappings().getBedrockAir();
|
||||||
|
subChunkBlocksPacket.getExtraBlocks().add(new org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry(
|
||||||
|
position,
|
||||||
|
waterDefinition,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry.MessageType.NONE
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extended collision boxes for custom blocks
|
||||||
|
if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) {
|
||||||
|
int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ());
|
||||||
|
BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState);
|
||||||
|
int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ());
|
||||||
|
BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock);
|
||||||
|
if (belowBedrockExtendedCollisionDefinition != null && blockState == BlockStateValues.JAVA_AIR_ID) {
|
||||||
|
subChunkBlocksPacket.getStandardBlocks().add(new org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry(
|
||||||
|
position,
|
||||||
|
belowBedrockExtendedCollisionDefinition,
|
||||||
|
NETWORK_FLAG,
|
||||||
|
-1,
|
||||||
|
org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry.MessageType.NONE
|
||||||
|
));
|
||||||
|
} else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == BlockStateValues.JAVA_AIR_ID) {
|
||||||
|
subChunkBlocksPacket.getStandardBlocks().add(new org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry(
|
||||||
|
position.add(0, 1, 0),
|
||||||
|
aboveBedrockExtendedCollisionDefinition,
|
||||||
|
NETWORK_FLAG,
|
||||||
|
-1,
|
||||||
|
org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry.MessageType.NONE
|
||||||
|
));
|
||||||
|
} else if (aboveBlock == BlockStateValues.JAVA_AIR_ID) {
|
||||||
|
subChunkBlocksPacket.getStandardBlocks().add(new org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry(
|
||||||
|
position.add(0, 1, 0),
|
||||||
|
session.getBlockMappings().getBedrockAir(),
|
||||||
|
NETWORK_FLAG,
|
||||||
|
-1,
|
||||||
|
org.cloudburstmc.protocol.bedrock.data.BlockChangeEntry.MessageType.NONE
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren