Made paintings not crash the client, bugfixes and improvements

This commit is contained in:
Tim203 2019-09-21 09:42:44 +02:00
parent b6d4bf5147
commit cbdf4f7633
16 changed files with 208 additions and 114 deletions

View file

@ -68,8 +68,8 @@ public class Entity {
protected boolean valid;
protected Set<Long> passengers = new HashSet<Long>();
protected Map<AttributeType, Attribute> attributes = new HashMap<AttributeType, Attribute>();
protected Set<Long> passengers = new HashSet<>();
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
public Entity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
this.entityId = entityId;
@ -128,9 +128,6 @@ public class Entity {
}
public void moveAbsolute(Vector3f position, Vector3f rotation) {
if (position.getX() == 0 && position.getY() == 0 && position.getZ() == 0 && rotation.getX() == 0 && rotation.getY() == 0)
return;
this.position = position;
this.rotation = rotation;
this.movePending = true;

View file

@ -0,0 +1,55 @@
package org.geysermc.connector.entity;
import com.flowpowered.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.PaintingType;
@Getter @Setter
@Accessors(chain = true)
public class PaintingEntity extends Entity {
private static final double OFFSET = -0.46875;
private PaintingType paintingName;
private int direction;
public PaintingEntity(long entityId, long geyserId, Vector3f position) {
super(entityId, geyserId, EntityType.PAINTING, position, Vector3f.ZERO, Vector3f.ZERO);
}
@Override
public void spawnEntity(GeyserSession session) {
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId);
addPaintingPacket.setRuntimeEntityId(geyserId);
addPaintingPacket.setName(paintingName.getBedrockName());
addPaintingPacket.setPosition(fixOffset(true));
addPaintingPacket.setDirection(direction);
session.getUpstream().sendPacket(addPaintingPacket);
valid = true;
GeyserLogger.DEFAULT.debug("Spawned painting on " + position);
}
public Vector3f fixOffset(boolean toBedrock) {
if (toBedrock) {
Vector3f position = super.position;
position = position.add(0.5, 0.5, 0.5);
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0;
switch (direction) {
case 0: return position.add(widthOffset, heightOffset, OFFSET);
case 1: return position.add(-OFFSET, heightOffset, widthOffset);
case 2: return position.add(-widthOffset, heightOffset, -OFFSET);
case 3: return position.add(OFFSET, heightOffset, -widthOffset);
}
}
return position;
}
}

View file

@ -49,8 +49,8 @@ public class PlayerEntity extends Entity {
private ItemData leggings;
private ItemData boots;
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
uuid = gameProfile.getId();
username = gameProfile.getName();
@ -58,8 +58,7 @@ public class PlayerEntity extends Entity {
// TODO: Break this into an EquippableEntity class
public void updateEquipment(GeyserSession session) {
if (hand != null && helmet != null && chestplate != null && leggings != null )
return;
if (!valid) return;
MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket();
armorEquipmentPacket.setRuntimeEntityId(geyserId);

View file

@ -112,14 +112,15 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(MovePlayerPacket packet) {
connector.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName());
if (!session.isLoggedIn()) {
if (!session.isLoggedIn() && !session.isLoggingIn()) {
// TODO it is safer to key authentication on something that won't change (UUID, not username)
if (!couldLoginUserByName(session.getAuthenticationData().getName())) {
LoginEncryptionUtils.showLoginWindow(session);
}
// else we were able to log the user in
return true;
} else if (session.isLoggingIn()) {
session.sendMessage("Please wait until you are logged in...");
}
return translateAndDefault(packet);

View file

@ -64,13 +64,10 @@ import java.util.UUID;
@Getter
public class GeyserSession implements Player {
private final GeyserConnector connector;
private final BedrockServerSession upstream;
private RemoteServer remoteServer;
private Client downstream;
private AuthData authenticationData;
private PlayerEntity playerEntity;
@ -86,12 +83,14 @@ public class GeyserSession implements Player {
@Setter
private Vector2i lastChunkPosition = null;
@Setter
private int renderDistance;
private boolean loggedIn;
private boolean loggingIn;
@Setter
private boolean spawned;
private boolean closed;
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
@ -104,10 +103,10 @@ public class GeyserSession implements Player {
this.scoreboardCache = new ScoreboardCache(this);
this.windowCache = new WindowCache(this);
this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "Unknown"), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), -1, 1, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
this.inventory = new PlayerInventory();
this.javaPacketCache = new DataCache<Packet>();
this.javaPacketCache = new DataCache<>();
this.spawned = false;
this.loggedIn = false;
@ -137,43 +136,49 @@ public class GeyserSession implements Player {
return;
}
try {
MinecraftProtocol protocol;
if (password != null && !password.isEmpty()) {
protocol = new MinecraftProtocol(username, password);
} else {
protocol = new MinecraftProtocol(username);
loggedIn = true;
// new thread so clients don't timeout
new Thread(() -> {
try {
MinecraftProtocol protocol;
if (password != null && !password.isEmpty()) {
protocol = new MinecraftProtocol(username, password);
} else {
protocol = new MinecraftProtocol(username);
}
downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory());
downstream.getSession().addListener(new SessionAdapter() {
@Override
public void connected(ConnectedEvent event) {
loggingIn = false;
loggedIn = true;
connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
playerEntity.setUuid(protocol.getProfile().getId());
playerEntity.setUsername(protocol.getProfile().getName());
}
@Override
public void disconnected(DisconnectedEvent event) {
loggingIn = false;
loggedIn = false;
connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason());
upstream.disconnect(event.getReason());
}
@Override
public void packetReceived(PacketReceivedEvent event) {
if (!closed)
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
}
});
downstream.getSession().connect();
} catch (RequestException ex) {
ex.printStackTrace();
}
downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory());
downstream.getSession().addListener(new SessionAdapter() {
@Override
public void connected(ConnectedEvent event) {
loggedIn = true;
connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
playerEntity.setUuid(protocol.getProfile().getId());
playerEntity.setUsername(protocol.getProfile().getName());
}
@Override
public void disconnected(DisconnectedEvent event) {
loggedIn = false;
connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason());
upstream.disconnect(event.getReason());
}
@Override
public void packetReceived(PacketReceivedEvent event) {
if (!closed)
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
}
});
downstream.getSession().connect();
} catch (RequestException ex) {
ex.printStackTrace();
}
}).start();
}
public void disconnect(String reason) {

View file

@ -64,7 +64,13 @@ public class EntityCache {
public void removeEntity(Entity entity) {
if (entity == null) return;
entityIdTranslations.remove(entity.getEntityId());
Long geyserId = entityIdTranslations.remove(entity.getEntityId());
if (geyserId != null) {
entities.remove(geyserId);
if (entity instanceof PlayerEntity) {
playerEntities.remove(((PlayerEntity) entity).getUuid());
}
}
entity.despawnEntity(session);
}

View file

@ -35,11 +35,10 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
@Override
public void translate(MobEquipmentPacket packet, GeyserSession session) {
if (packet.getHotbarSlot() > 8)
return;
if (packet.getContainerId() != ContainerId.INVENTORY)
if (!session.isSpawned() || packet.getHotbarSlot() > 8 ||
packet.getContainerId() != ContainerId.INVENTORY) {
return;
}
session.getInventory().setHeldItemSlot(packet.getHotbarSlot());

View file

@ -41,11 +41,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
@Override
public void translate(MovePlayerPacket packet, GeyserSession session) {
Entity entity = session.getPlayerEntity();
if (entity == null)
return;
if (!session.isLoggedIn())
return;
if (entity == null || !session.isSpawned()) return;
if (!isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) {
session.getConnector().getLogger().info("Recalculating position...");

View file

@ -2,6 +2,7 @@ package org.geysermc.connector.network.translators.block;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.network.translators.item.BedrockItem;
import org.geysermc.connector.utils.Remapper;
@ -11,8 +12,8 @@ public class BlockTranslator {
public BedrockItem getBedrockBlock(BlockState state) {
BedrockItem bedrockItem = Remapper.BLOCK_REMAPPER.convertToBedrockB(new ItemStack(state.getId()));
if (bedrockItem == null) {
// GeyserLogger.DEFAULT.debug("Missing mapping for java block " + state.getId());
return BedrockItem.AIR;
GeyserLogger.DEFAULT.debug("Missing mapping for java block " + state.getId() + "/nPlease report this to Geyser.");
return BedrockItem.DIRT; // so we can walk and not getting stuck x)
}
return bedrockItem;

View file

@ -25,21 +25,11 @@
package org.geysermc.connector.network.translators.java;
import com.flowpowered.math.vector.Vector3f;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import com.nukkitx.protocol.bedrock.packet.*;
import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.TranslatorsInit;
public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacket> {
@ -49,29 +39,12 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
session.getUpstream().sendPacketImmediately(bedrockPacket);
Vector3f pos = new Vector3f(0, 0, 0);
int chunkX = pos.getFloorX() >> 4;
int chunkZ = pos.getFloorZ() >> 4;
for (int x = -1; x < 1; x++) {
for (int z = -1; z < 1; z++) {
LevelChunkPacket data = new LevelChunkPacket();
data.setChunkX(chunkX + x);
data.setChunkZ(chunkZ + z);
data.setSubChunksLength(0);
data.setData(TranslatorsInit.EMPTY_LEVEL_CHUNK_DATA);
session.getUpstream().sendPacketImmediately(data);
}
}
PlayStatusPacket playStatus = new PlayStatusPacket();
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
session.getUpstream().sendPacketImmediately(playStatus);
Entity entity = session.getPlayerEntity();
if (entity == null)
return;
PlayerEntity entity = session.getPlayerEntity();
if (entity == null) return;
session.getPlayerEntity().setEntityId(packet.getEntityId());
@ -84,6 +57,14 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
entityDataPacket.getMetadata().putAll(entity.getMetadata());
session.getUpstream().sendPacket(entityDataPacket);
// session.setSpawned(true);
session.setRenderDistance(packet.getViewDistance() + 1); // +1 to be sure it includes every chunk
System.out.println(session.getRenderDistance());
if (session.getRenderDistance() > 32) session.setRenderDistance(32); // <3 u ViaVersion but I don't like crashing clients x)
ChunkRadiusUpdatedPacket packet1 = new ChunkRadiusUpdatedPacket();
packet1.setRadius(session.getRenderDistance());
session.getUpstream().sendPacket(packet1);
session.setSpawned(true);
}
}

View file

@ -40,8 +40,7 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
entity = session.getPlayerEntity();
}
if (entity == null)
return;
if (entity == null) return;
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());

View file

@ -6,7 +6,6 @@ import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.utils.ProvidedSkin;
@ -33,7 +32,6 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
entry.getProfile(),
-1,
geyserId,
EntityType.PLAYER,
Vector3f.ZERO,
Vector3f.ZERO,
Vector3f.ZERO

View file

@ -51,9 +51,6 @@ public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacke
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
type, position, motion, rotation);
if (entity == null)
return;
session.getEntityCache().spawnEntity(entity);
}
}

View file

@ -27,10 +27,11 @@ package org.geysermc.connector.network.translators.java.entity.spawn;
import com.flowpowered.math.vector.Vector3f;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPaintingPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.api.Geyser;
import org.geysermc.connector.entity.PaintingEntity;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.utils.PaintingType;
public class JavaSpawnPaintingTranslator extends PacketTranslator<ServerSpawnPaintingPacket> {
@ -38,12 +39,16 @@ public class JavaSpawnPaintingTranslator extends PacketTranslator<ServerSpawnPai
public void translate(ServerSpawnPaintingPacket packet, GeyserSession session) {
Vector3f position = new Vector3f(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
EntityType.PAINTING, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
Geyser.getGeneralThreadPool().execute(() -> { // #slowdownbrother, just don't execute it directly
PaintingEntity entity = new PaintingEntity(
packet.getEntityId(),
session.getEntityCache().getNextEntityId().incrementAndGet(),
position
)
.setPaintingName(PaintingType.getByPaintingType(packet.getPaintingType()))
.setDirection(packet.getDirection().ordinal());
if (entity == null)
return;
session.getEntityCache().spawnEntity(entity);
session.getEntityCache().spawnEntity(entity);
});
}
}

View file

@ -9,7 +9,6 @@ import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.geysermc.api.Geyser;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.utils.ChunkUtils;
@ -28,7 +27,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
if (chunkPos == null || !chunkPos.equals(newChunkPos)) {
NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket();
chunkPublisherUpdatePacket.setPosition(position.toInt());
chunkPublisherUpdatePacket.setRadius(8 << 4);
chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4);
session.getUpstream().sendPacket(chunkPublisherUpdatePacket);
session.setLastChunkPosition(newChunkPos);

View file

@ -0,0 +1,56 @@
package org.geysermc.connector.utils;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum PaintingType {
KEBAB("Kebab", 1, 1),
AZTEC("Aztec", 1, 1),
ALBAN("Alban", 1, 1),
AZTEC2("Aztec2", 1, 1),
BOMB("Bomb", 1, 1),
PLANT("Plant", 1, 1),
WASTELAND("Wasteland", 1, 1),
WANDERER("Wanderer", 1, 2),
GRAHAM("Graham", 1, 2),
POOL("Pool", 2, 1),
COURBET("Courbet", 2, 1),
SUNSET("Sunset", 2, 1),
SEA("Sea", 2, 1),
CREEBET("Creebet", 2, 1),
MATCH("Match", 2, 2),
BUST("Bust", 2, 2),
STAGE("Stage", 2, 2),
VOID("Void", 2, 2),
SKULL_AND_ROSES("SkullAndRoses", 2, 2),
WITHER("Wither", 2, 2),
FIGHTERS("Fighters", 4, 2),
SKELETON("Skeleton", 4, 3),
DONKEY_KONG("DonkeyKong", 4, 3),
POINTER("Pointer", 4, 4),
PIG_SCENE("Pigscene", 4, 4),
BURNING_SKULL("Flaming Skull", 4, 4); // burning skull on java edition, flaming skull on bedrock
private static final PaintingType[] VALUES = values();
private String bedrockName;
private int width;
private int height;
public com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType toJavaType() {
return com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType.valueOf(name());
}
public static PaintingType getByName(String javaName) {
for (PaintingType paintingName : VALUES) {
if (paintingName.name().equalsIgnoreCase(javaName)) return paintingName;
}
return KEBAB;
}
public static PaintingType getByPaintingType(com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType paintingType) {
return getByName(paintingType.name());
}
}