mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-11-22 23:08:30 +01:00
Yeet cache chunks
So many features require this config option, and we don't intend on supporting it being both disabled and enabled.
This commit is contained in:
parent
7b0099e869
commit
ebf726ce9e
31 changed files with 92 additions and 290 deletions
|
@ -48,9 +48,4 @@ public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration
|
|||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheChunks() {
|
||||
return true; // We override this as with Bukkit, we have direct access to the server implementation
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,8 +87,6 @@ public interface GeyserConfiguration {
|
|||
|
||||
boolean isAboveBedrockNetherBuilding();
|
||||
|
||||
boolean isCacheChunks();
|
||||
|
||||
boolean isForceResourcePacks();
|
||||
|
||||
boolean isXboxAchievementsEnabled();
|
||||
|
|
|
@ -111,9 +111,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||
@JsonProperty("default-locale")
|
||||
private String defaultLocale = null; // is null by default so system language takes priority
|
||||
|
||||
@JsonProperty("cache-chunks")
|
||||
private boolean cacheChunks = false;
|
||||
|
||||
@JsonProperty("cache-images")
|
||||
private int cacheImages = 0;
|
||||
|
||||
|
|
|
@ -174,11 +174,8 @@ public class FishingHookEntity extends ThrowableEntity {
|
|||
* @return true if this entity is currently in air.
|
||||
*/
|
||||
protected boolean isInAir(GeyserSession session) {
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
return false;
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -94,11 +94,9 @@ public class LivingEntity extends Entity {
|
|||
Position bedPosition = (Position) entityMetadata.getValue();
|
||||
if (bedPosition != null) {
|
||||
metadata.put(EntityData.BED_POSITION, Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()));
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
}
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
// Indicate that the player should enter the sleep cycle
|
||||
// Has to be a byte or it does not work
|
||||
// (Bed position is what actually triggers sleep - "pose" is only optional)
|
||||
|
|
|
@ -166,11 +166,8 @@ public class ThrowableEntity extends Entity implements Tickable {
|
|||
* @return true if this entity is currently in water.
|
||||
*/
|
||||
protected boolean isInWater(GeyserSession session) {
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
return false;
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -111,7 +111,7 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
|||
float bedPositionSubtractorW = 0;
|
||||
float bedPositionSubtractorN = 0;
|
||||
Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION, null);
|
||||
if (session.getConnector().getConfig().isCacheChunks() && bedPosition != null) {
|
||||
if (bedPosition != null) {
|
||||
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
}
|
||||
String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId);
|
||||
|
|
|
@ -233,12 +233,6 @@ public class GeyserSession implements CommandSender {
|
|||
@Setter
|
||||
private boolean sprinting;
|
||||
|
||||
/**
|
||||
* Not updated if cache chunks is enabled.
|
||||
*/
|
||||
@Setter
|
||||
private boolean jumping;
|
||||
|
||||
/**
|
||||
* Whether the player is swimming in water.
|
||||
* Used to update speed when crawling.
|
||||
|
|
|
@ -42,11 +42,7 @@ public class ChunkCache {
|
|||
private int minY;
|
||||
|
||||
public ChunkCache(GeyserSession session) {
|
||||
if (session.getConnector().getWorldManager().hasOwnChunkCache()) {
|
||||
this.cache = false; // To prevent Spigot from initializing
|
||||
} else {
|
||||
this.cache = session.getConnector().getConfig().isCacheChunks();
|
||||
}
|
||||
this.cache = !session.getConnector().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing
|
||||
chunks = cache ? new Long2ObjectOpenHashMap<>() : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,8 +51,6 @@ import org.geysermc.connector.network.translators.item.ItemRegistry;
|
|||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Translator(packet = PlayerActionPacket.class)
|
||||
public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket> {
|
||||
|
||||
|
@ -162,43 +160,42 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
// Otherwise handled in BedrockInventoryTransactionTranslator
|
||||
break;
|
||||
case START_BREAK:
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
// Start the block breaking animation
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, vector);
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEventType.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
PlayerInventory inventory = session.getPlayerInventory();
|
||||
GeyserItemStack item = inventory.getItemInHand();
|
||||
ItemEntry itemEntry;
|
||||
CompoundTag nbtData;
|
||||
if (item != null) {
|
||||
itemEntry = item.getItemEntry();
|
||||
nbtData = item.getNbt();
|
||||
} else {
|
||||
itemEntry = null;
|
||||
nbtData = new CompoundTag("");
|
||||
}
|
||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(session, BlockTranslator.getBlockMapping(blockState), itemEntry, nbtData, true) * 20);
|
||||
startBreak.setData((int) (65535 / breakTime));
|
||||
session.setBreakingBlock(blockState);
|
||||
session.sendUpstreamPacket(startBreak);
|
||||
// Start the block breaking animation
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, vector);
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEventType.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
PlayerInventory inventory = session.getPlayerInventory();
|
||||
GeyserItemStack item = inventory.getItemInHand();
|
||||
ItemEntry itemEntry;
|
||||
CompoundTag nbtData;
|
||||
if (item != null) {
|
||||
itemEntry = item.getItemEntry();
|
||||
nbtData = item.getNbt();
|
||||
} else {
|
||||
itemEntry = null;
|
||||
nbtData = new CompoundTag("");
|
||||
}
|
||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(session, BlockTranslator.getBlockMapping(blockState), itemEntry, nbtData, true) * 20);
|
||||
startBreak.setData((int) (65535 / breakTime));
|
||||
session.setBreakingBlock(blockState);
|
||||
session.sendUpstreamPacket(startBreak);
|
||||
}
|
||||
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
||||
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
||||
String identifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockUp);
|
||||
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
|
||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
||||
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
||||
session.sendDownstreamPacket(startBreakingPacket);
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
||||
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
||||
String identifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockUp);
|
||||
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
|
||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
||||
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
||||
session.sendDownstreamPacket(startBreakingPacket);
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, position, BlockFace.values()[packet.getFace()]);
|
||||
session.sendDownstreamPacket(startBreakingPacket);
|
||||
break;
|
||||
|
@ -246,11 +243,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
session.getEntityCache().updateBossBars();
|
||||
break;
|
||||
case JUMP:
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// Save the jumping status for determining teleport status
|
||||
session.setJumping(true);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> session.setJumping(false), 1, TimeUnit.SECONDS);
|
||||
}
|
||||
// Leaving as a potential placeholder for an event or soul sand fixing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,32 +141,22 @@ public class CollisionManager {
|
|||
Vector3d position = Vector3d.from(Double.parseDouble(Float.toString(bedrockPosition.getX())), javaY,
|
||||
Double.parseDouble(Float.toString(bedrockPosition.getZ())));
|
||||
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
// With chunk caching, we can do some proper collision checks
|
||||
updatePlayerBoundingBox(position);
|
||||
updatePlayerBoundingBox(position);
|
||||
|
||||
// Correct player position
|
||||
if (!correctPlayerPosition()) {
|
||||
// Cancel the movement if it needs to be cancelled
|
||||
recalculatePosition();
|
||||
return null;
|
||||
}
|
||||
// Correct player position
|
||||
if (!correctPlayerPosition()) {
|
||||
// Cancel the movement if it needs to be cancelled
|
||||
recalculatePosition();
|
||||
return null;
|
||||
}
|
||||
|
||||
position = Vector3d.from(playerBoundingBox.getMiddleX(),
|
||||
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
|
||||
playerBoundingBox.getMiddleZ());
|
||||
position = Vector3d.from(playerBoundingBox.getMiddleX(),
|
||||
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
|
||||
playerBoundingBox.getMiddleZ());
|
||||
|
||||
if (!onGround) {
|
||||
// Trim the position to prevent rounding errors that make Java think we are clipping into a block
|
||||
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
|
||||
}
|
||||
} else {
|
||||
// When chunk caching is off, we have to rely on this
|
||||
// It rounds the Y position up to the nearest 0.5
|
||||
// This snaps players to snap to the top of stairs and slabs like on Java Edition
|
||||
// However, it causes issues such as the player floating on carpets
|
||||
if (onGround) javaY = Math.ceil(javaY * 2) / 2;
|
||||
position = position.up(javaY - position.getY());
|
||||
if (!onGround) {
|
||||
// Trim the position to prevent rounding errors that make Java think we are clipping into a block
|
||||
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
|
||||
}
|
||||
|
||||
return position;
|
||||
|
@ -268,10 +258,6 @@ public class CollisionManager {
|
|||
* were they not sneaking
|
||||
*/
|
||||
public boolean isUnderSlab() {
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// We can't reliably determine this
|
||||
return false;
|
||||
}
|
||||
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||
BlockCollision collision = CollisionTranslator.getCollisionAt(session, position.getX(), position.getY(), position.getZ());
|
||||
if (collision != null) {
|
||||
|
@ -289,8 +275,7 @@ public class CollisionManager {
|
|||
* @return if the player is currently in a water block
|
||||
*/
|
||||
public boolean isPlayerInWater() {
|
||||
return session.getConnector().getConfig().isCacheChunks()
|
||||
&& session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockTranslator.JAVA_WATER_ID;
|
||||
return session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockTranslator.JAVA_WATER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,11 +48,6 @@ public class CollisionTranslator {
|
|||
private static final Int2ObjectMap<BlockCollision> COLLISION_MAP = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public static void init() {
|
||||
// If chunk caching is off then don't initialize
|
||||
if (!GeyserConnector.getInstance().getConfig().isCacheChunks()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Class<?>> collisionTypes = new ArrayList<>();
|
||||
|
||||
Map<Class<?>, CollisionRemapper> annotationMap = new HashMap<>();
|
||||
|
|
|
@ -54,15 +54,6 @@ import java.util.Collections;
|
|||
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public BeaconInventoryTranslator() {
|
||||
super(1, new BlockInventoryHolder("minecraft:beacon", ContainerType.BEACON) {
|
||||
@Override
|
||||
public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// Beacons cannot work without knowing their physical location
|
||||
return;
|
||||
}
|
||||
super.prepareInventory(translator, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkInteractionPosition(GeyserSession session) {
|
||||
// Since we can't fall back to a virtual inventory, let's make opening one easier
|
||||
|
@ -71,7 +62,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
|
||||
@Override
|
||||
public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
if (!session.getConnector().getConfig().isCacheChunks() || !((BeaconContainer) inventory).isUsingRealBlock()) {
|
||||
if (!((BeaconContainer) inventory).isUsingRealBlock()) {
|
||||
InventoryUtils.closeInventory(session, inventory.getId(), false);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -64,9 +64,7 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
|||
passenger = session.getPlayerEntity();
|
||||
session.setRidingVehicleEntity(entity);
|
||||
// We need to confirm teleports before entering a vehicle, or else we will likely exit right out
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
session.confirmTeleport(passenger.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0).toDouble());
|
||||
}
|
||||
session.confirmTeleport(passenger.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0).toDouble());
|
||||
}
|
||||
// Passenger hasn't loaded in (likely since we're waiting for a skin response)
|
||||
// and entity link needs to be set later
|
||||
|
|
|
@ -25,21 +25,15 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
@Translator(packet = ServerPlayerActionAckPacket.class)
|
||||
|
@ -56,47 +50,5 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayer
|
|||
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
||||
session.sendUpstreamPacket(stopBreak);
|
||||
}
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
LevelEventPacket levelEvent = new LevelEventPacket();
|
||||
switch (packet.getAction()) {
|
||||
case START_DIGGING:
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
PlayerInventory inventory = session.getPlayerInventory();
|
||||
GeyserItemStack item = inventory.getItemInHand();
|
||||
ItemEntry itemEntry;
|
||||
CompoundTag nbtData;
|
||||
if (item != null) {
|
||||
itemEntry = item.getItemEntry();
|
||||
nbtData = item.getNbt();
|
||||
} else {
|
||||
itemEntry = null;
|
||||
nbtData = new CompoundTag("");
|
||||
}
|
||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(session, BlockTranslator.getBlockMapping(packet.getNewState()), itemEntry, nbtData, true) * 20);
|
||||
levelEvent.setData((int) (65535 / breakTime));
|
||||
session.setBreakingBlock(packet.getNewState());
|
||||
session.sendUpstreamPacket(levelEvent);
|
||||
break;
|
||||
case CANCEL_DIGGING:
|
||||
levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
levelEvent.setData(0);
|
||||
session.setBreakingBlock(0);
|
||||
session.sendUpstreamPacket(levelEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,21 +87,6 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||
|
||||
session.setSpawned(true);
|
||||
|
||||
// Ignore certain move correction packets for smoother movement
|
||||
// These are never relative
|
||||
// When chunk caching is enabled this isn't needed as we shouldn't get these
|
||||
if (!session.getConnector().getConfig().isCacheChunks() && packet.getRelative().isEmpty()) {
|
||||
double xDis = Math.abs(entity.getPosition().getX() - packet.getX());
|
||||
double yDis = entity.getPosition().getY() - packet.getY();
|
||||
double zDis = Math.abs(entity.getPosition().getZ() - packet.getZ());
|
||||
if (!(xDis > 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5)) {
|
||||
// Fake confirm the teleport but don't send it to the client
|
||||
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
|
||||
session.sendDownstreamPacket(teleportConfirmPacket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If coordinates are relative, then add to the existing coordinate
|
||||
double newX = packet.getX() +
|
||||
(packet.getRelative().contains(PositionElement.X) ? entity.getPosition().getX() : 0);
|
||||
|
|
|
@ -45,8 +45,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChang
|
|||
public void translate(ServerBlockChangePacket packet, GeyserSession session) {
|
||||
Position pos = packet.getRecord().getPosition();
|
||||
boolean updatePlacement = session.getConnector().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
|
||||
!(session.getConnector().getConfig().isCacheChunks() &&
|
||||
session.getConnector().getWorldManager().getBlockAt(session, pos) == packet.getRecord().getBlock());
|
||||
session.getConnector().getWorldManager().getBlockAt(session, pos) != packet.getRecord().getBlock();
|
||||
ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), pos);
|
||||
if (updatePlacement) {
|
||||
this.checkPlace(session, packet);
|
||||
|
|
|
@ -31,27 +31,22 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdate
|
|||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.RequiresBlockState;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
@Translator(packet = ServerUpdateTileEntityPacket.class)
|
||||
public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdateTileEntityPacket> {
|
||||
private final boolean cacheChunks;
|
||||
|
||||
public JavaUpdateTileEntityTranslator() {
|
||||
cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) {
|
||||
String id = BlockEntityUtils.getBedrockBlockEntityId(packet.getType().name());
|
||||
if (packet.getNbt().isEmpty()) { // Fixes errors in CubeCraft sending empty NBT
|
||||
if (packet.getNbt().isEmpty()) { // Fixes errors in servers sending empty NBT
|
||||
BlockEntityUtils.updateBlockEntity(session, null, packet.getPosition());
|
||||
return;
|
||||
}
|
||||
|
@ -59,11 +54,12 @@ public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdat
|
|||
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
|
||||
// between Java block states and Bedrock block entity data
|
||||
int blockState = cacheChunks ?
|
||||
// Cache chunks is enabled; use chunk cache
|
||||
session.getConnector().getWorldManager().getBlockAt(session, packet.getPosition()) :
|
||||
// Cache chunks is not enabled; use block entity cache
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(packet.getPosition());
|
||||
int blockState;
|
||||
if (translator instanceof RequiresBlockState) {
|
||||
blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getPosition());
|
||||
} else {
|
||||
blockState = BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), blockState), packet.getPosition());
|
||||
// Check for custom skulls.
|
||||
if (SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS && packet.getNbt().contains("SkullOwner")) {
|
||||
|
|
|
@ -33,11 +33,6 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
|
||||
@BlockEntity(name = "Banner")
|
||||
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getBannerColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
int bannerColor = BlockStateValues.getBannerColor(blockState);
|
||||
|
|
|
@ -31,11 +31,6 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
|
||||
@BlockEntity(name = "Bed")
|
||||
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getBedColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
byte bedcolor = BlockStateValues.getBedColor(blockState);
|
||||
|
|
|
@ -32,7 +32,14 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
/**
|
||||
* Implemented only if a block is a block entity in Bedrock and not Java Edition.
|
||||
*/
|
||||
public interface BedrockOnlyBlockEntity {
|
||||
public interface BedrockOnlyBlockEntity extends RequiresBlockState {
|
||||
/**
|
||||
* Determines if block is part of class
|
||||
* @param blockState BlockState to be compared
|
||||
* @return true if part of the class
|
||||
*/
|
||||
boolean isBlock(int blockState);
|
||||
|
||||
/**
|
||||
* Update the block on Bedrock Edition.
|
||||
* @param session GeyserSession.
|
||||
|
|
|
@ -47,10 +47,9 @@ import java.util.Map;
|
|||
public abstract class BlockEntityTranslator {
|
||||
public static final Map<String, BlockEntityTranslator> BLOCK_ENTITY_TRANSLATORS = new HashMap<>();
|
||||
/**
|
||||
* A list of all block entities that require the Java block state in order to fill out their block entity information.
|
||||
* This list will be smaller with cache chunks on as we don't need to double-cache data
|
||||
* A list of all block entities that only exist on Bedrock
|
||||
*/
|
||||
public static final ObjectArrayList<RequiresBlockState> REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>();
|
||||
public static final ObjectArrayList<BedrockOnlyBlockEntity> BEDROCK_ONLY_BLOCK_ENTITIES = new ObjectArrayList<>();
|
||||
|
||||
/**
|
||||
* Contains a list of irregular block entity name translations that can't be fit into the regex
|
||||
|
@ -84,18 +83,12 @@ public abstract class BlockEntityTranslator {
|
|||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_entity.failed", clazz.getCanonicalName()));
|
||||
}
|
||||
}
|
||||
boolean cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
for (Class<?> clazz : ref.getSubTypesOf(RequiresBlockState.class)) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName());
|
||||
for (Class<?> clazz : ref.getSubTypesOf(BedrockOnlyBlockEntity.class)) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Found Bedrock-only block entity: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
RequiresBlockState requiresBlockState = (RequiresBlockState) clazz.newInstance();
|
||||
if (cacheChunks && !(requiresBlockState instanceof BedrockOnlyBlockEntity)) {
|
||||
// Not needed to put this one in the map; cache chunks takes care of that for us
|
||||
GeyserConnector.getInstance().getLogger().debug("Not adding because cache chunks is enabled.");
|
||||
continue;
|
||||
}
|
||||
REQUIRES_BLOCK_STATE_LIST.add(requiresBlockState);
|
||||
BedrockOnlyBlockEntity bedrockOnlyBlockEntity = (BedrockOnlyBlockEntity) clazz.newInstance();
|
||||
BEDROCK_ONLY_BLOCK_ENTITIES.add(bedrockOnlyBlockEntity);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_state.failed", clazz.getCanonicalName()));
|
||||
}
|
||||
|
|
|
@ -54,9 +54,4 @@ public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator imp
|
|||
builder.put("LastExecution", (long) 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getCommandBlockValues().containsKey(blockState);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.geysermc.connector.utils.BlockEntityUtils;
|
|||
* Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity
|
||||
*/
|
||||
@BlockEntity(name = "Chest")
|
||||
public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||
public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity {
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getDoubleChestValues().containsKey(blockState);
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
|
||||
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity {
|
||||
/**
|
||||
* @param blockState the Java block state of a potential flower pot block
|
||||
* @return true if the block is a flower pot
|
||||
|
|
|
@ -30,21 +30,14 @@ import com.nukkitx.math.vector.Vector3i;
|
|||
import com.nukkitx.protocol.bedrock.packet.BlockEventPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
/**
|
||||
* Does not implement BlockEntityTranslator because it's only a block entity in Bedrock
|
||||
*/
|
||||
public class NoteblockBlockEntityTranslator implements RequiresBlockState {
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getNoteblockPitch(blockState) != -1;
|
||||
}
|
||||
public class NoteblockBlockEntityTranslator {
|
||||
|
||||
public static void translate(GeyserSession session, Position position) {
|
||||
int blockState = session.getConnector().getConfig().isCacheChunks() ?
|
||||
session.getConnector().getWorldManager().getBlockAt(session, position) :
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(position);
|
||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, position);
|
||||
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
||||
blockEventPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
||||
blockEventPacket.setEventType(0);
|
||||
|
|
|
@ -29,12 +29,4 @@ package org.geysermc.connector.network.translators.world.block.entity;
|
|||
* Implemented in block entities if their Java block state is required for additional values in Bedrock
|
||||
*/
|
||||
public interface RequiresBlockState {
|
||||
|
||||
/**
|
||||
* Determines if block is part of class
|
||||
* @param blockState BlockState to be compared
|
||||
* @return true if part of the class
|
||||
*/
|
||||
boolean isBlock(int blockState);
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
@BlockEntity(name = "ShulkerBox")
|
||||
public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator {
|
||||
public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
/**
|
||||
* Also used in {@link org.geysermc.connector.network.translators.inventory.translators.ShulkerInventoryTranslator}
|
||||
* where {@code tag} is passed as null.
|
||||
|
|
|
@ -50,11 +50,6 @@ import java.util.concurrent.TimeUnit;
|
|||
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
public static boolean ALLOW_CUSTOM_SKULLS;
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getSkullVariant(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
byte skullVariant = BlockStateValues.getSkullVariant(blockState);
|
||||
|
|
|
@ -42,8 +42,6 @@ import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
@ -55,7 +53,6 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.BedrockOnlyBlockEntity;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.RequiresBlockState;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator;
|
||||
import org.geysermc.connector.network.translators.world.chunk.BlockStorage;
|
||||
import org.geysermc.connector.network.translators.world.chunk.ChunkSection;
|
||||
|
@ -70,11 +67,6 @@ import static org.geysermc.connector.network.translators.world.block.BlockTransl
|
|||
|
||||
@UtilityClass
|
||||
public class ChunkUtils {
|
||||
/**
|
||||
* Temporarily stores positions of BlockState values that are needed for certain block entities actively.
|
||||
* Not used if cache chunks is enabled
|
||||
*/
|
||||
public static final Object2IntMap<Position> CACHED_BLOCK_ENTITIES = new Object2IntOpenHashMap<>();
|
||||
|
||||
private static int indexYZXtoXZY(int yzx) {
|
||||
return (yzx >> 8) | (yzx & 0x0F0) | ((yzx & 0x00F) << 8);
|
||||
|
@ -364,20 +356,12 @@ public class ChunkUtils {
|
|||
return newLecternHasBook;
|
||||
});
|
||||
|
||||
// Since Java stores bed colors/skull information as part of the namespaced ID and Bedrock stores it as a tag
|
||||
// This is the only place I could find that interacts with the Java block state and block updates
|
||||
// Iterates through all block entity translators and determines if the block state needs to be saved
|
||||
for (RequiresBlockState requiresBlockState : BlockEntityTranslator.REQUIRES_BLOCK_STATE_LIST) {
|
||||
if (requiresBlockState.isBlock(blockState)) {
|
||||
// Iterates through all Bedrock-only block entity translators and determines if a manual block entity packet
|
||||
// needs to be sent
|
||||
for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityTranslator.BEDROCK_ONLY_BLOCK_ENTITIES) {
|
||||
if (bedrockOnlyBlockEntity.isBlock(blockState)) {
|
||||
// Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks
|
||||
if (requiresBlockState instanceof BedrockOnlyBlockEntity) {
|
||||
((BedrockOnlyBlockEntity) requiresBlockState).updateBlock(session, blockState, position);
|
||||
break;
|
||||
}
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// Blocks aren't saved to a chunk cache; resort to this smaller cache
|
||||
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
||||
}
|
||||
bedrockOnlyBlockEntity.updateBlock(session, blockState, position);
|
||||
break; //No block will be a part of two classes
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +396,6 @@ public class ChunkUtils {
|
|||
@Data
|
||||
public static final class ChunkData {
|
||||
private final ChunkSection[] sections;
|
||||
|
||||
private final NbtMap[] blockEntities;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,18 +134,6 @@ emote-offhand-workaround: "disabled"
|
|||
# The default locale if we dont have the one the client requested. Uncomment to not use the default system language.
|
||||
# default-locale: en_us
|
||||
|
||||
# Configures if chunk caching should be enabled or not. This keeps an individual
|
||||
# record of each block the client loads in. This feature does allow for a few things
|
||||
# such as more accurate movement that causes less problems with anticheat (meaning
|
||||
# you're less likely to be banned) and allows block break animations to show up in
|
||||
# creative mode (and other features). Although this increases RAM usage, it likely
|
||||
# won't have much of an effect for the vast majority of people. However, if you're
|
||||
# running out of RAM or are in a RAM-sensitive environment, you may want to disable
|
||||
# this. When using the Spigot version of Geyser, support for features or
|
||||
# implementations this allows is automatically enabled without the additional caching
|
||||
# as Geyser has direct access to the server itself.
|
||||
cache-chunks: true
|
||||
|
||||
# Specify how many days images will be cached to disk to save downloading them from the internet.
|
||||
# A value of 0 is disabled. (Default: 0)
|
||||
cache-images: 0
|
||||
|
|
Loading…
Reference in a new issue