Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Third party capes, rotation fixed, wait for the client and updated protocol lib
Dieser Commit ist enthalten in:
Ursprung
0b193c04e7
Commit
5eb7565b0a
@ -74,7 +74,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.protocol</groupId>
|
<groupId>com.nukkitx.protocol</groupId>
|
||||||
<artifactId>bedrock-v361</artifactId>
|
<artifactId>bedrock-v361</artifactId>
|
||||||
<version>2.1.3</version>
|
<version>2.2.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -32,7 +32,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserConfiguration {
|
public class GeyserConfiguration {
|
||||||
|
|
||||||
private BedrockConfiguration bedrock;
|
private BedrockConfiguration bedrock;
|
||||||
private RemoteConfiguration remote;
|
private RemoteConfiguration remote;
|
||||||
|
|
||||||
@ -50,5 +49,8 @@ public class GeyserConfiguration {
|
|||||||
@JsonProperty("general-thread-pool")
|
@JsonProperty("general-thread-pool")
|
||||||
private int generalThreadPool;
|
private int generalThreadPool;
|
||||||
|
|
||||||
|
@JsonProperty("allow-third-party-capes")
|
||||||
|
private boolean allowThirdPartyCapes;
|
||||||
|
|
||||||
private MetricInfo metrics;
|
private MetricInfo metrics;
|
||||||
}
|
}
|
@ -25,10 +25,11 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.console;
|
package org.geysermc.connector.console;
|
||||||
|
|
||||||
import org.geysermc.api.ChatColor;
|
|
||||||
import io.sentry.Sentry;
|
import io.sentry.Sentry;
|
||||||
|
import org.geysermc.api.ChatColor;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ public class GeyserLogger implements org.geysermc.api.logger.Logger {
|
|||||||
@Override
|
@Override
|
||||||
public void error(String message, Throwable error) {
|
public void error(String message, Throwable error) {
|
||||||
waitFor();
|
waitFor();
|
||||||
System.out.println(printConsole(ChatColor.RED + message + "\n" + error.getMessage(), colored));
|
System.out.println(printConsole(ChatColor.RED + message + "\n" + error, colored));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,7 +57,9 @@ public class Entity {
|
|||||||
protected Vector3f position;
|
protected Vector3f position;
|
||||||
protected Vector3f motion;
|
protected Vector3f motion;
|
||||||
|
|
||||||
// 1 - pitch, 2 - yaw, 3 - roll (head yaw)
|
/**
|
||||||
|
* x = Yaw, y = Pitch, z = HeadYaw
|
||||||
|
*/
|
||||||
protected Vector3f rotation;
|
protected Vector3f rotation;
|
||||||
|
|
||||||
protected int scale = 1;
|
protected int scale = 1;
|
||||||
@ -89,7 +91,7 @@ public class Entity {
|
|||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
addEntityPacket.setUniqueEntityId(geyserId);
|
||||||
addEntityPacket.setPosition(position);
|
addEntityPacket.setPosition(position);
|
||||||
addEntityPacket.setMotion(motion);
|
addEntityPacket.setMotion(motion);
|
||||||
addEntityPacket.setRotation(rotation);
|
addEntityPacket.setRotation(getBedrockRotation());
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
addEntityPacket.setEntityType(entityType.getType());
|
||||||
addEntityPacket.getMetadata().putAll(getMetadata());
|
addEntityPacket.getMetadata().putAll(getMetadata());
|
||||||
|
|
||||||
@ -99,33 +101,37 @@ public class Entity {
|
|||||||
GeyserLogger.DEFAULT.debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
GeyserLogger.DEFAULT.debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void despawnEntity(GeyserSession session) {
|
/**
|
||||||
if (!valid) return;
|
* @return can be deleted
|
||||||
|
*/
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
if (!valid) return true;
|
||||||
|
|
||||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||||
removeEntityPacket.setUniqueEntityId(geyserId);
|
removeEntityPacket.setUniqueEntityId(geyserId);
|
||||||
session.getUpstream().sendPacket(removeEntityPacket);
|
session.getUpstream().sendPacket(removeEntityPacket);
|
||||||
|
|
||||||
valid = false;
|
valid = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveRelative(double relX, double relY, double relZ, float pitch, float yaw) {
|
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch) {
|
||||||
moveRelative(relX, relY, relZ, new Vector3f(pitch, yaw, yaw));
|
moveRelative(relX, relY, relZ, new Vector3f(yaw, pitch, yaw));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveRelative(double relX, double relY, double relZ, Vector3f rotation) {
|
public void moveRelative(double relX, double relY, double relZ, Vector3f rotation) {
|
||||||
this.rotation = rotation;
|
setRotation(rotation);
|
||||||
this.position = new Vector3f(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
this.position = new Vector3f(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||||
this.movePending = true;
|
this.movePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveAbsolute(Vector3f position, float pitch, float yaw) {
|
public void moveAbsolute(Vector3f position, float yaw, float pitch) {
|
||||||
moveAbsolute(position, new Vector3f(pitch, yaw, yaw));
|
moveAbsolute(position, new Vector3f(yaw, pitch, yaw));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveAbsolute(Vector3f position, Vector3f rotation) {
|
public void moveAbsolute(Vector3f position, Vector3f rotation) {
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
this.rotation = rotation;
|
setRotation(rotation);
|
||||||
this.movePending = true;
|
this.movePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +195,13 @@ public class Entity {
|
|||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x = Pitch, y = HeadYaw, z = Yaw
|
||||||
|
*/
|
||||||
|
public Vector3f getBedrockRotation() {
|
||||||
|
return new Vector3f(rotation.getY(), rotation.getZ(), rotation.getX());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <I extends Entity> I as(Class<I> entityClass) {
|
public <I extends Entity> I as(Class<I> entityClass) {
|
||||||
return entityClass.isInstance(this) ? (I) this : null;
|
return entityClass.isInstance(this) ? (I) this : null;
|
||||||
|
@ -43,13 +43,13 @@ public class PlayerEntity extends Entity {
|
|||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
private String username;
|
private String username;
|
||||||
private long lastSkinUpdate = -1;
|
private long lastSkinUpdate = -1;
|
||||||
|
private boolean playerList = true;
|
||||||
private ItemData hand = ItemData.of(0, (short) 0, 0);
|
|
||||||
|
|
||||||
private ItemData helmet;
|
private ItemData helmet;
|
||||||
private ItemData chestplate;
|
private ItemData chestplate;
|
||||||
private ItemData leggings;
|
private ItemData leggings;
|
||||||
private ItemData boots;
|
private ItemData boots;
|
||||||
|
private ItemData hand = ItemData.of(0, (short) 0, 0);
|
||||||
|
|
||||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||||
@ -74,6 +74,12 @@ public class PlayerEntity extends Entity {
|
|||||||
session.getUpstream().sendPacket(armorEquipmentPacket);
|
session.getUpstream().sendPacket(armorEquipmentPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
super.despawnEntity(session);
|
||||||
|
return !playerList; // don't remove from cache when still on playerlist
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
if (geyserId == 1) return;
|
if (geyserId == 1) return;
|
||||||
@ -84,7 +90,7 @@ public class PlayerEntity extends Entity {
|
|||||||
addPlayerPacket.setRuntimeEntityId(geyserId);
|
addPlayerPacket.setRuntimeEntityId(geyserId);
|
||||||
addPlayerPacket.setUniqueEntityId(geyserId);
|
addPlayerPacket.setUniqueEntityId(geyserId);
|
||||||
addPlayerPacket.setPosition(position);
|
addPlayerPacket.setPosition(position);
|
||||||
addPlayerPacket.setRotation(rotation);
|
addPlayerPacket.setRotation(getBedrockRotation());
|
||||||
addPlayerPacket.setMotion(motion);
|
addPlayerPacket.setMotion(motion);
|
||||||
addPlayerPacket.setHand(hand);
|
addPlayerPacket.setHand(hand);
|
||||||
addPlayerPacket.setPlayerFlags(0);
|
addPlayerPacket.setPlayerFlags(0);
|
||||||
@ -98,6 +104,5 @@ public class PlayerEntity extends Entity {
|
|||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
session.getUpstream().sendPacket(addPlayerPacket);
|
session.getUpstream().sendPacket(addPlayerPacket);
|
||||||
// System.out.println("Spawned player "+uuid+" "+username+" "+geyserId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ import org.geysermc.api.session.AuthData;
|
|||||||
import org.geysermc.api.window.FormWindow;
|
import org.geysermc.api.window.FormWindow;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
import org.geysermc.connector.entity.PlayerEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.cache.*;
|
import org.geysermc.connector.network.session.cache.*;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
import org.geysermc.connector.network.translators.Registry;
|
||||||
@ -65,7 +64,7 @@ import java.util.UUID;
|
|||||||
@Getter
|
@Getter
|
||||||
public class GeyserSession implements Player {
|
public class GeyserSession implements Player {
|
||||||
private final GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
private final BedrockServerSession upstream;
|
private final UpstreamSession upstream;
|
||||||
private RemoteServer remoteServer;
|
private RemoteServer remoteServer;
|
||||||
private Client downstream;
|
private Client downstream;
|
||||||
private AuthData authenticationData;
|
private AuthData authenticationData;
|
||||||
@ -95,7 +94,7 @@ public class GeyserSession implements Player {
|
|||||||
|
|
||||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||||
this.connector = connector;
|
this.connector = connector;
|
||||||
this.upstream = bedrockServerSession;
|
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||||
|
|
||||||
this.chunkCache = new ChunkCache(this);
|
this.chunkCache = new ChunkCache(this);
|
||||||
this.entityCache = new EntityCache(this);
|
this.entityCache = new EntityCache(this);
|
||||||
@ -169,8 +168,9 @@ public class GeyserSession implements Player {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void packetReceived(PacketReceivedEvent event) {
|
public void packetReceived(PacketReceivedEvent event) {
|
||||||
if (!closed)
|
if (!closed) {
|
||||||
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -297,5 +297,7 @@ public class GeyserSession implements Player {
|
|||||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||||
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||||
upstream.sendPacket(playStatusPacket);
|
upstream.sendPacket(playStatusPacket);
|
||||||
|
|
||||||
|
upstream.setFrozen(true); // will freeze until the client decides it is ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.geysermc.connector.network.session;
|
||||||
|
|
||||||
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.geysermc.api.Geyser;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UpstreamSession {
|
||||||
|
@Getter private final BedrockServerSession session;
|
||||||
|
private Queue<BedrockPacket> packets = new ConcurrentLinkedQueue<>();
|
||||||
|
@Getter private boolean frozen = false;
|
||||||
|
|
||||||
|
public void sendPacket(@NonNull BedrockPacket packet) {
|
||||||
|
if (frozen || !packets.isEmpty()) {
|
||||||
|
packets.add(packet);
|
||||||
|
} else {
|
||||||
|
session.sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendPacketImmediately(@NonNull BedrockPacket packet) {
|
||||||
|
session.sendPacketImmediately(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrozen(boolean frozen) {
|
||||||
|
if (this.frozen != frozen) {
|
||||||
|
this.frozen = frozen;
|
||||||
|
|
||||||
|
if (!frozen) {
|
||||||
|
Geyser.getGeneralThreadPool().execute(() -> {
|
||||||
|
BedrockPacket packet;
|
||||||
|
while ((packet = packets.poll()) != null) {
|
||||||
|
session.sendPacket(packet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect(String reason) {
|
||||||
|
session.disconnect(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return session.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getAddress() {
|
||||||
|
return session.getAddress();
|
||||||
|
}
|
||||||
|
}
|
@ -62,17 +62,18 @@ public class EntityCache {
|
|||||||
entity.spawnEntity(session);
|
entity.spawnEntity(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEntity(Entity entity) {
|
public boolean removeEntity(Entity entity, boolean force) {
|
||||||
if (entity == null || !entity.isValid()) return;
|
if (entity != null && entity.isValid() && (force || entity.despawnEntity(session))) {
|
||||||
|
Long geyserId = entityIdTranslations.remove(entity.getEntityId());
|
||||||
Long geyserId = entityIdTranslations.remove(entity.getEntityId());
|
if (geyserId != null) {
|
||||||
if (geyserId != null) {
|
entities.remove(geyserId);
|
||||||
entities.remove(geyserId);
|
if (entity.is(PlayerEntity.class)) {
|
||||||
if (entity.is(PlayerEntity.class)) {
|
playerEntities.remove(entity.as(PlayerEntity.class).getUuid());
|
||||||
playerEntities.remove(entity.as(PlayerEntity.class).getUuid());
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
entity.despawnEntity(session);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity getEntityByGeyserId(long geyserId) {
|
public Entity getEntityByGeyserId(long geyserId) {
|
||||||
|
@ -48,13 +48,16 @@ public class Registry<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||||
try {
|
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||||
if (MAP.containsKey(clazz)) {
|
try {
|
||||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
if (MAP.containsKey(clazz)) {
|
||||||
return true;
|
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
GeyserLogger.DEFAULT.error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||||
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
} catch (NullPointerException ex) {
|
|
||||||
GeyserLogger.DEFAULT.error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -146,10 +146,11 @@ public class TranslatorsInit {
|
|||||||
|
|
||||||
Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
|
Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
|
||||||
Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator());
|
Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator());
|
||||||
Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
|
|
||||||
Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
|
Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
|
||||||
Registry.registerBedrock(PlayerActionPacket.class, new BedrockActionTranslator());
|
|
||||||
Registry.registerBedrock(MovePlayerPacket.class, new BedrockMovePlayerTranslator());
|
Registry.registerBedrock(MovePlayerPacket.class, new BedrockMovePlayerTranslator());
|
||||||
|
Registry.registerBedrock(PlayerActionPacket.class, new BedrockActionTranslator());
|
||||||
|
Registry.registerBedrock(SetLocalPlayerAsInitializedPacket.class, new BedrockPlayerInitialized());
|
||||||
|
Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
|
||||||
|
|
||||||
itemTranslator = new ItemTranslator();
|
itemTranslator = new ItemTranslator();
|
||||||
blockTranslator = new BlockTranslator();
|
blockTranslator = new BlockTranslator();
|
||||||
|
@ -53,9 +53,10 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
|
|
||||||
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
|
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
|
||||||
packet.isOnGround(), packet.getPosition().getX(), Math.ceil(javaY * 2) / 2,
|
packet.isOnGround(), packet.getPosition().getX(), Math.ceil(javaY * 2) / 2,
|
||||||
packet.getPosition().getZ(), packet.getRotation().getX(), packet.getRotation().getY());
|
packet.getPosition().getZ(), packet.getRotation().getY(), packet.getRotation().getX()
|
||||||
|
);
|
||||||
|
|
||||||
entity.moveAbsolute(packet.getPosition().sub(0, javaY, 0), packet.getRotation());
|
entity.moveAbsolute(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0), packet.getRotation());
|
||||||
|
|
||||||
boolean colliding = false;
|
boolean colliding = false;
|
||||||
Position position = new Position((int) packet.getPosition().getX(),
|
Position position = new Position((int) packet.getPosition().getX(),
|
||||||
@ -84,7 +85,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
if (zRange < 0)
|
if (zRange < 0)
|
||||||
zRange = -zRange;
|
zRange = -zRange;
|
||||||
|
|
||||||
if (xRange > 10 || yRange > 10 || zRange > 10) {
|
if ((xRange + yRange + zRange) > 100) {
|
||||||
session.getConnector().getLogger().warning(session.getName() + " moved too quickly." +
|
session.getConnector().getLogger().warning(session.getName() + " moved too quickly." +
|
||||||
" current position: " + currentPosition + ", new position: " + newPosition);
|
" current position: " + currentPosition + ", new position: " + newPosition);
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
movePlayerPacket.setPosition(entity.getPosition());
|
movePlayerPacket.setPosition(entity.getPosition());
|
||||||
movePlayerPacket.setRotation(entity.getRotation());
|
movePlayerPacket.setRotation(entity.getBedrockRotation());
|
||||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||||
movePlayerPacket.setOnGround(true);
|
movePlayerPacket.setOnGround(true);
|
||||||
entity.setMovePending(false);
|
entity.setMovePending(false);
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.geysermc.connector.network.translators.bedrock;
|
||||||
|
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
|
||||||
|
public class BedrockPlayerInitialized extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
|
||||||
|
@Override
|
||||||
|
public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession session) {
|
||||||
|
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
|
||||||
|
session.getUpstream().setFrozen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ public class BlockTranslator {
|
|||||||
public BedrockItem getBedrockBlock(BlockState state) {
|
public BedrockItem getBedrockBlock(BlockState state) {
|
||||||
BedrockItem bedrockItem = Remapper.BLOCK_REMAPPER.convertToBedrockB(new ItemStack(state.getId()));
|
BedrockItem bedrockItem = Remapper.BLOCK_REMAPPER.convertToBedrockB(new ItemStack(state.getId()));
|
||||||
if (bedrockItem == null) {
|
if (bedrockItem == null) {
|
||||||
GeyserLogger.DEFAULT.debug("Missing mapping for java block " + state.getId() + "/nPlease report this to Geyser.");
|
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.DIRT; // so we can walk and not getting stuck x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
package org.geysermc.connector.network.translators.inventory;
|
package org.geysermc.connector.network.translators.inventory;
|
||||||
|
|
||||||
import com.flowpowered.math.vector.Vector3i;
|
import com.flowpowered.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||||
@ -34,7 +33,6 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
|||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.TranslatorsInit;
|
import org.geysermc.connector.network.translators.TranslatorsInit;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
|
||||||
|
|
||||||
public class GenericInventoryTranslator extends InventoryTranslator {
|
public class GenericInventoryTranslator extends InventoryTranslator {
|
||||||
|
|
||||||
@ -54,29 +52,21 @@ public class GenericInventoryTranslator extends InventoryTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||||
ContainerId containerId = InventoryUtils.getContainerId(inventory.getId());
|
|
||||||
if (containerId == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ItemData[] bedrockItems = new ItemData[inventory.getItems().length];
|
ItemData[] bedrockItems = new ItemData[inventory.getItems().length];
|
||||||
for (int i = 0; i < bedrockItems.length; i++) {
|
for (int i = 0; i < bedrockItems.length; i++) {
|
||||||
bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||||
contentPacket.setContainerId(containerId);
|
contentPacket.setContainerId(inventory.getId());
|
||||||
contentPacket.setContents(bedrockItems);
|
contentPacket.setContents(bedrockItems);
|
||||||
session.getUpstream().sendPacket(contentPacket);
|
session.getUpstream().sendPacket(contentPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||||
ContainerId containerId = InventoryUtils.getContainerId(inventory.getId());
|
|
||||||
if (containerId == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(containerId);
|
slotPacket.setContainerId(inventory.getId());
|
||||||
slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot]));
|
slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot]));
|
||||||
slotPacket.setInventorySlot(slot);
|
slotPacket.setInventorySlot(slot);
|
||||||
session.getUpstream().sendPacket(slotPacket);
|
session.getUpstream().sendPacket(slotPacket);
|
||||||
|
@ -38,7 +38,7 @@ public class JavaEntityDestroyTranslator extends PacketTranslator<ServerEntityDe
|
|||||||
Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
|
Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||||
|
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
session.getEntityCache().removeEntity(entity);
|
session.getEntityCache().removeEntity(entity, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityH
|
|||||||
|
|
||||||
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
||||||
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
moveEntityAbsolutePacket.setRotation(entity.getRotation());
|
|
||||||
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
||||||
|
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
|
||||||
moveEntityAbsolutePacket.setOnGround(true);
|
moveEntityAbsolutePacket.setOnGround(true);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
||||||
|
@ -41,13 +41,13 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
|
|||||||
}
|
}
|
||||||
if (entity == null) return;
|
if (entity == null) return;
|
||||||
|
|
||||||
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
|
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getYaw(), packet.getPitch());
|
||||||
|
|
||||||
if (entity.isMovePending()) {
|
if (entity.isMovePending()) {
|
||||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
moveEntityPacket.setPosition(entity.getPosition());
|
moveEntityPacket.setPosition(entity.getPosition());
|
||||||
moveEntityPacket.setRotation(entity.getRotation());
|
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||||
moveEntityPacket.setTeleported(false);
|
moveEntityPacket.setTeleported(false);
|
||||||
entity.setMovePending(false);
|
entity.setMovePending(false);
|
||||||
|
@ -41,13 +41,13 @@ public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityP
|
|||||||
}
|
}
|
||||||
if (entity == null) return;
|
if (entity == null) return;
|
||||||
|
|
||||||
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
|
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), entity.getRotation());
|
||||||
|
|
||||||
if (entity.isMovePending()) {
|
if (entity.isMovePending()) {
|
||||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
moveEntityPacket.setPosition(entity.getPosition());
|
moveEntityPacket.setPosition(entity.getPosition());
|
||||||
moveEntityPacket.setRotation(entity.getRotation());
|
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||||
moveEntityPacket.setTeleported(false);
|
moveEntityPacket.setTeleported(false);
|
||||||
entity.setMovePending(false);
|
entity.setMovePending(false);
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.entity;
|
package org.geysermc.connector.network.translators.java.entity;
|
||||||
|
|
||||||
import com.flowpowered.math.vector.Vector3f;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
@ -42,15 +41,13 @@ public class JavaEntityRotationTranslator extends PacketTranslator<ServerEntityR
|
|||||||
}
|
}
|
||||||
if (entity == null) return;
|
if (entity == null) return;
|
||||||
|
|
||||||
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getPitch(), packet.getYaw());
|
entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getYaw(), packet.getPitch());
|
||||||
|
|
||||||
Vector3f rotation = new Vector3f(entity.getRotation().getX() / (360d / 256d), entity.getRotation().getY() / (360d / 256d),
|
|
||||||
entity.getRotation().getZ() / (360d / 256d));
|
|
||||||
if (entity.isMovePending()) {
|
if (entity.isMovePending()) {
|
||||||
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
||||||
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
||||||
moveEntityAbsolutePacket.setRotation(rotation);
|
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
|
||||||
entity.setMovePending(false);
|
entity.setMovePending(false);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
||||||
|
@ -42,13 +42,13 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
|
|||||||
}
|
}
|
||||||
if (entity == null) return;
|
if (entity == null) return;
|
||||||
|
|
||||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
|
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||||
|
|
||||||
if (entity.isMovePending()) {
|
if (entity.isMovePending()) {
|
||||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
moveEntityPacket.setPosition(entity.getPosition());
|
moveEntityPacket.setPosition(entity.getPosition());
|
||||||
moveEntityPacket.setRotation(entity.getRotation());
|
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||||
moveEntityPacket.setTeleported(true);
|
moveEntityPacket.setTeleported(true);
|
||||||
entity.setMovePending(false);
|
entity.setMovePending(false);
|
||||||
|
@ -48,7 +48,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!session.isSpawned()) {
|
if (!session.isSpawned()) {
|
||||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
|
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||||
|
|
||||||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||||
entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
|
entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
@ -70,7 +70,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
|
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||||
|
|
||||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
|
@ -5,15 +5,12 @@ import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
|
|||||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
|
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
import org.geysermc.connector.entity.PlayerEntity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.utils.ProvidedSkin;
|
import org.geysermc.connector.utils.SkinProvider;
|
||||||
|
|
||||||
public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayerListEntryPacket> {
|
public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayerListEntryPacket> {
|
||||||
private static byte[] providedSkin = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) {
|
public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) {
|
||||||
if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return;
|
if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return;
|
||||||
@ -25,26 +22,27 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
|
|||||||
PlayerListPacket.Entry entry1 = new PlayerListPacket.Entry(entry.getProfile().getId());
|
PlayerListPacket.Entry entry1 = new PlayerListPacket.Entry(entry.getProfile().getId());
|
||||||
|
|
||||||
if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) {
|
if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) {
|
||||||
if (session.getPlayerEntity().getUuid().equals(entry.getProfile().getId())) continue;
|
boolean self = session.getPlayerEntity().getUuid().equals(entry.getProfile().getId());
|
||||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
|
||||||
|
|
||||||
SetLocalPlayerAsInitializedPacket initPacket = new SetLocalPlayerAsInitializedPacket();
|
PlayerEntity playerEntity = session.getPlayerEntity();
|
||||||
initPacket.setRuntimeEntityId(geyserId);
|
if (!self) {
|
||||||
session.getUpstream().sendPacket(initPacket);
|
playerEntity = new PlayerEntity(
|
||||||
|
entry.getProfile(),
|
||||||
|
-1,
|
||||||
|
session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
Vector3f.ZERO,
|
||||||
|
Vector3f.ZERO,
|
||||||
|
Vector3f.ZERO
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
session.getEntityCache().addPlayerEntity(new PlayerEntity(
|
session.getEntityCache().addPlayerEntity(playerEntity);
|
||||||
entry.getProfile(),
|
playerEntity.setPlayerList(true);
|
||||||
-1,
|
|
||||||
geyserId,
|
|
||||||
Vector3f.ZERO,
|
|
||||||
Vector3f.ZERO,
|
|
||||||
Vector3f.ZERO
|
|
||||||
));
|
|
||||||
|
|
||||||
entry1.setName(entry.getProfile().getName());
|
entry1.setName(entry.getProfile().getName());
|
||||||
entry1.setEntityId(geyserId);
|
entry1.setEntityId(playerEntity.getGeyserId());
|
||||||
entry1.setSkinId(entry.getProfile().getIdAsString());
|
entry1.setSkinId(entry.getProfile().getIdAsString());
|
||||||
entry1.setSkinData(providedSkin);
|
entry1.setSkinData(SkinProvider.STEVE_SKIN);
|
||||||
entry1.setCapeData(new byte[0]);
|
entry1.setCapeData(new byte[0]);
|
||||||
entry1.setGeometryName("geometry.humanoid");
|
entry1.setGeometryName("geometry.humanoid");
|
||||||
entry1.setGeometryData("");
|
entry1.setGeometryData("");
|
||||||
@ -52,9 +50,11 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
|
|||||||
entry1.setPlatformChatId("");
|
entry1.setPlatformChatId("");
|
||||||
} else {
|
} else {
|
||||||
PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
|
PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
|
||||||
if (entity != null && entity.isValid()) { // we'll despawn it manually ;-)
|
if (entity != null && entity.isValid()) {
|
||||||
session.getEntityCache().removeEntity(entity);
|
// remove from tablist but player entity is still there
|
||||||
} else { // just remove it from caching
|
entity.setPlayerList(false);
|
||||||
|
} else {
|
||||||
|
// just remove it from caching
|
||||||
session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
|
session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,24 +27,22 @@ package org.geysermc.connector.network.translators.java.entity.spawn;
|
|||||||
|
|
||||||
import com.flowpowered.math.vector.Vector3f;
|
import com.flowpowered.math.vector.Vector3f;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
|
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.ExpOrbEntity;
|
import org.geysermc.connector.entity.ExpOrbEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.utils.EntityUtils;
|
|
||||||
|
|
||||||
public class JavaSpawnExpOrbTranslator extends PacketTranslator<ServerSpawnExpOrbPacket> {
|
public class JavaSpawnExpOrbTranslator extends PacketTranslator<ServerSpawnExpOrbPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerSpawnExpOrbPacket packet, GeyserSession session) {
|
public void translate(ServerSpawnExpOrbPacket packet, GeyserSession session) {
|
||||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||||
Entity entity = new ExpOrbEntity(packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
|
||||||
EntityType.EXPERIENCE_ORB, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
|
|
||||||
|
|
||||||
if (entity == null)
|
Entity entity = new ExpOrbEntity(
|
||||||
return;
|
packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
EntityType.EXPERIENCE_ORB, position, Vector3f.ZERO, Vector3f.ZERO
|
||||||
|
);
|
||||||
|
|
||||||
session.getEntityCache().spawnEntity(entity);
|
session.getEntityCache().spawnEntity(entity);
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,10 @@ public class JavaSpawnGlobalEntityTranslator extends PacketTranslator<ServerSpaw
|
|||||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||||
|
|
||||||
// Currently GlobalEntityType only has a lightning bolt
|
// Currently GlobalEntityType only has a lightning bolt
|
||||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
Entity entity = new Entity(
|
||||||
EntityType.LIGHTNING_BOLT, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
|
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
EntityType.LIGHTNING_BOLT, position, Vector3f.ZERO, Vector3f.ZERO
|
||||||
if (entity == null)
|
);
|
||||||
return;
|
|
||||||
|
|
||||||
session.getEntityCache().spawnEntity(entity);
|
session.getEntityCache().spawnEntity(entity);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacke
|
|||||||
public void translate(ServerSpawnMobPacket packet, GeyserSession session) {
|
public void translate(ServerSpawnMobPacket packet, GeyserSession session) {
|
||||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||||
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getHeadYaw());
|
Vector3f rotation = new Vector3f(packet.getYaw(), packet.getPitch(), packet.getHeadYaw());
|
||||||
|
|
||||||
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
@ -48,8 +48,10 @@ public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacke
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
Entity entity = new Entity(
|
||||||
type, position, motion, rotation);
|
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
type, position, motion, rotation
|
||||||
|
);
|
||||||
|
|
||||||
session.getEntityCache().spawnEntity(entity);
|
session.getEntityCache().spawnEntity(entity);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjec
|
|||||||
|
|
||||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||||
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
|
Vector3f rotation = new Vector3f(packet.getYaw(), packet.getPitch(), 0);
|
||||||
|
|
||||||
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
@ -52,11 +52,10 @@ public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjec
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
Entity entity = new Entity(
|
||||||
type, position, motion, rotation);
|
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
type, position, motion, rotation
|
||||||
if (entity == null)
|
);
|
||||||
return;
|
|
||||||
|
|
||||||
session.getEntityCache().spawnEntity(entity);
|
session.getEntityCache().spawnEntity(entity);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
|||||||
import org.apache.commons.codec.Charsets;
|
import org.apache.commons.codec.Charsets;
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.utils.SkinProvider;
|
import org.geysermc.connector.utils.SkinProvider;
|
||||||
@ -43,8 +44,8 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
|
public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
|
||||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
Vector3f position = new Vector3f(packet.getX(), packet.getY() - EntityType.PLAYER.getOffset(), packet.getZ());
|
||||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getYaw());
|
Vector3f rotation = new Vector3f(packet.getYaw(), packet.getPitch(), packet.getYaw());
|
||||||
|
|
||||||
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUUID());
|
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUUID());
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
@ -63,7 +64,7 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
|||||||
Geyser.getGeneralThreadPool().execute(() -> {
|
Geyser.getGeneralThreadPool().execute(() -> {
|
||||||
GameProfile.Property skinProperty = entity.getProfile().getProperty("textures");
|
GameProfile.Property skinProperty = entity.getProfile().getProperty("textures");
|
||||||
|
|
||||||
JsonObject skinObject = SkinProvider.getGson().fromJson(new String(Base64.getDecoder().decode(skinProperty.getValue()), Charsets.UTF_8), JsonObject.class);
|
JsonObject skinObject = SkinProvider.GSON.fromJson(new String(Base64.getDecoder().decode(skinProperty.getValue()), Charsets.UTF_8), JsonObject.class);
|
||||||
JsonObject textures = skinObject.getAsJsonObject("textures");
|
JsonObject textures = skinObject.getAsJsonObject("textures");
|
||||||
|
|
||||||
JsonObject skinTexture = textures.getAsJsonObject("SKIN");
|
JsonObject skinTexture = textures.getAsJsonObject("SKIN");
|
||||||
@ -82,8 +83,14 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
|||||||
SkinProvider.Skin skin = skinAndCape.getSkin();
|
SkinProvider.Skin skin = skinAndCape.getSkin();
|
||||||
SkinProvider.Cape cape = skinAndCape.getCape();
|
SkinProvider.Cape cape = skinAndCape.getCape();
|
||||||
|
|
||||||
|
if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) {
|
||||||
|
cape = SkinProvider.getOrDefault(SkinProvider.requestAndHandleUnofficialCape(
|
||||||
|
cape, entity.getUuid(),
|
||||||
|
entity.getUsername(), false
|
||||||
|
), SkinProvider.EMPTY_CAPE, SkinProvider.UnofficalCape.VALUES.length * 3);
|
||||||
|
}
|
||||||
|
|
||||||
if (entity.getLastSkinUpdate() < skin.getRequestedOn()) {
|
if (entity.getLastSkinUpdate() < skin.getRequestedOn()) {
|
||||||
Geyser.getLogger().debug("Received Skin for " + entity.getUuid() + ", updating player..");
|
|
||||||
entity.setLastSkinUpdate(skin.getRequestedOn());
|
entity.setLastSkinUpdate(skin.getRequestedOn());
|
||||||
|
|
||||||
PlayerListPacket.Entry updatedEntry = new PlayerListPacket.Entry(skin.getSkinOwner());
|
PlayerListPacket.Entry updatedEntry = new PlayerListPacket.Entry(skin.getSkinOwner());
|
||||||
|
@ -110,13 +110,4 @@ public class InventoryUtils {
|
|||||||
items[packet.getSlot()] = packet.getItem();
|
items[packet.getSlot()] = packet.getItem();
|
||||||
translator.updateSlot(session, openInventory, packet.getSlot());
|
translator.updateSlot(session, openInventory, packet.getSlot());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ContainerId getContainerId(int id) {
|
|
||||||
for (ContainerId value : ContainerId.values()) {
|
|
||||||
if (value.id() == id)
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ public class LoginEncryptionUtils {
|
|||||||
|
|
||||||
byte[] token = EncryptionUtils.generateRandomToken();
|
byte[] token = EncryptionUtils.generateRandomToken();
|
||||||
SecretKey encryptionKey = EncryptionUtils.getSecretKey(serverKeyPair.getPrivate(), key, token);
|
SecretKey encryptionKey = EncryptionUtils.getSecretKey(serverKeyPair.getPrivate(), key, token);
|
||||||
session.getUpstream().enableEncryption(encryptionKey);
|
session.getUpstream().getSession().enableEncryption(encryptionKey);
|
||||||
|
|
||||||
ServerToClientHandshakePacket packet = new ServerToClientHandshakePacket();
|
ServerToClientHandshakePacket packet = new ServerToClientHandshakePacket();
|
||||||
packet.setJwt(EncryptionUtils.createHandshakeJwt(serverKeyPair, token).serialize());
|
packet.setJwt(EncryptionUtils.createHandshakeJwt(serverKeyPair, token).serialize());
|
||||||
|
@ -5,8 +5,10 @@ import com.google.gson.GsonBuilder;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -16,19 +18,21 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
public class SkinProvider {
|
public class SkinProvider {
|
||||||
private static final ExecutorService executorService = Executors.newFixedThreadPool(14);
|
public static final Gson GSON = new GsonBuilder().create();
|
||||||
@Getter private static final Gson gson = new GsonBuilder().create();
|
public static final boolean ALLOW_THIRD_PARTY_CAPES = ((GeyserConnector)Geyser.getConnector()).getConfig().isAllowThirdPartyCapes();
|
||||||
|
private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14);
|
||||||
private static Map<UUID, Skin> cachedSkins = new ConcurrentHashMap<>();
|
|
||||||
private static Map<String, Cape> cachedCapes = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public static final Skin EMPTY_SKIN = new Skin(-1, "");
|
public static final Skin EMPTY_SKIN = new Skin(-1, "");
|
||||||
public static final Cape EMPTY_CAPE = new Cape("", new byte[0]);
|
public static final byte[] STEVE_SKIN = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin();
|
||||||
private static final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes
|
private static Map<UUID, Skin> cachedSkins = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private static Map<UUID, CompletableFuture<Skin>> requestedSkins = new ConcurrentHashMap<>();
|
private static Map<UUID, CompletableFuture<Skin>> requestedSkins = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static final Cape EMPTY_CAPE = new Cape("", new byte[0], -1, true);
|
||||||
|
private static Map<String, Cape> cachedCapes = new ConcurrentHashMap<>();
|
||||||
private static Map<String, CompletableFuture<Cape>> requestedCapes = new ConcurrentHashMap<>();
|
private static Map<String, CompletableFuture<Cape>> requestedCapes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes
|
||||||
|
|
||||||
public static boolean hasSkinCached(UUID uuid) {
|
public static boolean hasSkinCached(UUID uuid) {
|
||||||
return cachedSkins.containsKey(uuid);
|
return cachedSkins.containsKey(uuid);
|
||||||
}
|
}
|
||||||
@ -54,9 +58,9 @@ public class SkinProvider {
|
|||||||
getOrDefault(requestAndHandleCape(capeUrl, false), EMPTY_CAPE, 5)
|
getOrDefault(requestAndHandleCape(capeUrl, false), EMPTY_CAPE, 5)
|
||||||
);
|
);
|
||||||
|
|
||||||
Geyser.getLogger().info("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId);
|
Geyser.getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId);
|
||||||
return skinAndCape;
|
return skinAndCape;
|
||||||
}, executorService);
|
}, EXECUTOR_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<Skin> requestAndHandleSkin(UUID playerId, String textureUrl, boolean newThread) {
|
public static CompletableFuture<Skin> requestAndHandleSkin(UUID playerId, String textureUrl, boolean newThread) {
|
||||||
@ -70,7 +74,7 @@ public class SkinProvider {
|
|||||||
|
|
||||||
CompletableFuture<Skin> future;
|
CompletableFuture<Skin> future;
|
||||||
if (newThread) {
|
if (newThread) {
|
||||||
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), executorService)
|
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE)
|
||||||
.whenCompleteAsync((skin, throwable) -> {
|
.whenCompleteAsync((skin, throwable) -> {
|
||||||
if (!cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getTextureUrl().equals(textureUrl)) {
|
if (!cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getTextureUrl().equals(textureUrl)) {
|
||||||
skin.updated = true;
|
skin.updated = true;
|
||||||
@ -91,14 +95,17 @@ public class SkinProvider {
|
|||||||
if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE);
|
if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE);
|
||||||
if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested
|
if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested
|
||||||
|
|
||||||
if (cachedCapes.containsKey(capeUrl)) {
|
boolean officialCape = capeUrl.startsWith("https://textures.minecraft.net");
|
||||||
// no need to update the cache, capes are static :D
|
boolean validCache = (System.currentTimeMillis() - CACHE_INTERVAL) < cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE).getRequestedOn();
|
||||||
|
|
||||||
|
if ((cachedCapes.containsKey(capeUrl) && officialCape) || validCache) {
|
||||||
|
// the cape is an official cape (static) or the cape doesn't need a update yet
|
||||||
return CompletableFuture.completedFuture(cachedCapes.get(capeUrl));
|
return CompletableFuture.completedFuture(cachedCapes.get(capeUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletableFuture<Cape> future;
|
CompletableFuture<Cape> future;
|
||||||
if (newThread) {
|
if (newThread) {
|
||||||
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl), executorService)
|
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl), EXECUTOR_SERVICE)
|
||||||
.whenCompleteAsync((cape, throwable) -> {
|
.whenCompleteAsync((cape, throwable) -> {
|
||||||
cachedCapes.put(capeUrl, cape);
|
cachedCapes.put(capeUrl, cape);
|
||||||
requestedCapes.remove(capeUrl);
|
requestedCapes.remove(capeUrl);
|
||||||
@ -112,26 +119,57 @@ public class SkinProvider {
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture<Cape> requestAndHandleUnofficialCape(Cape officialCape, UUID playerId,
|
||||||
|
String username, boolean newThread) {
|
||||||
|
if (officialCape.isFailed() && ALLOW_THIRD_PARTY_CAPES) {
|
||||||
|
for (UnofficalCape cape : UnofficalCape.VALUES) {
|
||||||
|
Cape cape1 = getOrDefault(
|
||||||
|
requestAndHandleCape(cape.getUrlFor(playerId, username), newThread),
|
||||||
|
EMPTY_CAPE, 4
|
||||||
|
);
|
||||||
|
if (!cape1.isFailed()) {
|
||||||
|
return CompletableFuture.completedFuture(cape1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CompletableFuture.completedFuture(officialCape);
|
||||||
|
}
|
||||||
|
|
||||||
private static Skin supplySkin(UUID uuid, String textureUrl) {
|
private static Skin supplySkin(UUID uuid, String textureUrl) {
|
||||||
byte[] skin = EMPTY_SKIN.getSkinData();
|
byte[] skin = EMPTY_SKIN.getSkinData();
|
||||||
try {
|
try {
|
||||||
skin = requestImage(textureUrl);
|
skin = requestImage(textureUrl, false);
|
||||||
} catch (Exception ignored) {} // just ignore I guess
|
} catch (Exception ignored) {} // just ignore I guess
|
||||||
return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false);
|
return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Cape supplyCape(String capeUrl) {
|
private static Cape supplyCape(String capeUrl) {
|
||||||
byte[] cape = EMPTY_CAPE.getCapeData();
|
byte[] cape = new byte[0];
|
||||||
try {
|
try {
|
||||||
cape = requestImage(capeUrl);
|
cape = requestImage(capeUrl, true);
|
||||||
} catch (Exception ignored) {} // just ignore I guess
|
} catch (Exception ignored) {} // just ignore I guess
|
||||||
return new Cape(capeUrl, cape);
|
|
||||||
|
return new Cape(
|
||||||
|
capeUrl,
|
||||||
|
cape.length > 0 ? cape : EMPTY_CAPE.getCapeData(),
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
cape.length == 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] requestImage(String imageUrl) throws Exception {
|
private static byte[] requestImage(String imageUrl, boolean cape) throws Exception {
|
||||||
BufferedImage image = ImageIO.read(new URL(imageUrl));
|
BufferedImage image = ImageIO.read(new URL(imageUrl));
|
||||||
Geyser.getLogger().debug("Downloaded " + imageUrl);
|
Geyser.getLogger().debug("Downloaded " + imageUrl);
|
||||||
|
|
||||||
|
if (cape) {
|
||||||
|
BufferedImage newImage = new BufferedImage(64, 32, BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
|
Graphics g = newImage.createGraphics();
|
||||||
|
g.drawImage(image, 0, 0, 64, 32, null);
|
||||||
|
g.dispose();
|
||||||
|
image = newImage;
|
||||||
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4);
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4);
|
||||||
try {
|
try {
|
||||||
for (int y = 0; y < image.getHeight(); y++) {
|
for (int y = 0; y < image.getHeight(); y++) {
|
||||||
@ -152,6 +190,13 @@ public class SkinProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T getOrDefault(CompletableFuture<T> future, T defaultValue, int timeoutInSeconds) {
|
||||||
|
try {
|
||||||
|
return future.get(timeoutInSeconds, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public static class SkinAndCape {
|
public static class SkinAndCape {
|
||||||
@ -164,7 +209,7 @@ public class SkinProvider {
|
|||||||
public static class Skin {
|
public static class Skin {
|
||||||
private UUID skinOwner;
|
private UUID skinOwner;
|
||||||
private String textureUrl;
|
private String textureUrl;
|
||||||
private byte[] skinData = new byte[0];
|
private byte[] skinData = STEVE_SKIN;
|
||||||
private long requestedOn;
|
private long requestedOn;
|
||||||
private boolean updated;
|
private boolean updated;
|
||||||
|
|
||||||
@ -179,12 +224,45 @@ public class SkinProvider {
|
|||||||
public static class Cape {
|
public static class Cape {
|
||||||
private String textureUrl;
|
private String textureUrl;
|
||||||
private byte[] capeData;
|
private byte[] capeData;
|
||||||
|
private long requestedOn;
|
||||||
|
private boolean failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T getOrDefault(CompletableFuture<T> future, T defaultValue, int timeoutInSeconds) {
|
/*
|
||||||
try {
|
* Sorted by 'priority'
|
||||||
return future.get(timeoutInSeconds, TimeUnit.SECONDS);
|
*/
|
||||||
} catch (Exception ignored) {}
|
@AllArgsConstructor
|
||||||
return defaultValue;
|
@Getter
|
||||||
|
public enum UnofficalCape {
|
||||||
|
OPTIFINE("http://s.optifine.net/capes/%s.png", CapeUrlType.USERNAME),
|
||||||
|
LABYMOD("http://capes.labymod.net/capes/%s.png", CapeUrlType.UUID_DASHED),
|
||||||
|
FIVEZIG("http://textures.5zig.net/2/%s", CapeUrlType.UUID),
|
||||||
|
MINECRAFTCAPES("https://www.minecraftcapes.co.uk/getCape/%s", CapeUrlType.UUID);
|
||||||
|
|
||||||
|
public static final UnofficalCape[] VALUES = values();
|
||||||
|
private String url;
|
||||||
|
private CapeUrlType type;
|
||||||
|
|
||||||
|
public String getUrlFor(String type) {
|
||||||
|
return String.format(url, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrlFor(UUID uuid, String username) {
|
||||||
|
return getUrlFor(toRequestedType(type, uuid, username));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toRequestedType(CapeUrlType type, UUID uuid, String username) {
|
||||||
|
switch (type) {
|
||||||
|
case UUID: return uuid.toString().replace("-", "");
|
||||||
|
case UUID_DASHED: return uuid.toString();
|
||||||
|
default: return username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CapeUrlType {
|
||||||
|
USERNAME,
|
||||||
|
UUID,
|
||||||
|
UUID_DASHED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,10 @@ debug-mode: false
|
|||||||
# Thread pool size
|
# Thread pool size
|
||||||
general-thread-pool: 32
|
general-thread-pool: 32
|
||||||
|
|
||||||
|
# Allow third party capes to be visible. Currently allowing:
|
||||||
|
# OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes
|
||||||
|
allow-third-party-capes: true
|
||||||
|
|
||||||
# bStats is a stat tracker that is entirely anonymous and tracks only basic information
|
# bStats is a stat tracker that is entirely anonymous and tracks only basic information
|
||||||
# about Geyser, such as how many people are online, how many servers are using Geyser,
|
# about Geyser, such as how many people are online, how many servers are using Geyser,
|
||||||
# what OS is being used, etc. You can learn more about bStats here: https://bstats.org/.
|
# what OS is being used, etc. You can learn more about bStats here: https://bstats.org/.
|
||||||
@ -58,7 +62,3 @@ metrics:
|
|||||||
enabled: true
|
enabled: true
|
||||||
# UUID of server, don't change!
|
# UUID of server, don't change!
|
||||||
uuid: generateduuid
|
uuid: generateduuid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren