Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Ursprung
a84362af2c
Commit
1b6cfad5ad
@ -47,7 +47,7 @@ public class OffhandCommand extends GeyserCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
|
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
|
||||||
Direction.DOWN, session.getWorldCache().nextPredictionSequence());
|
Direction.DOWN, 0);
|
||||||
session.sendDownstreamPacket(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ public final class BlockRegistryPopulator {
|
|||||||
BlockMapping.BlockMappingBuilder builder = BlockMapping.builder();
|
BlockMapping.BlockMappingBuilder builder = BlockMapping.builder();
|
||||||
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
||||||
if (hardnessNode != null) {
|
if (hardnessNode != null) {
|
||||||
builder.hardness(hardnessNode.doubleValue());
|
builder.hardness(hardnessNode.floatValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand");
|
JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand");
|
||||||
|
@ -45,7 +45,7 @@ public class BlockMapping {
|
|||||||
*/
|
*/
|
||||||
int javaBlockId;
|
int javaBlockId;
|
||||||
|
|
||||||
double hardness;
|
float hardness;
|
||||||
boolean canBreakWithHand;
|
boolean canBreakWithHand;
|
||||||
/**
|
/**
|
||||||
* The index of this collision in collision.json
|
* The index of this collision in collision.json
|
||||||
|
@ -1311,7 +1311,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
private boolean disableBlocking() {
|
private boolean disableBlocking() {
|
||||||
if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
|
if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
|
||||||
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
|
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
|
||||||
Vector3i.ZERO, Direction.DOWN, worldCache.nextPredictionSequence());
|
Vector3i.ZERO, Direction.DOWN, 0);
|
||||||
sendDownstreamPacket(releaseItemPacket);
|
sendDownstreamPacket(releaseItemPacket);
|
||||||
playerEntity.setFlag(EntityFlag.BLOCKING, false);
|
playerEntity.setFlag(EntityFlag.BLOCKING, false);
|
||||||
return true;
|
return true;
|
||||||
|
@ -28,17 +28,17 @@ package org.geysermc.geyser.session.cache;
|
|||||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
|
||||||
import org.geysermc.geyser.scoreboard.Scoreboard;
|
import org.geysermc.geyser.scoreboard.Scoreboard;
|
||||||
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.ChunkUtils;
|
import org.geysermc.geyser.util.ChunkUtils;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class WorldCache {
|
public final class WorldCache {
|
||||||
private final GeyserSession session;
|
private final GeyserSession session;
|
||||||
@ -59,7 +59,7 @@ public final class WorldCache {
|
|||||||
private int trueTitleFadeOutTime;
|
private int trueTitleFadeOutTime;
|
||||||
|
|
||||||
private int currentSequence;
|
private int currentSequence;
|
||||||
private final Map<Vector3i, ServerVerifiedState> unverifiedPredictions = new Object2ObjectOpenHashMap<>(1);
|
private final Object2IntMap<Vector3i> unverifiedPredictions = new Object2IntOpenHashMap<>(1);
|
||||||
|
|
||||||
public WorldCache(GeyserSession session) {
|
public WorldCache(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
@ -135,30 +135,33 @@ public final class WorldCache {
|
|||||||
/* Code to support the prediction structure introduced in Java Edition 1.19.0
|
/* Code to support the prediction structure introduced in Java Edition 1.19.0
|
||||||
Blocks can be rolled back if invalid, but this requires some client-side information storage. */
|
Blocks can be rolled back if invalid, but this requires some client-side information storage. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This does not need to be called for all player action packets (as of 1.19.2) and can be set to 0 if blocks aren't
|
||||||
|
* changed in the action.
|
||||||
|
*/
|
||||||
public int nextPredictionSequence() {
|
public int nextPredictionSequence() {
|
||||||
return ++currentSequence;
|
return ++currentSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a record of a block at a certain position to rollback in the event it is incorrect.
|
* Stores a note that this position may need to be rolled back at a future point in time.
|
||||||
*/
|
*/
|
||||||
public void addServerCorrectBlockState(Vector3i position, int blockState) {
|
public void markPositionInSequence(Vector3i position) {
|
||||||
if (session.isEmulatePost1_18Logic()) {
|
if (session.isEmulatePost1_18Logic()) {
|
||||||
// Cheap hack
|
// Cheap hack
|
||||||
// On non-Bukkit platforms, ViaVersion will always confirm the sequence before the block is updated,
|
// On non-Bukkit platforms, ViaVersion will always confirm the sequence before the block is updated,
|
||||||
// meaning we'd send two block updates after (ChunkUtils.updateBlockClientSide in endPredictionsUpTo
|
// meaning we'd send two block updates after (ChunkUtils.updateBlockClientSide in endPredictionsUpTo
|
||||||
// and the packet updating from the client)
|
// and the packet updating from the client)
|
||||||
this.unverifiedPredictions.compute(position, ($, serverVerifiedState) -> serverVerifiedState == null
|
this.unverifiedPredictions.put(position, currentSequence);
|
||||||
? new ServerVerifiedState(currentSequence, blockState) : serverVerifiedState.setData(currentSequence, blockState));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateServerCorrectBlockState(Vector3i position) {
|
public void updateServerCorrectBlockState(Vector3i position, int blockState) {
|
||||||
if (this.unverifiedPredictions.isEmpty()) {
|
if (!this.unverifiedPredictions.isEmpty()) {
|
||||||
return;
|
this.unverifiedPredictions.removeInt(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unverifiedPredictions.remove(position);
|
ChunkUtils.updateBlock(session, blockState, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endPredictionsUpTo(int sequence) {
|
public void endPredictionsUpTo(int sequence) {
|
||||||
@ -166,40 +169,16 @@ public final class WorldCache {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Map.Entry<Vector3i, ServerVerifiedState>> it = this.unverifiedPredictions.entrySet().iterator();
|
Iterator<Object2IntMap.Entry<Vector3i>> it = Object2IntMaps.fastIterator(this.unverifiedPredictions);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Map.Entry<Vector3i, ServerVerifiedState> entry = it.next();
|
Object2IntMap.Entry<Vector3i> entry = it.next();
|
||||||
ServerVerifiedState serverVerifiedState = entry.getValue();
|
if (entry.getIntValue() <= sequence) {
|
||||||
if (serverVerifiedState.sequence <= sequence) {
|
|
||||||
// This block may be out of sync with the server
|
// This block may be out of sync with the server
|
||||||
// In 1.19.0 Java, you can verify this by trying to mine in spawn protection
|
// In 1.19.0 Java, you can verify this by trying to mine in spawn protection
|
||||||
ChunkUtils.updateBlockClientSide(session, serverVerifiedState.blockState, entry.getKey());
|
Vector3i position = entry.getKey();
|
||||||
|
ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().getBlockAt(session, position), position);
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ServerVerifiedState {
|
|
||||||
private int sequence;
|
|
||||||
private int blockState;
|
|
||||||
|
|
||||||
ServerVerifiedState(int sequence, int blockState) {
|
|
||||||
this.sequence = sequence;
|
|
||||||
this.blockState = blockState;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerVerifiedState setData(int sequence, int blockState) {
|
|
||||||
this.sequence = sequence;
|
|
||||||
this.blockState = blockState;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ServerVerifiedState{" +
|
|
||||||
"sequence=" + sequence +
|
|
||||||
", blockState=" + blockState +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -127,7 +127,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
|
dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
|
||||||
Vector3i.ZERO,
|
Vector3i.ZERO,
|
||||||
Direction.DOWN,
|
Direction.DOWN,
|
||||||
session.getWorldCache().nextPredictionSequence()
|
0
|
||||||
);
|
);
|
||||||
session.sendDownstreamPacket(dropPacket);
|
session.sendDownstreamPacket(dropPacket);
|
||||||
|
|
||||||
@ -408,13 +408,10 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sequence = session.getWorldCache().nextPredictionSequence();
|
int sequence = session.getWorldCache().nextPredictionSequence();
|
||||||
if (blockState != -1) {
|
session.getWorldCache().markPositionInSequence(packet.getBlockPosition());
|
||||||
session.getWorldCache().addServerCorrectBlockState(packet.getBlockPosition(), blockState);
|
// -1 means we don't know what block they're breaking
|
||||||
} else {
|
if (blockState == -1) {
|
||||||
blockState = BlockStateValues.JAVA_AIR_ID;
|
blockState = BlockStateValues.JAVA_AIR_ID;
|
||||||
// Client will desync here anyway
|
|
||||||
session.getWorldCache().addServerCorrectBlockState(packet.getBlockPosition(),
|
|
||||||
session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
||||||
@ -442,7 +439,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
if (packet.getActionType() == 0) {
|
if (packet.getActionType() == 0) {
|
||||||
// Followed to the Minecraft Protocol specification outlined at wiki.vg
|
// Followed to the Minecraft Protocol specification outlined at wiki.vg
|
||||||
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
|
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
|
||||||
Direction.DOWN, session.getWorldCache().nextPredictionSequence());
|
Direction.DOWN, 0);
|
||||||
session.sendDownstreamPacket(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -41,6 +41,7 @@ import com.nukkitx.protocol.bedrock.packet.*;
|
|||||||
import org.geysermc.geyser.entity.type.Entity;
|
import org.geysermc.geyser.entity.type.Entity;
|
||||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||||
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
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;
|
||||||
@ -128,7 +129,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
break;
|
break;
|
||||||
case DROP_ITEM:
|
case DROP_ITEM:
|
||||||
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
|
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
|
||||||
vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
|
vector, Direction.VALUES[packet.getFace()], 0);
|
||||||
session.sendDownstreamPacket(dropItemPacket);
|
session.sendDownstreamPacket(dropItemPacket);
|
||||||
break;
|
break;
|
||||||
case STOP_SLEEP:
|
case STOP_SLEEP:
|
||||||
@ -171,7 +172,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
}
|
}
|
||||||
int breakingBlock = session.getBreakingBlock();
|
int breakingBlock = session.getBreakingBlock();
|
||||||
if (breakingBlock == -1) {
|
if (breakingBlock == -1) {
|
||||||
break;
|
breakingBlock = BlockStateValues.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3f vectorFloat = vector.toFloat();
|
Vector3f vectorFloat = vector.toFloat();
|
||||||
@ -202,7 +203,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, session.getWorldCache().nextPredictionSequence());
|
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
||||||
session.sendDownstreamPacket(abortBreakingPacket);
|
session.sendDownstreamPacket(abortBreakingPacket);
|
||||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||||
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
|
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||||
|
@ -44,7 +44,7 @@ public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
|
|||||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
|
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
|
||||||
// Activate the workaround - we should trigger the offhand now
|
// Activate the workaround - we should trigger the offhand now
|
||||||
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
|
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
|
||||||
Direction.DOWN, session.getWorldCache().nextPredictionSequence());
|
Direction.DOWN, 0);
|
||||||
session.sendDownstreamPacket(swapHandsPacket);
|
session.sendDownstreamPacket(swapHandsPacket);
|
||||||
|
|
||||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||||
|
@ -35,7 +35,6 @@ 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 org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator;
|
import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator;
|
||||||
import org.geysermc.geyser.util.ChunkUtils;
|
|
||||||
|
|
||||||
@Translator(packet = ClientboundBlockUpdatePacket.class)
|
@Translator(packet = ClientboundBlockUpdatePacket.class)
|
||||||
public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlockUpdatePacket> {
|
public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlockUpdatePacket> {
|
||||||
@ -45,7 +44,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
|
|||||||
Vector3i pos = packet.getEntry().getPosition();
|
Vector3i pos = packet.getEntry().getPosition();
|
||||||
boolean updatePlacement = session.getGeyser().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
|
boolean updatePlacement = session.getGeyser().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
|
||||||
session.getGeyser().getWorldManager().getBlockAt(session, pos) != packet.getEntry().getBlock();
|
session.getGeyser().getWorldManager().getBlockAt(session, pos) != packet.getEntry().getBlock();
|
||||||
ChunkUtils.updateBlock(session, packet.getEntry().getBlock(), pos);
|
session.getWorldCache().updateServerCorrectBlockState(pos, packet.getEntry().getBlock());
|
||||||
if (updatePlacement) {
|
if (updatePlacement) {
|
||||||
this.checkPlace(session, packet);
|
this.checkPlace(session, packet);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.Clientb
|
|||||||
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 org.geysermc.geyser.util.ChunkUtils;
|
|
||||||
|
|
||||||
@Translator(packet = ClientboundSectionBlocksUpdatePacket.class)
|
@Translator(packet = ClientboundSectionBlocksUpdatePacket.class)
|
||||||
public class JavaSectionBlocksUpdateTranslator extends PacketTranslator<ClientboundSectionBlocksUpdatePacket> {
|
public class JavaSectionBlocksUpdateTranslator extends PacketTranslator<ClientboundSectionBlocksUpdatePacket> {
|
||||||
@ -38,7 +37,7 @@ public class JavaSectionBlocksUpdateTranslator extends PacketTranslator<Clientbo
|
|||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundSectionBlocksUpdatePacket packet) {
|
public void translate(GeyserSession session, ClientboundSectionBlocksUpdatePacket packet) {
|
||||||
for (BlockChangeEntry entry : packet.getEntries()) {
|
for (BlockChangeEntry entry : packet.getEntries()) {
|
||||||
ChunkUtils.updateBlock(session, entry.getBlock(), entry.getPosition());
|
session.getWorldCache().updateServerCorrectBlockState(entry.getPosition(), entry.getBlock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,6 @@ public class ChunkUtils {
|
|||||||
public static void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
public static void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||||
updateBlockClientSide(session, blockState, position);
|
updateBlockClientSide(session, blockState, position);
|
||||||
session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState);
|
session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState);
|
||||||
session.getWorldCache().updateServerCorrectBlockState(position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren