forked from GeyserMC/Geyser
Merge pull request #41 from Tim203/master
Players spawn, skins and capes, scoreboard, bossbar, fixes and updated protocol lib
This commit is contained in:
commit
30d15707a6
66 changed files with 1471 additions and 1715 deletions
|
@ -75,7 +75,7 @@
|
|||
<dependency>
|
||||
<groupId>com.nukkitx.protocol</groupId>
|
||||
<artifactId>bedrock-v361</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.Map;
|
|||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Getter
|
||||
public class GeyserConfiguration {
|
||||
|
||||
private BedrockConfiguration bedrock;
|
||||
private RemoteConfiguration remote;
|
||||
|
||||
|
@ -52,5 +51,8 @@ public class GeyserConfiguration {
|
|||
@JsonProperty("general-thread-pool")
|
||||
private int generalThreadPool;
|
||||
|
||||
@JsonProperty("allow-third-party-capes")
|
||||
private boolean allowThirdPartyCapes;
|
||||
|
||||
private MetricInfo metrics;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
|
||||
package org.geysermc.connector.console;
|
||||
|
||||
import org.geysermc.api.ChatColor;
|
||||
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.logging.*;
|
||||
|
||||
|
@ -108,7 +109,7 @@ public class GeyserLogger implements org.geysermc.api.logger.Logger {
|
|||
@Override
|
||||
public void error(String message, Throwable error) {
|
||||
waitFor();
|
||||
System.out.println(printConsole(ChatColor.RED + message + "\n" + error.getMessage(), colored));
|
||||
System.out.println(printConsole(ChatColor.RED + message + "\n" + error, colored));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityDataDictionary;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
|
@ -49,7 +49,6 @@ import java.util.*;
|
|||
@Getter
|
||||
@Setter
|
||||
public class Entity {
|
||||
|
||||
protected long entityId;
|
||||
protected long geyserId;
|
||||
|
||||
|
@ -58,7 +57,9 @@ public class Entity {
|
|||
protected Vector3f position;
|
||||
protected Vector3f motion;
|
||||
|
||||
// 1 - pitch, 2 - yaw, 3 - roll (head yaw)
|
||||
/**
|
||||
* x = Yaw, y = Pitch, z = HeadYaw
|
||||
*/
|
||||
protected Vector3f rotation;
|
||||
|
||||
protected int scale = 1;
|
||||
|
@ -90,7 +91,7 @@ public class Entity {
|
|||
addEntityPacket.setUniqueEntityId(geyserId);
|
||||
addEntityPacket.setPosition(position);
|
||||
addEntityPacket.setMotion(motion);
|
||||
addEntityPacket.setRotation(rotation);
|
||||
addEntityPacket.setRotation(getBedrockRotation());
|
||||
addEntityPacket.setEntityType(entityType.getType());
|
||||
addEntityPacket.getMetadata().putAll(getMetadata());
|
||||
|
||||
|
@ -100,36 +101,37 @@ public class Entity {
|
|||
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.setUniqueEntityId(geyserId);
|
||||
session.getUpstream().sendPacket(removeEntityPacket);
|
||||
|
||||
valid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void moveRelative(double relX, double relY, double relZ, float pitch, float yaw) {
|
||||
moveRelative(relX, relY, relZ, new Vector3f(pitch, yaw, 0));
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch) {
|
||||
moveRelative(relX, relY, relZ, Vector3f.from(yaw, pitch, yaw));
|
||||
}
|
||||
|
||||
public void moveRelative(double relX, double relY, double relZ, Vector3f rotation) {
|
||||
if (relX == 0 && relY == 0 && relZ == 0 && position.getX() == 0 && position.getY() == 0)
|
||||
return;
|
||||
|
||||
this.rotation = rotation;
|
||||
this.position = new Vector3f(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||
setRotation(rotation);
|
||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||
this.movePending = true;
|
||||
}
|
||||
|
||||
public void moveAbsolute(Vector3f position, float pitch, float yaw) {
|
||||
moveAbsolute(position, new Vector3f(pitch, yaw, 0));
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch) {
|
||||
moveAbsolute(position, Vector3f.from(yaw, pitch, yaw));
|
||||
}
|
||||
|
||||
public void moveAbsolute(Vector3f position, Vector3f rotation) {
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
setPosition(position);
|
||||
setRotation(rotation);
|
||||
this.movePending = true;
|
||||
}
|
||||
|
||||
|
@ -138,14 +140,13 @@ public class Entity {
|
|||
flags.setFlag(EntityFlag.HAS_GRAVITY, true);
|
||||
flags.setFlag(EntityFlag.HAS_COLLISION, true);
|
||||
flags.setFlag(EntityFlag.CAN_SHOW_NAME, true);
|
||||
flags.setFlag(EntityFlag.NO_AI, false);
|
||||
flags.setFlag(EntityFlag.CAN_CLIMB, true);
|
||||
|
||||
EntityDataDictionary dictionary = new EntityDataDictionary();
|
||||
dictionary.put(EntityData.NAMETAG, "");
|
||||
dictionary.put(EntityData.ENTITY_AGE, 0);
|
||||
dictionary.put(EntityData.SCALE, 1f);
|
||||
dictionary.put(EntityData.MAX_AIR, (short) 400);
|
||||
dictionary.put(EntityData.AIR, (short) 0);
|
||||
dictionary.put(EntityData.LEAD_HOLDER_EID, -1L);
|
||||
dictionary.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||
dictionary.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
|
||||
dictionary.putFlags(flags);
|
||||
|
@ -185,4 +186,28 @@ public class Entity {
|
|||
ServerEntityPropertiesPacket entityPropertiesPacket = new ServerEntityPropertiesPacket((int) entityId, attributes);
|
||||
session.getDownstream().getSession().send(entityPropertiesPacket);
|
||||
}
|
||||
|
||||
public void setPosition(Vector3f position) {
|
||||
if (is(PlayerEntity.class)) {
|
||||
this.position = position.add(0, entityType.getOffset(), 0);
|
||||
return;
|
||||
}
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* x = Pitch, y = HeadYaw, z = Yaw
|
||||
*/
|
||||
public Vector3f getBedrockRotation() {
|
||||
return Vector3f.from(rotation.getY(), rotation.getZ(), rotation.getX());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Entity> I as(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this) ? (I) this : null;
|
||||
}
|
||||
|
||||
public <I extends Entity> boolean is(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
|
|
@ -25,35 +25,42 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter @Setter
|
||||
public class PlayerEntity extends Entity {
|
||||
private GameProfile profile;
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
|
||||
private ItemData hand;
|
||||
private long lastSkinUpdate = -1;
|
||||
private boolean playerList = true;
|
||||
|
||||
private ItemData helmet;
|
||||
private ItemData chestplate;
|
||||
private ItemData leggings;
|
||||
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) {
|
||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||
|
||||
profile = gameProfile;
|
||||
uuid = gameProfile.getId();
|
||||
username = gameProfile.getName();
|
||||
if (geyserId == 1) valid = true;
|
||||
}
|
||||
|
||||
// TODO: Break this into an EquippableEntity class
|
||||
|
@ -70,27 +77,62 @@ public class PlayerEntity extends Entity {
|
|||
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
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
if (geyserId == 1) return;
|
||||
|
||||
AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
|
||||
addPlayerPacket.setRuntimeEntityId(geyserId);
|
||||
addPlayerPacket.setUniqueEntityId(geyserId);
|
||||
addPlayerPacket.setUuid(uuid);
|
||||
addPlayerPacket.setUsername(username);
|
||||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.setRuntimeEntityId(geyserId);
|
||||
addPlayerPacket.setUniqueEntityId(geyserId);
|
||||
addPlayerPacket.setPosition(position);
|
||||
addPlayerPacket.setRotation(getBedrockRotation());
|
||||
addPlayerPacket.setMotion(motion);
|
||||
addPlayerPacket.setRotation(rotation);
|
||||
addPlayerPacket.setHand(hand);
|
||||
addPlayerPacket.getMetadata().putAll(getMetadata());
|
||||
addPlayerPacket.setPlayerFlags(0);
|
||||
addPlayerPacket.setCommandPermission(0);
|
||||
addPlayerPacket.setWorldFlags(0);
|
||||
addPlayerPacket.setPlayerPermission(0);
|
||||
addPlayerPacket.setCustomFlags(0);
|
||||
addPlayerPacket.setDeviceId("WIN10");
|
||||
addPlayerPacket.setDeviceId("");
|
||||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.getMetadata().putAll(getMetadata());
|
||||
|
||||
valid = true;
|
||||
session.getUpstream().sendPacket(addPlayerPacket);
|
||||
}
|
||||
|
||||
public void sendPlayer(GeyserSession session) {
|
||||
if (getLastSkinUpdate() == -1) {
|
||||
if (playerList) {
|
||||
PlayerListPacket playerList = new PlayerListPacket();
|
||||
playerList.setType(PlayerListPacket.Type.ADD);
|
||||
playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId));
|
||||
session.getUpstream().sendPacket(playerList);
|
||||
}
|
||||
}
|
||||
|
||||
if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) {
|
||||
session.getEntityCache().spawnEntity(this);
|
||||
} else {
|
||||
spawnEntity(session);
|
||||
}
|
||||
|
||||
if (!playerList) {
|
||||
// remove from playerlist if player isn't on playerlist
|
||||
Geyser.getGeneralThreadPool().execute(() -> {
|
||||
PlayerListPacket playerList = new PlayerListPacket();
|
||||
playerList.setType(PlayerListPacket.Type.REMOVE);
|
||||
playerList.getEntries().add(new PlayerListPacket.Entry(uuid));
|
||||
session.getUpstream().sendPacket(playerList);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
private boolean translateAndDefault(BedrockPacket packet) {
|
||||
Registry.BEDROCK.translate(packet.getClass(), packet, session);
|
||||
return defaultHandler(packet);
|
||||
return Registry.BEDROCK.translate(packet.getClass(), packet, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +65,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public boolean handle(ResourcePackClientResponsePacket textPacket) {
|
||||
connector.getLogger().debug("Handled " + textPacket.getClass().getSimpleName());
|
||||
switch (textPacket.getStatus()) {
|
||||
case COMPLETED:
|
||||
session.connect(connector.getRemoteServer());
|
||||
|
@ -88,7 +86,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public boolean handle(ModalFormResponsePacket packet) {
|
||||
connector.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName());
|
||||
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormData());
|
||||
}
|
||||
|
||||
|
@ -111,7 +108,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public boolean handle(MovePlayerPacket packet) {
|
||||
connector.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName());
|
||||
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())) {
|
||||
|
@ -119,7 +115,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
// else we were able to log the user in
|
||||
return true;
|
||||
} else if (session.isLoggingIn()) {
|
||||
}
|
||||
if (session.isLoggingIn()) {
|
||||
session.sendMessage("Please wait until you are logged in...");
|
||||
}
|
||||
|
||||
|
@ -127,27 +124,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(AnimatePacket packet) {
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(CommandRequestPacket packet) {
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(TextPacket packet) {
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MobEquipmentPacket packet) {
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PlayerActionPacket packet) {
|
||||
boolean defaultHandler(BedrockPacket packet) {
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,6 @@
|
|||
|
||||
package org.geysermc.connector.network.session;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2f;
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
|
@ -40,6 +36,10 @@ import com.github.steveice10.packetlib.event.session.PacketReceivedEvent;
|
|||
import com.github.steveice10.packetlib.event.session.SessionAdapter;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||
import com.nukkitx.math.vector.Vector2f;
|
||||
import com.nukkitx.math.vector.Vector2i;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
||||
import com.nukkitx.protocol.bedrock.data.GameRule;
|
||||
|
@ -54,7 +54,6 @@ import org.geysermc.api.session.AuthData;
|
|||
import org.geysermc.api.window.FormWindow;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.session.cache.*;
|
||||
import org.geysermc.connector.network.translators.Registry;
|
||||
|
@ -67,7 +66,7 @@ import java.util.UUID;
|
|||
public class GeyserSession implements Player {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
private final BedrockServerSession upstream;
|
||||
private final UpstreamSession upstream;
|
||||
private RemoteServer remoteServer;
|
||||
private Client downstream;
|
||||
private AuthData authenticationData;
|
||||
|
@ -102,7 +101,7 @@ public class GeyserSession implements Player {
|
|||
|
||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||
this.connector = connector;
|
||||
this.upstream = bedrockServerSession;
|
||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||
|
||||
this.chunkCache = new ChunkCache(this);
|
||||
this.entityCache = new EntityCache(this);
|
||||
|
@ -110,7 +109,7 @@ 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, 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, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO);
|
||||
this.inventory = new PlayerInventory();
|
||||
|
||||
this.javaPacketCache = new DataCache<>();
|
||||
|
@ -176,8 +175,9 @@ public class GeyserSession implements Player {
|
|||
|
||||
@Override
|
||||
public void packetReceived(PacketReceivedEvent event) {
|
||||
if (!closed)
|
||||
if (!closed) {
|
||||
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -257,15 +257,15 @@ public class GeyserSession implements Player {
|
|||
startGamePacket.setUniqueEntityId(playerEntity.getGeyserId());
|
||||
startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId());
|
||||
startGamePacket.setPlayerGamemode(0);
|
||||
startGamePacket.setPlayerPosition(new Vector3f(0, 69, 0));
|
||||
startGamePacket.setRotation(new Vector2f(1, 1));
|
||||
startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0));
|
||||
startGamePacket.setRotation(Vector2f.from(1, 1));
|
||||
|
||||
startGamePacket.setSeed(0);
|
||||
startGamePacket.setDimensionId(playerEntity.getDimension());
|
||||
startGamePacket.setGeneratorId(1);
|
||||
startGamePacket.setLevelGamemode(0);
|
||||
startGamePacket.setDifficulty(1);
|
||||
startGamePacket.setDefaultSpawn(new Vector3i(0, 0, 0));
|
||||
startGamePacket.setDefaultSpawn(Vector3i.ZERO);
|
||||
startGamePacket.setAcheivementsDisabled(true);
|
||||
startGamePacket.setTime(0);
|
||||
startGamePacket.setEduLevel(false);
|
||||
|
@ -297,7 +297,7 @@ public class GeyserSession implements Player {
|
|||
startGamePacket.setCurrentTick(0);
|
||||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE.copy());
|
||||
startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE.retainedDuplicate());
|
||||
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
||||
upstream.sendPacket(startGamePacket);
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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 lombok.Setter;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UpstreamSession {
|
||||
@Getter private final BedrockServerSession session;
|
||||
@Getter @Setter
|
||||
private boolean initialized = false;
|
||||
|
||||
public void sendPacket(@NonNull BedrockPacket packet) {
|
||||
session.sendPacket(packet);
|
||||
}
|
||||
|
||||
public void sendPacketImmediately(@NonNull BedrockPacket packet) {
|
||||
session.sendPacketImmediately(packet);
|
||||
}
|
||||
|
||||
public void disconnect(String reason) {
|
||||
session.disconnect(reason);
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return session.isClosed();
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return session.getAddress();
|
||||
}
|
||||
}
|
|
@ -30,9 +30,7 @@ import org.geysermc.connector.entity.Entity;
|
|||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
|
@ -46,6 +44,7 @@ public class EntityCache {
|
|||
private Map<Long, Entity> entities = new HashMap<>();
|
||||
private Map<Long, Long> entityIdTranslations = new HashMap<>();
|
||||
private Map<UUID, PlayerEntity> playerEntities = new HashMap<>();
|
||||
private Map<UUID, Long> bossbars = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private AtomicLong nextEntityId = new AtomicLong(2L);
|
||||
|
@ -61,17 +60,18 @@ public class EntityCache {
|
|||
entity.spawnEntity(session);
|
||||
}
|
||||
|
||||
public void removeEntity(Entity entity) {
|
||||
if (entity == null) return;
|
||||
|
||||
Long geyserId = entityIdTranslations.remove(entity.getEntityId());
|
||||
if (geyserId != null) {
|
||||
entities.remove(geyserId);
|
||||
if (entity instanceof PlayerEntity) {
|
||||
playerEntities.remove(((PlayerEntity) entity).getUuid());
|
||||
public boolean removeEntity(Entity entity, boolean force) {
|
||||
if (entity != null && entity.isValid() && (force || entity.despawnEntity(session))) {
|
||||
Long geyserId = entityIdTranslations.remove(entity.getEntityId());
|
||||
if (geyserId != null) {
|
||||
entities.remove(geyserId);
|
||||
if (entity.is(PlayerEntity.class)) {
|
||||
playerEntities.remove(entity.as(PlayerEntity.class).getUuid());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
entity.despawnEntity(session);
|
||||
return false;
|
||||
}
|
||||
|
||||
public Entity getEntityByGeyserId(long geyserId) {
|
||||
|
@ -82,6 +82,16 @@ public class EntityCache {
|
|||
return entities.get(entityIdTranslations.get(javaId));
|
||||
}
|
||||
|
||||
public <T extends Entity> Set<T> getEntitiesByType(Class<T> entityType) {
|
||||
Set<T> entitiesOfType = new HashSet<>();
|
||||
for (Entity entity : (entityType == PlayerEntity.class ? playerEntities : entities).values()) {
|
||||
if (entity.is(entityType)) {
|
||||
entitiesOfType.add(entity.as(entityType));
|
||||
}
|
||||
}
|
||||
return entitiesOfType;
|
||||
}
|
||||
|
||||
public void addPlayerEntity(PlayerEntity entity) {
|
||||
playerEntities.put(entity.getUuid(), entity);
|
||||
}
|
||||
|
@ -93,4 +103,18 @@ public class EntityCache {
|
|||
public void removePlayerEntity(UUID uuid) {
|
||||
playerEntities.remove(uuid);
|
||||
}
|
||||
|
||||
public long addBossBar(UUID uuid) {
|
||||
long entityId = getNextEntityId().incrementAndGet();
|
||||
bossbars.put(uuid, entityId);
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public long getBossBar(UUID uuid) {
|
||||
return bossbars.containsKey(uuid) ? bossbars.get(uuid) : -1;
|
||||
}
|
||||
|
||||
public long removeBossBar(UUID uuid) {
|
||||
return bossbars.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,27 +25,31 @@
|
|||
|
||||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
|
||||
public class ScoreboardCache {
|
||||
import java.util.Collection;
|
||||
|
||||
@Getter
|
||||
public class ScoreboardCache {
|
||||
private GeyserSession session;
|
||||
private Scoreboard scoreboard;
|
||||
|
||||
public ScoreboardCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
this.scoreboard = new Scoreboard(session);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Scoreboard scoreboard;
|
||||
|
||||
public void removeScoreboard() {
|
||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||
removeObjectivePacket.setObjectiveId(scoreboard.getObjective().getObjectiveName());
|
||||
session.getUpstream().sendPacket(removeObjectivePacket);
|
||||
if (scoreboard != null) {
|
||||
Collection<Objective> objectives = scoreboard.getObjectives().values();
|
||||
scoreboard = new Scoreboard(session);
|
||||
|
||||
for (Objective objective : objectives) {
|
||||
scoreboard.despawnObjective(objective);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public class Registry<T> {
|
||||
|
||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> MAP = new HashMap<>();
|
||||
|
||||
public static final Registry<Packet> JAVA = new Registry<>();
|
||||
|
@ -48,14 +47,18 @@ public class Registry<T> {
|
|||
BEDROCK.MAP.put(clazz, translator);
|
||||
}
|
||||
|
||||
public <P extends T> void translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
try {
|
||||
if (MAP.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
if (MAP.containsKey(clazz)) {
|
||||
((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.debug("Could not translate packet " + packet.getClass().getSimpleName());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.Serv
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.*;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
|
||||
|
@ -52,14 +53,12 @@ import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
|||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.java.*;
|
||||
import org.geysermc.connector.network.translators.java.entity.*;
|
||||
import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerActionAckTranslator;
|
||||
import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerHealthTranslator;
|
||||
import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerPositionRotationTranslator;
|
||||
import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerSetExperienceTranslator;
|
||||
import org.geysermc.connector.network.translators.java.entity.player.*;
|
||||
import org.geysermc.connector.network.translators.java.entity.spawn.*;
|
||||
import org.geysermc.connector.network.translators.java.inventory.OpenWindowPacketTranslator;
|
||||
import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator;
|
||||
import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator;
|
||||
import org.geysermc.connector.network.translators.java.scoreboard.JavaTeamTranslator;
|
||||
import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator;
|
||||
import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
|
||||
import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
|
||||
|
@ -115,6 +114,7 @@ public class TranslatorsInit {
|
|||
Registry.registerJava(ServerEntityRotationPacket.class, new JavaEntityRotationTranslator());
|
||||
Registry.registerJava(ServerEntityHeadLookPacket.class, new JavaEntityHeadLookTranslator());
|
||||
Registry.registerJava(ServerEntityMetadataPacket.class, new JavaEntityMetadataTranslator());
|
||||
Registry.registerJava(ServerBossBarPacket.class, new JavaBossBarTranslator());
|
||||
|
||||
Registry.registerJava(ServerSpawnExpOrbPacket.class, new JavaSpawnExpOrbTranslator());
|
||||
Registry.registerJava(ServerSpawnGlobalEntityPacket.class, new JavaSpawnGlobalEntityTranslator());
|
||||
|
@ -138,6 +138,7 @@ public class TranslatorsInit {
|
|||
Registry.registerJava(ServerScoreboardObjectivePacket.class, new JavaScoreboardObjectiveTranslator());
|
||||
Registry.registerJava(ServerDisplayScoreboardPacket.class, new JavaDisplayScoreboardTranslator());
|
||||
Registry.registerJava(ServerUpdateScorePacket.class, new JavaUpdateScoreTranslator());
|
||||
Registry.registerJava(ServerTeamPacket.class, new JavaTeamTranslator());
|
||||
Registry.registerJava(ServerBlockChangePacket.class, new JavaBlockChangeTranslator());
|
||||
Registry.registerJava(ServerMultiBlockChangePacket.class, new JavaMultiBlockChangeTranslator());
|
||||
|
||||
|
@ -146,11 +147,12 @@ public class TranslatorsInit {
|
|||
|
||||
Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator());
|
||||
Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator());
|
||||
Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
|
||||
Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
|
||||
Registry.registerBedrock(PlayerActionPacket.class, new BedrockActionTranslator());
|
||||
Registry.registerBedrock(MovePlayerPacket.class, new BedrockMovePlayerTranslator());
|
||||
Registry.registerBedrock(InventoryTransactionPacket.class, new BedrockInventoryTransactionTranslator());
|
||||
Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
|
||||
Registry.registerBedrock(MovePlayerPacket.class, new BedrockMovePlayerTranslator());
|
||||
Registry.registerBedrock(PlayerActionPacket.class, new BedrockActionTranslator());
|
||||
Registry.registerBedrock(SetLocalPlayerAsInitializedPacket.class, new BedrockPlayerInitializedTranslator());
|
||||
Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
|
||||
|
||||
itemTranslator = new ItemTranslator();
|
||||
blockTranslator = new BlockTranslator();
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
|
@ -34,6 +33,7 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
|
|
@ -25,21 +25,11 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
||||
|
|
|
@ -25,39 +25,58 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
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.network.translators.item.BedrockItem;
|
||||
|
||||
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(MovePlayerPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getPlayerEntity();
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
if (entity == null || !session.isSpawned()) return;
|
||||
|
||||
// can cause invalid moves when packet queue is not empty
|
||||
if (!session.getUpstream().isInitialized()) {
|
||||
MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket();
|
||||
moveEntityBack.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityBack.setPosition(entity.getPosition());
|
||||
moveEntityBack.setRotation(entity.getBedrockRotation());
|
||||
moveEntityBack.setTeleported(true);
|
||||
moveEntityBack.setOnGround(true);
|
||||
session.getUpstream().sendPacketImmediately(moveEntityBack);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) {
|
||||
session.getConnector().getLogger().info("Recalculating position...");
|
||||
recalculatePosition(session, entity, entity.getPosition());
|
||||
return;
|
||||
}
|
||||
|
||||
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
|
||||
packet.isOnGround(), packet.getPosition().getX(), Math.ceil((packet.getPosition().getY() - EntityType.PLAYER.getOffset()) * 2) / 2,
|
||||
packet.getPosition().getZ(), packet.getRotation().getY(), packet.getRotation().getX());
|
||||
double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset();
|
||||
|
||||
entity.moveAbsolute(packet.getPosition(), packet.getRotation());
|
||||
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
|
||||
packet.isOnGround(), packet.getPosition().getX(), Math.ceil(javaY * 2) / 2,
|
||||
packet.getPosition().getZ(), packet.getRotation().getY(), packet.getRotation().getX()
|
||||
);
|
||||
|
||||
// head yaw, pitch, head yaw
|
||||
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
||||
|
||||
entity.moveAbsolute(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0), rotation);
|
||||
|
||||
boolean colliding = false;
|
||||
Position position = new Position((int) packet.getPosition().getX(),
|
||||
(int) Math.ceil((packet.getPosition().getY() - EntityType.PLAYER.getOffset()) * 2) / 2, (int) packet.getPosition().getZ());
|
||||
(int) Math.ceil(javaY * 2) / 2, (int) packet.getPosition().getZ());
|
||||
|
||||
BedrockItem block = session.getChunkCache().getBlockAt(position);
|
||||
if (!block.getIdentifier().contains("air"))
|
||||
|
@ -82,7 +101,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
if (zRange < 0)
|
||||
zRange = -zRange;
|
||||
|
||||
if (xRange > 10 || yRange > 10 || zRange > 10) {
|
||||
if ((xRange + yRange + zRange) > 100) {
|
||||
session.getConnector().getLogger().warning(session.getName() + " moved too quickly." +
|
||||
" current position: " + currentPosition + ", new position: " + newPosition);
|
||||
|
||||
|
@ -102,7 +121,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
movePlayerPacket.setPosition(entity.getPosition());
|
||||
movePlayerPacket.setRotation(entity.getRotation());
|
||||
movePlayerPacket.setRotation(entity.getBedrockRotation());
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||
movePlayerPacket.setOnGround(true);
|
||||
entity.setMovePending(false);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
public class BedrockPlayerInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
|
||||
@Override
|
||||
public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession session) {
|
||||
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
|
||||
if (!session.getUpstream().isInitialized()) {
|
||||
session.getUpstream().setInitialized(true);
|
||||
|
||||
for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) {
|
||||
if (!entity.isValid()) {
|
||||
entity.sendPlayer(session);
|
||||
// async skin loading
|
||||
SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ 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() + "/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)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
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.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.TranslatorsInit;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
public class GenericInventoryTranslator extends InventoryTranslator {
|
||||
|
||||
|
@ -48,35 +46,27 @@ public class GenericInventoryTranslator extends InventoryTranslator {
|
|||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setWindowId((byte) inventory.getId());
|
||||
containerOpenPacket.setType((byte) 0);
|
||||
containerOpenPacket.setBlockPosition(new Vector3i(0, 0, 0));
|
||||
containerOpenPacket.setBlockPosition(Vector3i.ZERO);
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
ContainerId containerId = InventoryUtils.getContainerId(inventory.getId());
|
||||
if (containerId == null)
|
||||
return;
|
||||
|
||||
ItemData[] bedrockItems = new ItemData[inventory.getItems().length];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]);
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(containerId);
|
||||
contentPacket.setContainerId(inventory.getId());
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
ContainerId containerId = InventoryUtils.getContainerId(inventory.getId());
|
||||
if (containerId == null)
|
||||
return;
|
||||
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(containerId);
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot]));
|
||||
slotPacket.setInventorySlot(slot);
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package org.geysermc.connector.network.translators.java;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerBossBarPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.BossEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
public class JavaBossBarTranslator extends PacketTranslator<ServerBossBarPacket> {
|
||||
@Override
|
||||
public void translate(ServerBossBarPacket packet, GeyserSession session) {
|
||||
BossEventPacket bossEventPacket = new BossEventPacket();
|
||||
bossEventPacket.setBossUniqueEntityId(session.getEntityCache().getBossBar(packet.getUUID()));
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case ADD:
|
||||
long entityId = session.getEntityCache().addBossBar(packet.getUUID());
|
||||
addBossEntity(session, entityId);
|
||||
|
||||
bossEventPacket.setType(BossEventPacket.Type.SHOW);
|
||||
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||
bossEventPacket.setTitle(MessageUtils.getBedrockMessage(packet.getTitle()));
|
||||
bossEventPacket.setHealthPercentage(packet.getHealth());
|
||||
bossEventPacket.setColor(0); //ignored by client
|
||||
bossEventPacket.setOverlay(1);
|
||||
bossEventPacket.setDarkenSky(0);
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
bossEventPacket.setType(BossEventPacket.Type.TITLE);
|
||||
bossEventPacket.setTitle(MessageUtils.getBedrockMessage(packet.getTitle()));
|
||||
break;
|
||||
case UPDATE_HEALTH:
|
||||
bossEventPacket.setType(BossEventPacket.Type.HEALTH_PERCENTAGE);
|
||||
bossEventPacket.setHealthPercentage(packet.getHealth());
|
||||
break;
|
||||
case REMOVE:
|
||||
bossEventPacket.setType(BossEventPacket.Type.HIDE);
|
||||
removeBossEntity(session, session.getEntityCache().removeBossBar(packet.getUUID()));
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
case UPDATE_FLAGS:
|
||||
//todo
|
||||
return;
|
||||
}
|
||||
|
||||
session.getUpstream().sendPacket(bossEventPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bedrock still needs an entity to display the BossBar.<br>
|
||||
* Just like 1.8 but it doesn't care about which entity
|
||||
*/
|
||||
private void addBossEntity(GeyserSession session, long entityId) {
|
||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||
addEntityPacket.setUniqueEntityId(entityId);
|
||||
addEntityPacket.setRuntimeEntityId(entityId);
|
||||
addEntityPacket.setIdentifier("minecraft:creeper");
|
||||
addEntityPacket.setEntityType(33);
|
||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition());
|
||||
addEntityPacket.setRotation(Vector3f.ZERO);
|
||||
addEntityPacket.setMotion(Vector3f.ZERO);
|
||||
addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work?
|
||||
|
||||
session.getUpstream().sendPacket(addEntityPacket);
|
||||
}
|
||||
|
||||
private void removeBossEntity(GeyserSession session, long entityId) {
|
||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||
removeEntityPacket.setUniqueEntityId(entityId);
|
||||
|
||||
session.getUpstream().sendPacket(removeEntityPacket);
|
||||
}
|
||||
}
|
|
@ -43,12 +43,16 @@ public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
|||
switch (packet.getType()) {
|
||||
case CHAT:
|
||||
textPacket.setType(TextPacket.Type.CHAT);
|
||||
break;
|
||||
case SYSTEM:
|
||||
textPacket.setType(TextPacket.Type.SYSTEM);
|
||||
break;
|
||||
case NOTIFICATION:
|
||||
textPacket.setType(TextPacket.Type.TIP);
|
||||
break;
|
||||
default:
|
||||
textPacket.setType(TextPacket.Type.RAW);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.getMessage() instanceof TranslationMessage) {
|
||||
|
|
|
@ -36,7 +36,10 @@ public class JavaEntityDestroyTranslator extends PacketTranslator<ServerEntityDe
|
|||
public void translate(ServerEntityDestroyPacket packet, GeyserSession session) {
|
||||
for (int entityId : packet.getEntityIds()) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||
session.getEntityCache().removeEntity(entity);
|
||||
|
||||
if (entity != null) {
|
||||
session.getEntityCache().removeEntity(entity, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -40,15 +40,15 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityH
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
entity.setRotation(new Vector3f(entity.getRotation().getX(), entity.getRotation().getY(), packet.getHeadYaw()));
|
||||
if (entity == null) return;
|
||||
|
||||
entity.setRotation(Vector3f.from(entity.getRotation().getX(), entity.getRotation().getY(), packet.getHeadYaw()));
|
||||
|
||||
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityAbsolutePacket.setRotation(entity.getRotation());
|
||||
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
||||
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
|
||||
moveEntityAbsolutePacket.setOnGround(true);
|
||||
|
||||
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
||||
|
|
|
@ -39,8 +39,7 @@ public class JavaEntityMetadataTranslator extends PacketTranslator<ServerEntityM
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
if (entity == null) return;
|
||||
|
||||
if (entity.isValid()) {
|
||||
// TODO: Make this actually useful lol
|
||||
|
|
|
@ -39,16 +39,15 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
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()) {
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityPacket.setPosition(entity.getPosition());
|
||||
moveEntityPacket.setRotation(entity.getRotation());
|
||||
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||
moveEntityPacket.setTeleported(false);
|
||||
entity.setMovePending(false);
|
||||
|
|
|
@ -39,16 +39,15 @@ public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityP
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
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()) {
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityPacket.setPosition(entity.getPosition());
|
||||
moveEntityPacket.setRotation(entity.getRotation());
|
||||
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||
moveEntityPacket.setTeleported(false);
|
||||
entity.setMovePending(false);
|
||||
|
|
|
@ -40,11 +40,7 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntit
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
if (!entity.isValid())
|
||||
return;
|
||||
if (entity == null || !entity.isValid()) return;
|
||||
|
||||
for (Attribute attribute : packet.getAttributes()) {
|
||||
switch (attribute.getType()) {
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
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.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
@ -40,18 +39,15 @@ public class JavaEntityRotationTranslator extends PacketTranslator<ServerEntityR
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
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()) {
|
||||
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
||||
moveEntityAbsolutePacket.setRotation(rotation);
|
||||
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
|
||||
entity.setMovePending(false);
|
||||
|
||||
session.getUpstream().sendPacket(moveEntityAbsolutePacket);
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -42,13 +42,13 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
|
|||
}
|
||||
if (entity == null) return;
|
||||
|
||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
|
||||
entity.moveAbsolute(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||
|
||||
if (entity.isMovePending()) {
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityPacket.setPosition(entity.getPosition());
|
||||
moveEntityPacket.setRotation(entity.getRotation());
|
||||
moveEntityPacket.setRotation(entity.getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(packet.isOnGround());
|
||||
moveEntityPacket.setTeleported(true);
|
||||
entity.setMovePending(false);
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -40,10 +40,9 @@ public class JavaEntityVelocityTranslator extends PacketTranslator<ServerEntityV
|
|||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
if (entity == null) return;
|
||||
|
||||
entity.setMotion(new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()));
|
||||
entity.setMotion(Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()));
|
||||
|
||||
SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
|
||||
entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.data.game.ClientRequest;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerHealthPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetHealthPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
@ -61,7 +61,7 @@ public class JavaPlayerHealthTranslator extends PacketTranslator<ServerPlayerHea
|
|||
|
||||
if (packet.getHealth() <= 0) {
|
||||
RespawnPacket respawnPacket = new RespawnPacket();
|
||||
respawnPacket.setPosition(new Vector3f(0, 72, 0));
|
||||
respawnPacket.setPosition(Vector3f.from(0, 72, 0));
|
||||
session.getUpstream().sendPacket(new RespawnPacket());
|
||||
|
||||
ClientRequestPacket javaRespawnPacket = new ClientRequestPacket(ClientRequest.RESPAWN);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
|
||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayerListEntryPacket> {
|
||||
@Override
|
||||
public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) {
|
||||
if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return;
|
||||
|
||||
PlayerListPacket translate = new PlayerListPacket();
|
||||
translate.setType(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Type.ADD : PlayerListPacket.Type.REMOVE);
|
||||
|
||||
for (PlayerListEntry entry : packet.getEntries()) {
|
||||
if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) {
|
||||
boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid());
|
||||
|
||||
PlayerEntity playerEntity = session.getPlayerEntity();
|
||||
if (self) playerEntity.setProfile(entry.getProfile());
|
||||
else {
|
||||
playerEntity = new PlayerEntity(
|
||||
entry.getProfile(),
|
||||
-1,
|
||||
session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
Vector3f.ZERO,
|
||||
Vector3f.ZERO,
|
||||
Vector3f.ZERO
|
||||
);
|
||||
}
|
||||
|
||||
session.getEntityCache().addPlayerEntity(playerEntity);
|
||||
playerEntity.setPlayerList(true);
|
||||
|
||||
translate.getEntries().add(SkinUtils.buildCachedEntry(entry.getProfile(), playerEntity.getGeyserId()));
|
||||
} else {
|
||||
PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
|
||||
if (entity != null && entity.isValid()) {
|
||||
// remove from tablist but player entity is still there
|
||||
entity.setPlayerList(false);
|
||||
} else {
|
||||
// just remove it from caching
|
||||
session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
|
||||
}
|
||||
translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId()));
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.getAction() == PlayerListEntryAction.REMOVE_PLAYER || session.getUpstream().isInitialized()) {
|
||||
session.getUpstream().sendPacket(translate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.geysermc.connector.console.GeyserLogger;
|
||||
|
@ -48,7 +48,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||
return;
|
||||
|
||||
if (!session.isSpawned()) {
|
||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
|
||||
entity.moveAbsolute(Vector3f.from(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||
|
||||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||
entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
|
@ -57,8 +57,8 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()));
|
||||
movePlayerPacket.setRotation(new Vector3f(packet.getPitch(), packet.getYaw(), 0));
|
||||
movePlayerPacket.setPosition(Vector3f.from(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()));
|
||||
movePlayerPacket.setRotation(Vector3f.from(packet.getPitch(), packet.getYaw(), 0));
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.RESET);
|
||||
movePlayerPacket.setOnGround(true);
|
||||
entity.setMovePending(false);
|
||||
|
@ -70,12 +70,12 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
|||
return;
|
||||
}
|
||||
|
||||
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
|
||||
entity.moveAbsolute(Vector3f.from(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getYaw(), packet.getPitch());
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.01f, packet.getZ()));
|
||||
movePlayerPacket.setRotation(new Vector3f(packet.getPitch(), packet.getYaw(), 0));
|
||||
movePlayerPacket.setPosition(Vector3f.from(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.01f, packet.getZ()));
|
||||
movePlayerPacket.setRotation(Vector3f.from(packet.getPitch(), packet.getYaw(), 0));
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||
movePlayerPacket.setOnGround(true);
|
||||
entity.setMovePending(false);
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package org.geysermc.connector.network.translators.java.entity.spawn;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
|
||||
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.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.utils.ProvidedSkin;
|
||||
import org.geysermc.connector.utils.ProvidedSkinData;
|
||||
|
||||
public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayerListEntryPacket> {
|
||||
private static ProvidedSkinData providedSkinData = ProvidedSkinData.getProvidedSkin("bedrock/skin/model_steve.json");
|
||||
private static byte[] providedSkin = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin();
|
||||
|
||||
@Override
|
||||
public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) {
|
||||
if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return;
|
||||
|
||||
PlayerListPacket translate = new PlayerListPacket();
|
||||
translate.setType(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Type.ADD : PlayerListPacket.Type.REMOVE);
|
||||
|
||||
for (PlayerListEntry entry : packet.getEntries()) {
|
||||
PlayerListPacket.Entry entry1 = new PlayerListPacket.Entry(entry.getProfile().getId());
|
||||
|
||||
if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) {
|
||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
||||
|
||||
session.getEntityCache().addPlayerEntity(new PlayerEntity(
|
||||
entry.getProfile(),
|
||||
-1,
|
||||
geyserId,
|
||||
Vector3f.ZERO,
|
||||
Vector3f.ZERO,
|
||||
Vector3f.ZERO
|
||||
));
|
||||
|
||||
entry1.setName(entry.getProfile().getName());
|
||||
entry1.setEntityId(geyserId);
|
||||
entry1.setSkinId(providedSkinData.getSkinId());
|
||||
entry1.setSkinData(providedSkin);
|
||||
entry1.setCapeData(new byte[0]);
|
||||
entry1.setGeometryName(providedSkinData.getGeometryId());
|
||||
entry1.setGeometryData(providedSkinData.getGeometryDataEncoded());
|
||||
entry1.setXuid("");
|
||||
entry1.setPlatformChatId("WIN10");
|
||||
} else {
|
||||
session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
|
||||
}
|
||||
translate.getEntries().add(entry1);
|
||||
}
|
||||
|
||||
session.getUpstream().sendPacket(translate);
|
||||
}
|
||||
}
|
|
@ -25,26 +25,24 @@
|
|||
|
||||
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.ServerSpawnExpOrbPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.ExpOrbEntity;
|
||||
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.EntityUtils;
|
||||
|
||||
public class JavaSpawnExpOrbTranslator extends PacketTranslator<ServerSpawnExpOrbPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerSpawnExpOrbPacket packet, GeyserSession session) {
|
||||
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));
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
|
||||
if (entity == null)
|
||||
return;
|
||||
Entity entity = new ExpOrbEntity(
|
||||
packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
EntityType.EXPERIENCE_ORB, position, Vector3f.ZERO, Vector3f.ZERO
|
||||
);
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
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.ServerSpawnGlobalEntityPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -36,14 +36,13 @@ public class JavaSpawnGlobalEntityTranslator extends PacketTranslator<ServerSpaw
|
|||
|
||||
@Override
|
||||
public void translate(ServerSpawnGlobalEntityPacket packet, GeyserSession session) {
|
||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
|
||||
// Currently GlobalEntityType only has a lightning bolt
|
||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
EntityType.LIGHTNING_BOLT, position, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
|
||||
|
||||
if (entity == null)
|
||||
return;
|
||||
Entity entity = new Entity(
|
||||
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
EntityType.LIGHTNING_BOLT, position, Vector3f.ZERO, Vector3f.ZERO
|
||||
);
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
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.ServerSpawnMobPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.console.GeyserLogger;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
@ -38,9 +38,9 @@ public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacke
|
|||
|
||||
@Override
|
||||
public void translate(ServerSpawnMobPacket packet, GeyserSession session) {
|
||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getHeadYaw());
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||
Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getHeadYaw());
|
||||
|
||||
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
||||
if (type == null) {
|
||||
|
@ -48,8 +48,10 @@ public class JavaSpawnMobTranslator extends PacketTranslator<ServerSpawnMobPacke
|
|||
return;
|
||||
}
|
||||
|
||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
type, position, motion, rotation);
|
||||
Entity entity = new Entity(
|
||||
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
type, position, motion, rotation
|
||||
);
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.spawn;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.object.ObjectType;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnObjectPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.console.GeyserLogger;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
@ -42,9 +42,9 @@ public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjec
|
|||
if (packet.getType() == ObjectType.ITEM_FRAME)
|
||||
return;
|
||||
|
||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f motion = new Vector3f(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
|
||||
Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), 0);
|
||||
|
||||
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
|
||||
if (type == null) {
|
||||
|
@ -52,11 +52,10 @@ public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjec
|
|||
return;
|
||||
}
|
||||
|
||||
Entity entity = new Entity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
type, position, motion, rotation);
|
||||
|
||||
if (entity == null)
|
||||
return;
|
||||
Entity entity = new Entity(
|
||||
packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
type, position, motion, rotation
|
||||
);
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
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 com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.entity.PaintingEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -37,7 +37,7 @@ public class JavaSpawnPaintingTranslator extends PacketTranslator<ServerSpawnPai
|
|||
|
||||
@Override
|
||||
public void translate(ServerSpawnPaintingPacket packet, GeyserSession session) {
|
||||
Vector3f position = new Vector3f(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
|
||||
Vector3f position = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
|
||||
|
||||
Geyser.getGeneralThreadPool().execute(() -> { // #slowdownbrother, just don't execute it directly
|
||||
PaintingEntity entity = new PaintingEntity(
|
||||
|
|
|
@ -25,23 +25,25 @@
|
|||
|
||||
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.ServerSpawnPlayerPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.api.Geyser;
|
||||
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.SkinUtils;
|
||||
|
||||
public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlayerPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
|
||||
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getYaw());
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY() - EntityType.PLAYER.getOffset(), packet.getZ());
|
||||
Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getYaw());
|
||||
|
||||
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUUID());
|
||||
if (entity == null) {
|
||||
Geyser.getLogger().error("Haven't received PlayerListEntry packet before spawning player! We ignore the player");
|
||||
Geyser.getLogger().error("Haven't received PlayerListEntry packet before spawning player! We ignore the player " + packet.getUUID());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,8 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
|||
entity.setPosition(position);
|
||||
entity.setRotation(rotation);
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
entity.sendPlayer(session);
|
||||
// async skin loading
|
||||
SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,20 +27,14 @@ package org.geysermc.connector.network.translators.java.scoreboard;
|
|||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.ScoreboardCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
|
||||
public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisplayScoreboardPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
||||
try {
|
||||
ScoreboardCache cache = session.getScoreboardCache();
|
||||
Scoreboard scoreboard = new Scoreboard(session);
|
||||
cache.setScoreboard(scoreboard);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
session.getScoreboardCache().getScoreboard().registerNewObjective(
|
||||
packet.getScoreboardName(), packet.getPosition()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,43 +25,39 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.scoreboard;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.ScoreboardCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
import org.geysermc.connector.scoreboard.ScoreboardObjective;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerScoreboardObjectivePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
||||
try {
|
||||
ScoreboardCache cache = session.getScoreboardCache();
|
||||
Scoreboard scoreboard = new Scoreboard(session);
|
||||
if (cache.getScoreboard() != null)
|
||||
scoreboard = cache.getScoreboard();
|
||||
ScoreboardCache cache = session.getScoreboardCache();
|
||||
Scoreboard scoreboard = cache.getScoreboard();
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case ADD:
|
||||
ScoreboardObjective objective = scoreboard.registerNewObjective(packet.getName());
|
||||
objective.setDisplaySlot(ScoreboardObjective.DisplaySlot.SIDEBAR);
|
||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
||||
break;
|
||||
case UPDATE:
|
||||
ScoreboardObjective updateObj = scoreboard.getObjective(packet.getName());
|
||||
updateObj.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
||||
break;
|
||||
case REMOVE:
|
||||
scoreboard.unregisterObjective(packet.getName());
|
||||
break;
|
||||
}
|
||||
Objective objective = scoreboard.getObjective(packet.getName());
|
||||
|
||||
scoreboard.onUpdate();
|
||||
cache.setScoreboard(scoreboard);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
||||
objective = scoreboard.registerNewObjective(packet.getName(), true);
|
||||
}
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case ADD:
|
||||
case UPDATE:
|
||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
||||
objective.setType(packet.getType().ordinal());
|
||||
break;
|
||||
case REMOVE:
|
||||
scoreboard.unregisterObjective(packet.getName());
|
||||
break;
|
||||
}
|
||||
|
||||
if (objective != null && !objective.isTemp()) scoreboard.onUpdate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,52 @@
|
|||
package org.geysermc.connector.network.translators.java.scoreboard;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
import org.geysermc.connector.scoreboard.UpdateType;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerTeamPacket packet, GeyserSession session) {
|
||||
Geyser.getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction()+" "+ Arrays.toString(packet.getPlayers()));
|
||||
|
||||
Scoreboard scoreboard = session.getScoreboardCache().getScoreboard();
|
||||
switch (packet.getAction()) {
|
||||
case CREATE:
|
||||
scoreboard.registerNewTeam(packet.getTeamName(), toPlayerSet(packet.getPlayers()))
|
||||
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
||||
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()));
|
||||
break;
|
||||
case UPDATE:
|
||||
scoreboard.getTeam(packet.getTeamName())
|
||||
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
||||
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()))
|
||||
.setUpdateType(UpdateType.UPDATE);
|
||||
break;
|
||||
case ADD_PLAYER:
|
||||
scoreboard.getTeam(packet.getTeamName()).addEntities(packet.getPlayers());
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
scoreboard.getTeam(packet.getTeamName()).removeEntities(packet.getPlayers());
|
||||
break;
|
||||
case REMOVE:
|
||||
scoreboard.removeTeam(packet.getTeamName());
|
||||
break;
|
||||
}
|
||||
scoreboard.onUpdate();
|
||||
}
|
||||
|
||||
private Set<String> toPlayerSet(String[] players) {
|
||||
return new HashSet<>(Arrays.asList(players));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,38 +25,41 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.scoreboard;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.ScoreboardCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
import org.geysermc.connector.scoreboard.ScoreboardObjective;
|
||||
|
||||
public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScorePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerUpdateScorePacket packet, GeyserSession session) {
|
||||
try {
|
||||
ScoreboardCache cache = session.getScoreboardCache();
|
||||
Scoreboard scoreboard = new Scoreboard(session);
|
||||
if (cache.getScoreboard() != null)
|
||||
scoreboard = cache.getScoreboard();
|
||||
Scoreboard scoreboard = session.getScoreboardCache().getScoreboard();
|
||||
|
||||
ScoreboardObjective objective = scoreboard.getObjective(packet.getObjective());
|
||||
if (objective == null) {
|
||||
objective = scoreboard.registerNewObjective(packet.getObjective());
|
||||
Objective objective = scoreboard.getObjective(packet.getObjective());
|
||||
if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) {
|
||||
Geyser.getLogger().info("Tried to update score without the existence of its requested objective '" + packet.getObjective() + '\'');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case REMOVE:
|
||||
objective.registerScore(packet.getEntry(), packet.getEntry(), packet.getValue(), SetScorePacket.Action.REMOVE);
|
||||
break;
|
||||
case ADD_OR_UPDATE:
|
||||
objective.registerScore(packet.getEntry(), packet.getEntry(), packet.getValue(), SetScorePacket.Action.SET);
|
||||
objective.setScore(packet.getEntry(), packet.getValue());
|
||||
break;
|
||||
case REMOVE:
|
||||
if (objective != null) {
|
||||
objective.resetScore(packet.getEntry());
|
||||
} else {
|
||||
for (Objective objective1 : scoreboard.getObjectives().values()) {
|
||||
objective1.resetScore(packet.getEntry());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
cache.setScoreboard(scoreboard);
|
||||
scoreboard.onUpdate();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockChangeRecord;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -16,10 +16,11 @@ public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChang
|
|||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
BlockChangeRecord record = packet.getRecord();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(new Vector3i(
|
||||
updateBlockPacket.setBlockPosition(Vector3i.from(
|
||||
record.getPosition().getX(),
|
||||
record.getPosition().getY(),
|
||||
record.getPosition().getZ()));
|
||||
record.getPosition().getZ()
|
||||
));
|
||||
|
||||
BedrockItem bedrockItem = TranslatorsInit.getBlockTranslator().getBedrockBlock(record.getBlock());
|
||||
updateBlockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(bedrockItem.hashCode()));
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
|
||||
import com.nukkitx.math.vector.Vector2i;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.network.VarInts;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockChangeRecord;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerMultiBlockChangePacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -42,10 +42,11 @@ public class JavaMultiBlockChangeTranslator extends PacketTranslator<ServerMulti
|
|||
for (BlockChangeRecord record : packet.getRecords()) {
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(new Vector3i(
|
||||
updateBlockPacket.setBlockPosition(Vector3i.from(
|
||||
record.getPosition().getX(),
|
||||
record.getPosition().getY(),
|
||||
record.getPosition().getZ()));
|
||||
record.getPosition().getZ()
|
||||
));
|
||||
|
||||
BedrockItem bedrockItem = TranslatorsInit.getBlockTranslator().getBedrockBlock(record.getBlock());
|
||||
updateBlockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(bedrockItem.hashCode()));
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
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.world.ServerNotifyClientPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ShowCreditsPacket;
|
||||
|
@ -46,14 +46,14 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
|
|||
LevelEventPacket startRainPacket = new LevelEventPacket();
|
||||
startRainPacket.setEvent(LevelEventPacket.Event.START_RAIN);
|
||||
startRainPacket.setData(ThreadLocalRandom.current().nextInt(50000) + 10000);
|
||||
startRainPacket.setPosition(new Vector3f(0, 0, 0));
|
||||
startRainPacket.setPosition(Vector3f.ZERO);
|
||||
session.getUpstream().sendPacket(startRainPacket);
|
||||
break;
|
||||
case STOP_RAIN:
|
||||
LevelEventPacket stopRainPacket = new LevelEventPacket();
|
||||
stopRainPacket.setEvent(LevelEventPacket.Event.STOP_RAIN);
|
||||
stopRainPacket.setData(ThreadLocalRandom.current().nextInt(50000) + 10000);
|
||||
stopRainPacket.setPosition(new Vector3f(0, 0, 0));
|
||||
stopRainPacket.setPosition(Vector3f.ZERO);
|
||||
session.getUpstream().sendPacket(stopRainPacket);
|
||||
break;
|
||||
case CHANGE_GAMEMODE:
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnPositionPacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetSpawnPositionPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -36,7 +36,7 @@ public class JavaSpawnPositionTranslator extends PacketTranslator<ServerSpawnPos
|
|||
@Override
|
||||
public void translate(ServerSpawnPositionPacket packet, GeyserSession session) {
|
||||
SetSpawnPositionPacket spawnPositionPacket = new SetSpawnPositionPacket();
|
||||
spawnPositionPacket.setBlockPosition(new Vector3i(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||
spawnPositionPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||
spawnPositionPacket.setSpawnForced(true);
|
||||
spawnPositionPacket.setSpawnType(SetSpawnPositionPacket.Type.PLAYER_SPAWN);
|
||||
session.getUpstream().sendPacket(spawnPositionPacket);
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2019 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public class Objective {
|
||||
private Scoreboard scoreboard;
|
||||
private long id;
|
||||
private boolean temp;
|
||||
|
||||
@Setter
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
private String objectiveName;
|
||||
private String displaySlot;
|
||||
private String displayName = "unknown";
|
||||
private int type = 0; // 0 = integer, 1 = heart
|
||||
|
||||
private Map<String, Score> scores = new HashMap<>();
|
||||
|
||||
private Objective(Scoreboard scoreboard) {
|
||||
this.id = scoreboard.getNextId().getAndIncrement();
|
||||
this.scoreboard = scoreboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* /!\ This method is made for temporary objectives until the real objective is received
|
||||
*/
|
||||
public Objective(Scoreboard scoreboard, String objectiveName) {
|
||||
this(scoreboard);
|
||||
this.objectiveName = objectiveName;
|
||||
this.temp = true;
|
||||
}
|
||||
|
||||
public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) {
|
||||
this(scoreboard, objectiveName, displaySlot.name().toLowerCase(), displayName, type);
|
||||
}
|
||||
|
||||
public Objective(Scoreboard scoreboard, String objectiveName, String displaySlot, String displayName, int type) {
|
||||
this(scoreboard);
|
||||
this.objectiveName = objectiveName;
|
||||
this.displaySlot = displaySlot;
|
||||
this.displayName = displayName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void registerScore(String id, int score) {
|
||||
if (!scores.containsKey(id)) {
|
||||
Score score1 = new Score(this, id)
|
||||
.setScore(score)
|
||||
.setTeam(scoreboard.getTeamFor(id));
|
||||
scores.put(id, score1);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScore(String id, int score) {
|
||||
if (scores.containsKey(id)) {
|
||||
scores.get(id).setScore(score).setUpdateType(UpdateType.ADD);
|
||||
} else {
|
||||
registerScore(id, score);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScoreText(String oldText, String newText) {
|
||||
if (!scores.containsKey(oldText) || oldText.equals(newText)) return;
|
||||
Score oldScore = scores.get(oldText);
|
||||
|
||||
Score newScore = new Score(this, newText)
|
||||
.setScore(oldScore.getScore())
|
||||
.setTeam(scoreboard.getTeamFor(newText));
|
||||
|
||||
scores.put(newText, newScore);
|
||||
oldScore.setUpdateType(UpdateType.REMOVE);
|
||||
}
|
||||
|
||||
public int getScore(String id) {
|
||||
if (scores.containsKey(id)) {
|
||||
return scores.get(id).getScore();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Score getScore(int line) {
|
||||
for (Score score : scores.values()) {
|
||||
if (score.getScore() == line) return score;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void resetScore(String id) {
|
||||
if (scores.containsKey(id)) {
|
||||
scores.get(id).setUpdateType(UpdateType.REMOVE);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeScore(String id) {
|
||||
scores.remove(id);
|
||||
}
|
||||
|
||||
public Objective setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Objective setType(int type) {
|
||||
this.type = type;
|
||||
if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void removeTemp(ScoreboardPosition displaySlot) {
|
||||
if (temp) {
|
||||
temp = false;
|
||||
this.displaySlot = displaySlot.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,43 +25,40 @@
|
|||
|
||||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Adapted from: https://github.com/Ragnok123/GTScoreboard
|
||||
*/
|
||||
@Getter @Setter
|
||||
@Accessors(chain = true)
|
||||
public class Score {
|
||||
private Objective objective;
|
||||
private long id;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
private String name;
|
||||
private Team team;
|
||||
private int score;
|
||||
private int oldScore = Integer.MIN_VALUE;
|
||||
|
||||
@Getter
|
||||
private long scoreboardId;
|
||||
|
||||
private ScoreboardObjective objective;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String fakePlayer;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private SetScorePacket.Action action = SetScorePacket.Action.SET;
|
||||
|
||||
private boolean modified = false;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String fakeId;
|
||||
|
||||
public Score(ScoreboardObjective objective, String fakePlayer) {
|
||||
this.scoreboardId = -new Random().nextLong();
|
||||
public Score(Objective objective, String name) {
|
||||
this.id = objective.getScoreboard().getNextId().getAndIncrement();
|
||||
this.objective = objective;
|
||||
this.fakePlayer = fakePlayer;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
if (team != null && team.getUpdateType() != UpdateType.REMOVE) {
|
||||
return team.getPrefix() + name + team.getSuffix();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public Score setScore(int score) {
|
||||
if (oldScore == Integer.MIN_VALUE) {
|
||||
this.oldScore = score;
|
||||
}
|
||||
this.score = score;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,111 +25,228 @@
|
|||
|
||||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
||||
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Adapted from: https://github.com/Ragnok123/GTScoreboard
|
||||
*/
|
||||
import static org.geysermc.connector.scoreboard.UpdateType.*;
|
||||
|
||||
@Getter
|
||||
public class Scoreboard {
|
||||
|
||||
@Getter
|
||||
private ScoreboardObjective objective;
|
||||
|
||||
private GeyserSession session;
|
||||
private AtomicLong nextId = new AtomicLong(0);
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private long id;
|
||||
|
||||
private Map<String, ScoreboardObjective> objectiveMap = new HashMap<String, ScoreboardObjective>();
|
||||
private Map<String, Objective> objectives = new HashMap<>();
|
||||
private Map<String, Team> teams = new HashMap<>();
|
||||
|
||||
public Scoreboard(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
||||
id = new Random().nextLong();
|
||||
}
|
||||
|
||||
public ScoreboardObjective registerNewObjective(String objectiveName) {
|
||||
ScoreboardObjective objective = new ScoreboardObjective();
|
||||
objective.setObjectiveName(objectiveName);
|
||||
this.objective = objective;
|
||||
if (!objectiveMap.containsKey(objectiveName)) {
|
||||
objectiveMap.put(objectiveName, objective);
|
||||
}
|
||||
|
||||
public Objective registerNewObjective(String objectiveId, boolean temp) {
|
||||
if (!temp || objectives.containsKey(objectiveId)) return objectives.get(objectiveId);
|
||||
Objective objective = new Objective(this, objectiveId);
|
||||
objectives.put(objectiveId, objective);
|
||||
return objective;
|
||||
}
|
||||
|
||||
public ScoreboardObjective getObjective(String objectiveName) {
|
||||
ScoreboardObjective objective = null;
|
||||
if (objectiveMap.containsKey(objectiveName) && this.objective.getObjectiveName().contains(objectiveName)) {
|
||||
objective = this.objective;
|
||||
public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
||||
Objective objective = null;
|
||||
if (objectives.containsKey(objectiveId)) {
|
||||
objective = objectives.get(objectiveId);
|
||||
if (objective.isTemp()) objective.removeTemp(displaySlot);
|
||||
else {
|
||||
despawnObjective(objective);
|
||||
objective = null;
|
||||
}
|
||||
}
|
||||
if (objective == null) {
|
||||
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
||||
objectives.put(objectiveId, objective);
|
||||
}
|
||||
|
||||
return objective;
|
||||
}
|
||||
|
||||
public void setObjective(String objectiveName) {
|
||||
if (objectiveMap.containsKey(objectiveName))
|
||||
objective = objectiveMap.get(objectiveName);
|
||||
public Team registerNewTeam(String teamName, Set<String> players) {
|
||||
if (teams.containsKey(teamName)) {
|
||||
Geyser.getLogger().info("Ignoring team " + teamName + ". It overrides without removing old team.");
|
||||
return getTeam(teamName);
|
||||
}
|
||||
|
||||
Team team = new Team(this, teamName).setEntities(players);
|
||||
teams.put(teamName, team);
|
||||
|
||||
for (Objective objective : objectives.values()) {
|
||||
for (Score score : objective.getScores().values()) {
|
||||
if (players.contains(score.getName())) {
|
||||
score.setTeam(team);
|
||||
}
|
||||
}
|
||||
}
|
||||
return team;
|
||||
}
|
||||
|
||||
public Objective getObjective(String objectiveName) {
|
||||
return objectives.get(objectiveName);
|
||||
}
|
||||
|
||||
public Team getTeam(String teamName) {
|
||||
return teams.get(teamName);
|
||||
}
|
||||
|
||||
public void unregisterObjective(String objectiveName) {
|
||||
if (!objectiveMap.containsKey(objectiveName))
|
||||
return;
|
||||
Objective objective = getObjective(objectiveName);
|
||||
if (objective != null) objective.setUpdateType(REMOVE);
|
||||
}
|
||||
|
||||
if (objective.getObjectiveName().equals(objectiveName)) {
|
||||
objective = null;
|
||||
}
|
||||
|
||||
objectiveMap.remove(objectiveName);
|
||||
public void removeTeam(String teamName) {
|
||||
Team remove = teams.remove(teamName);
|
||||
if (remove != null) remove.setUpdateType(REMOVE);
|
||||
}
|
||||
|
||||
public void onUpdate() {
|
||||
if (objective == null)
|
||||
return;
|
||||
Set<Objective> changedObjectives = new HashSet<>();
|
||||
List<ScoreInfo> addScores = new ArrayList<>();
|
||||
List<ScoreInfo> removeScores = new ArrayList<>();
|
||||
|
||||
for (String objectiveId : new ArrayList<>(objectives.keySet())) {
|
||||
Objective objective = objectives.get(objectiveId);
|
||||
if (objective.isTemp()) {
|
||||
Geyser.getLogger().debug("Ignoring temp Scoreboard Objective '"+ objectiveId +'\'');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (objective.getUpdateType() != NOTHING) changedObjectives.add(objective);
|
||||
|
||||
boolean globalUpdate = objective.getUpdateType() == UPDATE;
|
||||
boolean globalAdd = objective.getUpdateType() == ADD || globalUpdate;
|
||||
boolean globalRemove = objective.getUpdateType() == REMOVE || globalUpdate;
|
||||
|
||||
boolean hasUpdate = globalUpdate;
|
||||
|
||||
List<Score> handledScores = new ArrayList<>();
|
||||
for (String identifier : new HashSet<>(objective.getScores().keySet())) {
|
||||
Score score = objective.getScores().get(identifier);
|
||||
Team team = score.getTeam();
|
||||
|
||||
boolean inTeam = team != null && team.getEntities().contains(score.getName());
|
||||
|
||||
boolean teamAdd = team != null && (team.getUpdateType() == ADD || team.getUpdateType() == UPDATE);
|
||||
boolean teamRemove = team != null && (team.getUpdateType() == REMOVE || team.getUpdateType() == UPDATE);
|
||||
|
||||
if (team != null && (team.getUpdateType() == REMOVE || !inTeam)) score.setTeam(null);
|
||||
|
||||
boolean add = (hasUpdate || globalAdd || teamAdd || teamRemove || score.getUpdateType() == ADD || score.getUpdateType() == UPDATE) && (score.getUpdateType() != REMOVE);
|
||||
boolean remove = hasUpdate || globalRemove || teamAdd || teamRemove || score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE;
|
||||
|
||||
boolean updated = false;
|
||||
if (!hasUpdate) {
|
||||
updated = hasUpdate = add;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
for (Score score1 : handledScores) {
|
||||
ScoreInfo scoreInfo = new ScoreInfo(score1.getId(), score1.getObjective().getObjectiveName(), score1.getScore(), score1.getDisplayName());
|
||||
addScores.add(scoreInfo);
|
||||
removeScores.add(scoreInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
addScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getScore(), score.getDisplayName()));
|
||||
}
|
||||
if (remove) {
|
||||
removeScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getOldScore(), score.getDisplayName()));
|
||||
}
|
||||
score.setOldScore(score.getScore());
|
||||
|
||||
if (score.getUpdateType() == REMOVE) {
|
||||
objective.removeScore(score.getName());
|
||||
}
|
||||
|
||||
if (add || remove) {
|
||||
changedObjectives.add(objective);
|
||||
} else { // stays the same like before
|
||||
handledScores.add(score);
|
||||
}
|
||||
score.setUpdateType(NOTHING);
|
||||
}
|
||||
}
|
||||
|
||||
for (Objective objective : changedObjectives) {
|
||||
boolean update = objective.getUpdateType() == NOTHING || objective.getUpdateType() == UPDATE;
|
||||
if (objective.getUpdateType() == REMOVE || update) {
|
||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
session.getUpstream().sendPacket(removeObjectivePacket);
|
||||
if (objective.getUpdateType() == REMOVE) {
|
||||
objectives.remove(objective.getObjectiveName()); // now we can deregister
|
||||
}
|
||||
}
|
||||
if (objective.getUpdateType() == ADD || update) {
|
||||
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||
displayObjectivePacket.setCriteria("dummy");
|
||||
displayObjectivePacket.setDisplaySlot(objective.getDisplaySlot());
|
||||
displayObjectivePacket.setSortOrder(1); // ??
|
||||
session.getUpstream().sendPacket(displayObjectivePacket);
|
||||
}
|
||||
objective.setUpdateType(NOTHING);
|
||||
}
|
||||
|
||||
if (!removeScores.isEmpty()) {
|
||||
SetScorePacket setScorePacket = new SetScorePacket();
|
||||
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
||||
setScorePacket.setInfos(removeScores);
|
||||
session.getUpstream().sendPacket(setScorePacket);
|
||||
}
|
||||
|
||||
if (!addScores.isEmpty()) {
|
||||
SetScorePacket setScorePacket = new SetScorePacket();
|
||||
setScorePacket.setAction(SetScorePacket.Action.SET);
|
||||
setScorePacket.setInfos(addScores);
|
||||
session.getUpstream().sendPacket(setScorePacket);
|
||||
}
|
||||
}
|
||||
|
||||
public void despawnObjective(Objective objective) {
|
||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
session.getUpstream().sendPacket(removeObjectivePacket);
|
||||
objectives.remove(objective.getDisplayName());
|
||||
|
||||
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||
displayObjectivePacket.setCriteria("dummy");
|
||||
displayObjectivePacket.setDisplaySlot("sidebar");
|
||||
displayObjectivePacket.setSortOrder(1);
|
||||
session.getUpstream().sendPacket(displayObjectivePacket);
|
||||
|
||||
Map<String, Score> fakeMap = new HashMap<String, Score>();
|
||||
for (Map.Entry<String, Score> entry : objective.getScores().entrySet()) {
|
||||
fakeMap.put(entry.getKey(), entry.getValue());
|
||||
List<ScoreInfo> toRemove = new ArrayList<>();
|
||||
for (String identifier : objective.getScores().keySet()) {
|
||||
Score score = objective.getScores().get(identifier);
|
||||
toRemove.add(new ScoreInfo(
|
||||
score.getId(), score.getObjective().getObjectiveName(),
|
||||
0, ""
|
||||
));
|
||||
}
|
||||
|
||||
for (String string : fakeMap.keySet()) {
|
||||
Score score = fakeMap.get(string);
|
||||
ScoreInfo scoreInfo = new ScoreInfo(score.getScoreboardId(), objective.getObjectiveName(), score.getScore(), score.getFakePlayer());
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
SetScorePacket setScorePacket = new SetScorePacket();
|
||||
setScorePacket.setAction(score.getAction());
|
||||
setScorePacket.setInfos(Arrays.asList(scoreInfo));
|
||||
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
||||
setScorePacket.setInfos(toRemove);
|
||||
session.getUpstream().sendPacket(setScorePacket);
|
||||
|
||||
if (score.getAction() == SetScorePacket.Action.REMOVE) {
|
||||
String id = score.getFakeId();
|
||||
objective.getScores().remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Team getTeamFor(String entity) {
|
||||
for (Team team : teams.values()) {
|
||||
if (team.getEntities().contains(entity)) {
|
||||
return team;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapted from: https://github.com/Ragnok123/GTScoreboard
|
||||
*/
|
||||
public class ScoreboardObjective {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private int scoreboardTick = 0;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String objectiveName;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private DisplaySlot displaySlot;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String displayName;
|
||||
|
||||
@Getter
|
||||
private Map<String, Score> scores = new HashMap<String, Score>();
|
||||
|
||||
public void registerScore(String id, String fake, int value) {
|
||||
registerScore(id, fake, value, SetScorePacket.Action.SET);
|
||||
}
|
||||
|
||||
public void registerScore(String id, String fake, int value, SetScorePacket.Action action) {
|
||||
Score score = new Score(this, fake);
|
||||
score.setScore(value);
|
||||
score.setFakeId(id);
|
||||
score.setAction(action);
|
||||
if (!scores.containsKey(id)) {
|
||||
scores.put(id, score);
|
||||
} else {
|
||||
setScore(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScore(String id, int value) {
|
||||
if (scores.containsKey(id)) {
|
||||
Score modifiedScore = scores.get(id);
|
||||
modifiedScore.setScore(value);
|
||||
scores.remove(id);
|
||||
scores.put(id, modifiedScore);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScoreText(String id, String text) {
|
||||
if (scores.containsKey(id)) {
|
||||
Score newScore = new Score(this, text);
|
||||
newScore.setScore(scores.get(id).getScore());
|
||||
newScore.setFakeId(id);
|
||||
scores.remove(id);
|
||||
scores.put(id, newScore);
|
||||
}
|
||||
}
|
||||
|
||||
public int getScore(String id) {
|
||||
int i = 0;
|
||||
if (scores.containsKey(id)) {
|
||||
Score score = scores.get(id);
|
||||
i = score.getScore();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public Score getScore(int line) {
|
||||
Score score = null;
|
||||
for (Map.Entry<String, Score> entry : scores.entrySet()) {
|
||||
if (entry.getValue().getScore() == line)
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void resetScore(String id) {
|
||||
if (scores.containsKey(id)) {
|
||||
Score modifiedScore = scores.get(id);
|
||||
modifiedScore.setAction(SetScorePacket.Action.REMOVE);
|
||||
scores.remove(id);
|
||||
scores.put(id, modifiedScore);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DisplaySlot {
|
||||
|
||||
SIDEBAR,
|
||||
LIST,
|
||||
BELOWNAME;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class Team {
|
||||
private final Scoreboard scoreboard;
|
||||
private final String id;
|
||||
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
private String name;
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
private Set<String> entities = new HashSet<>();
|
||||
|
||||
|
||||
public Team(Scoreboard scoreboard, String id) {
|
||||
this.scoreboard = scoreboard;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void addEntities(String... names) {
|
||||
List<String> added = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
if (!entities.contains(name)) {
|
||||
entities.add(name);
|
||||
added.add(name);
|
||||
}
|
||||
}
|
||||
setUpdateType(UpdateType.UPDATE);
|
||||
for (Objective objective : scoreboard.getObjectives().values()) {
|
||||
for (Score score : objective.getScores().values()) {
|
||||
if (added.contains(score.getName())) {
|
||||
score.setTeam(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntities(String... names) {
|
||||
for (String name : names) {
|
||||
entities.remove(name);
|
||||
}
|
||||
setUpdateType(UpdateType.UPDATE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.geysermc.connector.scoreboard;
|
||||
|
||||
public enum UpdateType {
|
||||
REMOVE,
|
||||
/**
|
||||
* Nothing has changed, it's cool
|
||||
*/
|
||||
NOTHING,
|
||||
ADD,
|
||||
/**
|
||||
* Hey, something has been updated!<br>
|
||||
* Only used in {@link Objective Objective}
|
||||
*/
|
||||
UPDATE
|
||||
}
|
|
@ -1,662 +0,0 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3d;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.*;
|
||||
|
||||
public class GeyserUtils {
|
||||
|
||||
public static final int FLAG_RUNTIME = 1;
|
||||
|
||||
public static final int GLOBAL_PALETTE_BITS_PER_BLOCK = 14;
|
||||
|
||||
public static final int SECTION_COUNT_BLOCKS = 16;
|
||||
|
||||
public static final int SECTION_COUNT_LIGHT = 18;
|
||||
|
||||
public static final int BLOCKS_IN_SECTION = 16 * 16 * 16;
|
||||
|
||||
public static final int LIGHT_DATA_LENGTH = BLOCKS_IN_SECTION / 2;
|
||||
|
||||
public static final int EMPTY_SUBCHUNK_BYTES = BLOCKS_IN_SECTION / 8;
|
||||
|
||||
public static final int SUBCHUNK_VERSION = 8;
|
||||
|
||||
public static void writeEmpty(ByteBuf to) {
|
||||
|
||||
to.writeByte(storageHeader(1));
|
||||
|
||||
to.writeZero(EMPTY_SUBCHUNK_BYTES);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected static final int storageHeader(int bitsPerBlock) {
|
||||
|
||||
return (bitsPerBlock << 1) | FLAG_RUNTIME;
|
||||
|
||||
}
|
||||
|
||||
public static void writeEmptySubChunk(ByteBuf out) {
|
||||
|
||||
out.writeBytes(new byte[4096 + 4096]);
|
||||
|
||||
}
|
||||
|
||||
public static void skipPosition(ByteBuf from) {
|
||||
from.skipBytes(Long.BYTES);
|
||||
}
|
||||
|
||||
public static Vector3d readPosition(ByteBuf from) {
|
||||
long l = from.readLong();
|
||||
return new Vector3d(
|
||||
(int) (l >> 38), (int) (l & 0xFFF), (int) ((l << 26) >> 38)
|
||||
);
|
||||
}
|
||||
|
||||
public static void readPEPosition(ByteBuf from) {
|
||||
readSVarInt(from);
|
||||
readVarInt(from);
|
||||
readSVarInt(from);
|
||||
}
|
||||
|
||||
public static Vector3d readLegacyPositionI(ByteBuf from) {
|
||||
return new Vector3d(from.readInt(), from.readInt(), from.readInt());
|
||||
}
|
||||
|
||||
public static void writePosition(ByteBuf to, Vector3i position) {
|
||||
to.writeLong(((position.getX() & 0x3FFFFFFL) << 38) | ((position.getZ() & 0x3FFFFFFL) << 12) | (position.getY() & 0xFFFL));
|
||||
}
|
||||
|
||||
public static void writeLegacyPositionL(ByteBuf to, Vector3d position) {
|
||||
to.writeLong((((int) position.getX() & 0x3FFFFFFL) << 38) | (((int) position.getY() & 0xFFFL) << 26) | ((int) position.getZ() & 0x3FFFFFFL));
|
||||
}
|
||||
|
||||
public static void writePEPosition(ByteBuf to, Vector3d position) {
|
||||
writeSVarInt(to, (int) position.getX());
|
||||
writeVarInt(to, (int) position.getY());
|
||||
writeSVarInt(to, (int) position.getZ());
|
||||
}
|
||||
|
||||
public static void writeLegacyPositionB(ByteBuf to, Vector3d position) {
|
||||
to.writeInt((int) position.getX());
|
||||
to.writeByte((int) position.getY());
|
||||
to.writeInt((int) position.getZ());
|
||||
}
|
||||
|
||||
public static void writeLegacyPositionS(ByteBuf to, Vector3d position) {
|
||||
to.writeInt((int) position.getX());
|
||||
to.writeShort((int) position.getY());
|
||||
to.writeInt((int) position.getZ());
|
||||
}
|
||||
|
||||
public static void writeLegacyPositionI(ByteBuf to, Vector3d position) {
|
||||
to.writeInt((int) position.getX());
|
||||
to.writeInt((int) position.getY());
|
||||
to.writeInt((int) position.getZ());
|
||||
}
|
||||
|
||||
public static Vector2i readIntChunkCoord(ByteBuf from) {
|
||||
return new Vector2i(from.readInt(), from.readInt());
|
||||
}
|
||||
|
||||
public static Vector2i readVarIntChunkCoord(ByteBuf from) {
|
||||
return new Vector2i(readVarInt(from), readVarInt(from));
|
||||
}
|
||||
|
||||
public static void writeIntChunkCoord(ByteBuf to, Vector2i chunk) {
|
||||
to.writeInt(chunk.getX());
|
||||
to.writeInt(chunk.getY());
|
||||
}
|
||||
|
||||
public static Vector2i readPEChunkCoord(ByteBuf from) {
|
||||
return new Vector2i(readSVarInt(from), readSVarInt(from));
|
||||
}
|
||||
|
||||
public static void writePEChunkCoord(ByteBuf to, Vector2i chunk) {
|
||||
writeSVarInt(to, chunk.getX());
|
||||
writeSVarInt(to, chunk.getY());
|
||||
}
|
||||
|
||||
public static int readLocalCoord(ByteBuf from) {
|
||||
return from.readUnsignedShort();
|
||||
}
|
||||
|
||||
public static void writeLocalCoord(ByteBuf to, int coord) {
|
||||
to.writeShort(coord);
|
||||
}
|
||||
|
||||
public static void writeVarIntChunkCoord(ByteBuf to, Vector2i chunk) {
|
||||
writeVarInt(to, chunk.getX());
|
||||
writeVarInt(to, chunk.getY());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final int MAX_LENGTH = 5;
|
||||
|
||||
|
||||
|
||||
public static void writeFixedSizeVarInt(ByteBuf to, int i) {
|
||||
|
||||
int writerIndex = to.writerIndex();
|
||||
|
||||
while ((i & 0xFFFFFF80) != 0x0) {
|
||||
|
||||
to.writeByte(i | 0x80);
|
||||
|
||||
i >>>= 7;
|
||||
|
||||
}
|
||||
|
||||
int paddingBytes = MAX_LENGTH - (to.writerIndex() - writerIndex) - 1;
|
||||
|
||||
if (paddingBytes == 0) {
|
||||
|
||||
to.writeByte(i);
|
||||
|
||||
} else {
|
||||
|
||||
to.writeByte(i | 0x80);
|
||||
|
||||
while (--paddingBytes > 0) {
|
||||
|
||||
to.writeByte(0x80);
|
||||
|
||||
}
|
||||
|
||||
to.writeByte(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int readVarInt(ByteBuf from) {
|
||||
|
||||
int value = 0;
|
||||
|
||||
int length = 0;
|
||||
|
||||
byte part;
|
||||
|
||||
do {
|
||||
|
||||
part = from.readByte();
|
||||
|
||||
value |= (part & 0x7F) << (length++ * 7);
|
||||
|
||||
if (length > MAX_LENGTH) {
|
||||
|
||||
throw new DecoderException("VarInt too big");
|
||||
|
||||
}
|
||||
|
||||
} while (part < 0);
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeVarInt(ByteBuf to, int i) {
|
||||
|
||||
while ((i & 0xFFFFFF80) != 0x0) {
|
||||
|
||||
to.writeByte(i | 0x80);
|
||||
|
||||
i >>>= 7;
|
||||
|
||||
}
|
||||
|
||||
to.writeByte(i);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int readSVarInt(ByteBuf from) {
|
||||
|
||||
int varint = readVarInt(from);
|
||||
|
||||
return (varint >> 1) ^ -(varint & 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeSVarInt(ByteBuf to, int varint) {
|
||||
|
||||
writeVarInt(to, (varint << 1) ^ (varint >> 31));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static long readVarLong(ByteBuf from) {
|
||||
|
||||
long varlong = 0L;
|
||||
|
||||
int length = 0;
|
||||
|
||||
byte part;
|
||||
|
||||
do {
|
||||
|
||||
part = from.readByte();
|
||||
|
||||
varlong |= (part & 0x7F) << (length++ * 7);
|
||||
|
||||
if (length > 10) {
|
||||
|
||||
throw new RuntimeException("VarLong too big");
|
||||
|
||||
}
|
||||
|
||||
} while ((part & 0x80) == 0x80);
|
||||
|
||||
return varlong;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeVarLong(ByteBuf to, long varlong) {
|
||||
|
||||
while ((varlong & 0xFFFFFFFFFFFFFF80L) != 0x0L) {
|
||||
|
||||
to.writeByte((int) (varlong & 0x7FL) | 0x80);
|
||||
|
||||
varlong >>>= 7;
|
||||
|
||||
}
|
||||
|
||||
to.writeByte((int) varlong);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static long readSVarLong(ByteBuf from) {
|
||||
|
||||
long varlong = readVarLong(from);
|
||||
|
||||
return (varlong >> 1) ^ -(varlong & 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeSVarLong(ByteBuf to, long varlong) {
|
||||
|
||||
writeVarLong(to, (varlong << 1) ^ (varlong >> 63));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static ByteBuf readShortByteArraySlice(ByteBuf from, int limit) {
|
||||
|
||||
int length = from.readShort();
|
||||
|
||||
checkLimit(length, limit);
|
||||
|
||||
return from.readSlice(length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
public static <T> T[] readShortTArray(ByteBuf from, Class<T> tclass, Function<ByteBuf, T> elementReader) {
|
||||
|
||||
T[] array = (T[]) Array.newInstance(tclass, from.readShort());
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
|
||||
array[i] = elementReader.apply(from);
|
||||
|
||||
}
|
||||
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte[] readVarIntByteArray(ByteBuf from) {
|
||||
|
||||
return readBytes(from, readVarInt(from));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ByteBuf readVarIntByteArraySlice(ByteBuf from, int limit) {
|
||||
|
||||
int length = readVarInt(from);
|
||||
|
||||
checkLimit(length, limit);
|
||||
|
||||
return from.readSlice(length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ByteBuf readVarIntByteArraySlice(ByteBuf from) {
|
||||
|
||||
return from.readSlice(readVarInt(from));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
public static <T> T[] readVarIntTArray(ByteBuf from, Class<T> tclass, Function<ByteBuf, T> elementReader) {
|
||||
|
||||
T[] array = (T[]) Array.newInstance(tclass, readVarInt(from));
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
|
||||
array[i] = elementReader.apply(from);
|
||||
|
||||
}
|
||||
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int[] readVarIntVarIntArray(ByteBuf from) {
|
||||
|
||||
int[] array = new int[readVarInt(from)];
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
|
||||
array[i] = readVarInt(from);
|
||||
|
||||
}
|
||||
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static void writeShortByteArray(ByteBuf to, ByteBuf data) {
|
||||
|
||||
to.writeShort(data.readableBytes());
|
||||
|
||||
to.writeBytes(data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeShortByteArray(ByteBuf to, byte[] data) {
|
||||
|
||||
to.writeShort(data.length);
|
||||
|
||||
to.writeBytes(data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeShortByteArray(ByteBuf to, Consumer<ByteBuf> dataWriter) {
|
||||
|
||||
writeLengthPrefixedBytes(to, (lTo, length) -> lTo.writeShort(length), dataWriter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <T> void writeShortTArray(ByteBuf to, T[] array, BiConsumer<ByteBuf, T> elementWriter) {
|
||||
|
||||
to.writeShort(array.length);
|
||||
|
||||
for (T element : array) {
|
||||
|
||||
elementWriter.accept(to, element);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static void writeVarIntByteArray(ByteBuf to, ByteBuf data) {
|
||||
|
||||
writeVarInt(to, data.readableBytes());
|
||||
|
||||
to.writeBytes(data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeVarIntByteArray(ByteBuf to, byte[] data) {
|
||||
|
||||
writeVarInt(to, data.length);
|
||||
|
||||
to.writeBytes(data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeVarIntByteArray(ByteBuf to, Consumer<ByteBuf> dataWriter) {
|
||||
|
||||
writeLengthPrefixedBytes(to, GeyserUtils::writeFixedSizeVarInt, dataWriter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeVarIntTArray(ByteBuf to, ToIntFunction<ByteBuf> arrayWriter) {
|
||||
|
||||
writeSizePrefixedData(to, GeyserUtils::writeFixedSizeVarInt, arrayWriter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <T> void writeVarIntTArray(ByteBuf to, T[] array, BiConsumer<ByteBuf, T> elementWriter) {
|
||||
|
||||
writeVarInt(to, array.length);
|
||||
|
||||
for (T element : array) {
|
||||
|
||||
elementWriter.accept(to, element);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <T> void writeVarIntTArray(ByteBuf to, List<T> array, BiConsumer<ByteBuf, T> elementWriter) {
|
||||
|
||||
writeVarInt(to, array.size());
|
||||
|
||||
for (T element : array) {
|
||||
|
||||
elementWriter.accept(to, element);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void writeVarIntEnum(ByteBuf to, Enum<?> e) {
|
||||
|
||||
writeVarInt(to, e.ordinal());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeByteEnum(ByteBuf to, Enum<?> e) {
|
||||
|
||||
to.writeByte(e.ordinal());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static UUID readUUID(ByteBuf from) {
|
||||
|
||||
return new UUID(from.readLong(), from.readLong());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeUUID(ByteBuf to, UUID uuid) {
|
||||
|
||||
to.writeLong(uuid.getMostSignificantBits());
|
||||
|
||||
to.writeLong(uuid.getLeastSignificantBits());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writePEUUID(ByteBuf to, UUID uuid) {
|
||||
|
||||
to.writeLongLE(uuid.getMostSignificantBits());
|
||||
|
||||
to.writeLongLE(uuid.getLeastSignificantBits());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static byte[] readAllBytes(ByteBuf buf) {
|
||||
|
||||
return readBytes(buf, buf.readableBytes());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ByteBuf readAllBytesSlice(ByteBuf from) {
|
||||
|
||||
return from.readSlice(from.readableBytes());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ByteBuf readAllBytesSlice(ByteBuf buf, int limit) {
|
||||
|
||||
checkLimit(buf.readableBytes(), limit);
|
||||
|
||||
return readAllBytesSlice(buf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static byte[] readBytes(ByteBuf buf, int length) {
|
||||
|
||||
byte[] result = new byte[length];
|
||||
|
||||
buf.readBytes(result);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected static void checkLimit(int length, int limit) {
|
||||
|
||||
if (length > limit) {
|
||||
|
||||
throw new DecoderException(MessageFormat.format("Size {0} is bigger than allowed {1}", length, limit));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeLengthPrefixedBytes(ByteBuf to, ObjIntConsumer<ByteBuf> lengthWriter, Consumer<ByteBuf> dataWriter) {
|
||||
|
||||
int lengthWriterIndex = to.writerIndex();
|
||||
|
||||
lengthWriter.accept(to, 0);
|
||||
|
||||
int writerIndexDataStart = to.writerIndex();
|
||||
|
||||
dataWriter.accept(to);
|
||||
|
||||
int writerIndexDataEnd = to.writerIndex();
|
||||
|
||||
to.writerIndex(lengthWriterIndex);
|
||||
|
||||
lengthWriter.accept(to, writerIndexDataEnd - writerIndexDataStart);
|
||||
|
||||
to.writerIndex(writerIndexDataEnd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void writeSizePrefixedData(ByteBuf to, ObjIntConsumer<ByteBuf> sizeWriter, ToIntFunction<ByteBuf> dataWriter) {
|
||||
|
||||
int sizeWriterIndex = to.writerIndex();
|
||||
|
||||
sizeWriter.accept(to, 0);
|
||||
|
||||
int size = dataWriter.applyAsInt(to);
|
||||
|
||||
int writerIndexDataEnd = to.writerIndex();
|
||||
|
||||
to.writerIndex(sizeWriterIndex);
|
||||
|
||||
sizeWriter.accept(to, size);
|
||||
|
||||
to.writerIndex(writerIndexDataEnd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static int getAnvilIndex(int x, int y, int z) {
|
||||
|
||||
return (y << 8) + (z << 4) + x;
|
||||
|
||||
}
|
||||
|
||||
public static <T> boolean instanceOf(Class<T> clazz, Object o) {
|
||||
try {
|
||||
T t = (T) o;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -110,13 +110,4 @@ public class InventoryUtils {
|
|||
items[packet.getSlot()] = packet.getItem();
|
||||
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();
|
||||
SecretKey encryptionKey = EncryptionUtils.getSecretKey(serverKeyPair.getPrivate(), key, token);
|
||||
session.getUpstream().enableEncryption(encryptionKey);
|
||||
session.getUpstream().getSession().enableEncryption(encryptionKey);
|
||||
|
||||
ServerToClientHandshakePacket packet = new ServerToClientHandshakePacket();
|
||||
packet.setJwt(EncryptionUtils.createHandshakeJwt(serverKeyPair, token).serialize());
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.codec.Charsets;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@Getter
|
||||
public class ProvidedSkinData {
|
||||
private static final Gson gson = new GsonBuilder().create();
|
||||
private String skinId;
|
||||
private String skinName;
|
||||
private String geometryId;
|
||||
private ObjectNode geometryData;
|
||||
|
||||
public static ProvidedSkinData getProvidedSkin(String skinName) {
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
|
||||
return objectMapper.readValue(ProvidedSkinData.class.getClassLoader().getResource(skinName), ProvidedSkinData.class);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getGeometryDataEncoded() {
|
||||
try {
|
||||
return new String(Base64.getEncoder().encode(geometryData.toString().getBytes(Charsets.UTF_8)));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,20 +3,15 @@ package org.geysermc.connector.utils;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.block.JavaBlock;
|
||||
import org.geysermc.connector.network.translators.block.type.*;
|
||||
import org.geysermc.connector.network.translators.item.BedrockItem;
|
||||
import org.geysermc.connector.network.translators.item.JavaItem;
|
||||
import org.geysermc.connector.network.translators.block.type.ColoredBlock;
|
||||
import org.geysermc.connector.network.translators.block.type.DyeColor;
|
||||
import org.geysermc.connector.network.translators.block.type.StoneType;
|
||||
import org.geysermc.connector.network.translators.block.type.WoodBlock;
|
||||
import org.geysermc.connector.network.translators.block.type.WoodType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Remapper {
|
||||
|
||||
public static final String MINECRAFT = "minecraft:";
|
||||
public static final String MINECRAFT_PREFIX = "minecraft:";
|
||||
|
||||
public static final Remapper ITEM_REMAPPER = new Remapper();
|
||||
public static final Remapper BLOCK_REMAPPER = new Remapper();
|
||||
|
@ -37,7 +32,7 @@ public class Remapper {
|
|||
|
||||
// Colorable block remapping
|
||||
for (ColoredBlock coloredBlock : ColoredBlock.values()) {
|
||||
if (!getBedrockIdentifier(coloredBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT, "")))
|
||||
if (!getBedrockIdentifier(coloredBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "")))
|
||||
continue;
|
||||
|
||||
// The item must be colorable
|
||||
|
@ -46,13 +41,13 @@ public class Remapper {
|
|||
continue;
|
||||
|
||||
// Add the color to the identifier
|
||||
identifier = MINECRAFT + color.name().toLowerCase() + "_" + coloredBlock.name().toLowerCase();
|
||||
identifier = MINECRAFT_PREFIX + color.name().toLowerCase() + "_" + coloredBlock.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
// Wood remapping
|
||||
for (WoodBlock woodBlock : WoodBlock.values()) {
|
||||
if (!getBedrockIdentifier(woodBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT, "")))
|
||||
if (!getBedrockIdentifier(woodBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "")))
|
||||
continue;
|
||||
|
||||
if (isTool(bedrockItem.getIdentifier()))
|
||||
|
@ -65,36 +60,36 @@ public class Remapper {
|
|||
if (woodType.getId() != bedrockItem.getData())
|
||||
continue;
|
||||
|
||||
identifier = MINECRAFT + woodType.name().toLowerCase() + "_" + woodBlock.name().toLowerCase();
|
||||
identifier = MINECRAFT_PREFIX + woodType.name().toLowerCase() + "_" + woodBlock.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
// Stone remapping
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("stone") && !isTool(bedrockItem.getIdentifier())) {
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "").equalsIgnoreCase("stone") && !isTool(bedrockItem.getIdentifier())) {
|
||||
for (StoneType stoneType : StoneType.values()) {
|
||||
if (stoneType.getId() != bedrockItem.getData())
|
||||
continue;
|
||||
|
||||
// Set the identifier to stone
|
||||
identifier = MINECRAFT + stoneType.name().toLowerCase();
|
||||
identifier = MINECRAFT_PREFIX + stoneType.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
// Grass remapping
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("grass")) {
|
||||
identifier = MINECRAFT + "grass_block";
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "").equalsIgnoreCase("grass")) {
|
||||
identifier = MINECRAFT_PREFIX + "grass_block";
|
||||
}
|
||||
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("tallgrass")) {
|
||||
identifier = MINECRAFT + "grass";
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "").equalsIgnoreCase("tallgrass")) {
|
||||
identifier = MINECRAFT_PREFIX + "grass";
|
||||
}
|
||||
|
||||
// Dirt remapping
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("dirt")) {
|
||||
if (bedrockItem.getIdentifier().replace(MINECRAFT_PREFIX, "").equalsIgnoreCase("dirt")) {
|
||||
if (bedrockItem.getData() == 0)
|
||||
identifier = MINECRAFT + "dirt";
|
||||
identifier = MINECRAFT_PREFIX + "dirt";
|
||||
else
|
||||
identifier = MINECRAFT + "coarse_dirt";
|
||||
identifier = MINECRAFT_PREFIX + "coarse_dirt";
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, ? extends JavaItem> javaItemEntry : javaItems.entrySet()) {
|
||||
|
@ -115,34 +110,19 @@ public class Remapper {
|
|||
|
||||
return bedrockToJava.get(bedrockItem.getValue());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public BedrockItem convertToBedrock(ItemStack item) {
|
||||
for (Map.Entry<Integer, JavaItem> javaItem : Toolbox.JAVA_ITEMS.entrySet()) {
|
||||
if (javaItem.getValue().getId() != item.getId())
|
||||
continue;
|
||||
|
||||
return javaToBedrock.get(javaItem.getValue());
|
||||
}
|
||||
|
||||
return null;
|
||||
JavaItem javaItem = Toolbox.JAVA_ITEMS.get(item.getId());
|
||||
return javaItem != null ? javaToBedrock.get(javaItem) : null;
|
||||
}
|
||||
|
||||
public BedrockItem convertToBedrockB(ItemStack block) {
|
||||
for (Map.Entry<Integer, JavaBlock> javaItem : Toolbox.JAVA_BLOCKS.entrySet()) {
|
||||
if (javaItem.getValue().getId() != block.getId())
|
||||
continue;
|
||||
|
||||
return javaToBedrock.get(javaItem.getValue());
|
||||
}
|
||||
|
||||
return null;
|
||||
JavaBlock javaBlock = Toolbox.JAVA_BLOCKS.get(block.getId());
|
||||
return javaBlock != null ? javaToBedrock.get(javaBlock) : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String getBedrockIdentifier(String javaIdentifier) {
|
||||
javaIdentifier = javaIdentifier.toLowerCase();
|
||||
javaIdentifier = javaIdentifier.replace("terracotta", "stained_hardened_clay");
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class SkinProvider {
|
||||
public 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);
|
||||
|
||||
public static final Skin EMPTY_SKIN = new Skin(-1, "");
|
||||
public static final byte[] STEVE_SKIN = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin();
|
||||
private static Map<UUID, Skin> cachedSkins = 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 final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes
|
||||
|
||||
public static boolean hasSkinCached(UUID uuid) {
|
||||
return cachedSkins.containsKey(uuid);
|
||||
}
|
||||
|
||||
public static boolean hasCapeCached(String capeUrl) {
|
||||
return cachedCapes.containsKey(capeUrl);
|
||||
}
|
||||
|
||||
public static Skin getCachedSkin(UUID uuid) {
|
||||
return cachedSkins.getOrDefault(uuid, EMPTY_SKIN);
|
||||
}
|
||||
|
||||
public static Cape getCachedCape(String capeUrl) {
|
||||
return capeUrl != null ? cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE) : EMPTY_CAPE;
|
||||
}
|
||||
|
||||
public static CompletableFuture<SkinAndCape> requestSkinAndCape(UUID playerId, String skinUrl, String capeUrl) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
SkinAndCape skinAndCape = new SkinAndCape(
|
||||
getOrDefault(requestSkin(playerId, skinUrl, false), EMPTY_SKIN, 5),
|
||||
getOrDefault(requestCape(capeUrl, false), EMPTY_CAPE, 5)
|
||||
);
|
||||
|
||||
Geyser.getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId);
|
||||
return skinAndCape;
|
||||
}, EXECUTOR_SERVICE);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Skin> requestSkin(UUID playerId, String textureUrl, boolean newThread) {
|
||||
if (textureUrl == null || textureUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_SKIN);
|
||||
if (requestedSkins.containsKey(playerId)) return requestedSkins.get(playerId); // already requested
|
||||
|
||||
if ((System.currentTimeMillis() - CACHE_INTERVAL) < cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getRequestedOn()) {
|
||||
// no need to update, still cached
|
||||
return CompletableFuture.completedFuture(cachedSkins.get(playerId));
|
||||
}
|
||||
|
||||
CompletableFuture<Skin> future;
|
||||
if (newThread) {
|
||||
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE)
|
||||
.whenCompleteAsync((skin, throwable) -> {
|
||||
if (!cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getTextureUrl().equals(textureUrl)) {
|
||||
skin.updated = true;
|
||||
cachedSkins.put(playerId, skin);
|
||||
}
|
||||
requestedSkins.remove(skin.getSkinOwner());
|
||||
});
|
||||
requestedSkins.put(playerId, future);
|
||||
} else {
|
||||
Skin skin = supplySkin(playerId, textureUrl);
|
||||
future = CompletableFuture.completedFuture(skin);
|
||||
cachedSkins.put(playerId, skin);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public static CompletableFuture<Cape> requestCape(String capeUrl, boolean newThread) {
|
||||
if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE);
|
||||
if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested
|
||||
|
||||
boolean officialCape = capeUrl.startsWith("https://textures.minecraft.net");
|
||||
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));
|
||||
}
|
||||
|
||||
CompletableFuture<Cape> future;
|
||||
if (newThread) {
|
||||
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl), EXECUTOR_SERVICE)
|
||||
.whenCompleteAsync((cape, throwable) -> {
|
||||
cachedCapes.put(capeUrl, cape);
|
||||
requestedCapes.remove(capeUrl);
|
||||
});
|
||||
requestedCapes.put(capeUrl, future);
|
||||
} else {
|
||||
Cape cape = supplyCape(capeUrl); // blocking
|
||||
future = CompletableFuture.completedFuture(cape);
|
||||
cachedCapes.put(capeUrl, cape);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public static CompletableFuture<Cape> requestUnofficialCape(Cape officialCape, UUID playerId,
|
||||
String username, boolean newThread) {
|
||||
if (officialCape.isFailed() && ALLOW_THIRD_PARTY_CAPES) {
|
||||
for (UnofficalCape cape : UnofficalCape.VALUES) {
|
||||
Cape cape1 = getOrDefault(
|
||||
requestCape(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) {
|
||||
byte[] skin = EMPTY_SKIN.getSkinData();
|
||||
try {
|
||||
skin = requestImage(textureUrl, false);
|
||||
} catch (Exception ignored) {} // just ignore I guess
|
||||
return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false);
|
||||
}
|
||||
|
||||
private static Cape supplyCape(String capeUrl) {
|
||||
byte[] cape = new byte[0];
|
||||
try {
|
||||
cape = requestImage(capeUrl, true);
|
||||
} catch (Exception ignored) {} // just ignore I guess
|
||||
|
||||
return new Cape(
|
||||
capeUrl,
|
||||
cape.length > 0 ? cape : EMPTY_CAPE.getCapeData(),
|
||||
System.currentTimeMillis(),
|
||||
cape.length == 0
|
||||
);
|
||||
}
|
||||
|
||||
private static byte[] requestImage(String imageUrl, boolean cape) throws Exception {
|
||||
BufferedImage image = ImageIO.read(new URL(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);
|
||||
try {
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
int rgba = image.getRGB(x, y);
|
||||
outputStream.write((rgba >> 16) & 0xFF);
|
||||
outputStream.write((rgba >> 8) & 0xFF);
|
||||
outputStream.write(rgba & 0xFF);
|
||||
outputStream.write((rgba >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
image.flush();
|
||||
return outputStream.toByteArray();
|
||||
} finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@Getter
|
||||
public static class SkinAndCape {
|
||||
private Skin skin;
|
||||
private Cape cape;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class Skin {
|
||||
private UUID skinOwner;
|
||||
private String textureUrl;
|
||||
private byte[] skinData = STEVE_SKIN;
|
||||
private long requestedOn;
|
||||
private boolean updated;
|
||||
|
||||
private Skin(long requestedOn, String textureUrl) {
|
||||
this.requestedOn = requestedOn;
|
||||
this.textureUrl = textureUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class Cape {
|
||||
private String textureUrl;
|
||||
private byte[] capeData;
|
||||
private long requestedOn;
|
||||
private boolean failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sorted by 'priority'
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.codec.Charsets;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SkinUtils {
|
||||
public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long geyserId) {
|
||||
GameProfileData data = GameProfileData.from(profile);
|
||||
|
||||
return buildEntryManually(
|
||||
profile.getId(),
|
||||
profile.getName(),
|
||||
geyserId,
|
||||
profile.getIdAsString(),
|
||||
SkinProvider.getCachedSkin(profile.getId()).getSkinData(),
|
||||
SkinProvider.getCachedCape(data.getCapeUrl()).getCapeData(),
|
||||
"geometry.humanoid.custom" + (data.isAlex() ? "Slim" : ""),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
public static PlayerListPacket.Entry buildDefaultEntry(GameProfile profile, long geyserId) {
|
||||
return buildEntryManually(
|
||||
profile.getId(),
|
||||
profile.getName(),
|
||||
geyserId,
|
||||
profile.getIdAsString(),
|
||||
SkinProvider.STEVE_SKIN,
|
||||
SkinProvider.EMPTY_CAPE.getCapeData(),
|
||||
"geometry.humanoid",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
public static PlayerListPacket.Entry buildEntryManually(UUID uuid, String username, long geyserId,
|
||||
String skinId, byte[] skinData, byte[] capeData,
|
||||
String geometryName, String geometryData) {
|
||||
PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid);
|
||||
entry.setName(username);
|
||||
entry.setEntityId(geyserId);
|
||||
entry.setSkinId(skinId);
|
||||
entry.setSkinData(skinData != null ? skinData : SkinProvider.STEVE_SKIN);
|
||||
entry.setCapeData(capeData);
|
||||
entry.setGeometryName(geometryName);
|
||||
entry.setGeometryData(geometryData);
|
||||
entry.setXuid("");
|
||||
entry.setPlatformChatId("");
|
||||
return entry;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class GameProfileData {
|
||||
private String skinUrl;
|
||||
private String capeUrl;
|
||||
private boolean alex;
|
||||
|
||||
public static GameProfileData from(GameProfile profile) {
|
||||
try {
|
||||
GameProfile.Property skinProperty = profile.getProperty("textures");
|
||||
|
||||
JsonObject skinObject = SkinProvider.GSON.fromJson(new String(Base64.getDecoder().decode(skinProperty.getValue()), Charsets.UTF_8), JsonObject.class);
|
||||
JsonObject textures = skinObject.getAsJsonObject("textures");
|
||||
|
||||
JsonObject skinTexture = textures.getAsJsonObject("SKIN");
|
||||
String skinUrl = skinTexture.get("url").getAsString();
|
||||
|
||||
boolean isAlex = skinTexture.has("metadata");
|
||||
|
||||
String capeUrl = null;
|
||||
if (textures.has("CAPE")) {
|
||||
JsonObject capeTexture = textures.getAsJsonObject("CAPE");
|
||||
capeUrl = capeTexture.get("url").getAsString();
|
||||
}
|
||||
|
||||
return new GameProfileData(skinUrl, capeUrl, isAlex);
|
||||
} catch (Exception exception) {
|
||||
// return default skin with default cape when texture data is invalid
|
||||
Geyser.getLogger().debug("Got invalid texture data for " + profile.getName() + " " + exception.getMessage());
|
||||
return new GameProfileData("", "", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session,
|
||||
Consumer<SkinProvider.SkinAndCape> skinAndCapeConsumer) {
|
||||
Geyser.getGeneralThreadPool().execute(() -> {
|
||||
SkinUtils.GameProfileData data = SkinUtils.GameProfileData.from(entity.getProfile());
|
||||
|
||||
SkinProvider.requestSkinAndCape(entity.getUuid(), data.getSkinUrl(), data.getCapeUrl())
|
||||
.whenCompleteAsync((skinAndCape, throwable) -> {
|
||||
try {
|
||||
SkinProvider.Skin skin = skinAndCape.getSkin();
|
||||
SkinProvider.Cape cape = skinAndCape.getCape();
|
||||
|
||||
if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) {
|
||||
cape = SkinProvider.getOrDefault(SkinProvider.requestUnofficialCape(
|
||||
cape, entity.getUuid(),
|
||||
entity.getUsername(), false
|
||||
), SkinProvider.EMPTY_CAPE, SkinProvider.UnofficalCape.VALUES.length * 3);
|
||||
}
|
||||
|
||||
if (entity.getLastSkinUpdate() < skin.getRequestedOn()) {
|
||||
entity.setLastSkinUpdate(skin.getRequestedOn());
|
||||
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
PlayerListPacket.Entry updatedEntry = SkinUtils.buildEntryManually(
|
||||
entity.getUuid(),
|
||||
entity.getUsername(),
|
||||
entity.getGeyserId(),
|
||||
entity.getUuid().toString(),
|
||||
skin.getSkinData(),
|
||||
cape.getCapeData(),
|
||||
"geometry.humanoid.custom" + (data.isAlex() ? "Slim" : ""),
|
||||
""
|
||||
);
|
||||
|
||||
PlayerListPacket playerRemovePacket = new PlayerListPacket();
|
||||
playerRemovePacket.setType(PlayerListPacket.Type.REMOVE);
|
||||
playerRemovePacket.getEntries().add(updatedEntry);
|
||||
session.getUpstream().sendPacket(playerRemovePacket);
|
||||
|
||||
PlayerListPacket playerAddPacket = new PlayerListPacket();
|
||||
playerAddPacket.setType(PlayerListPacket.Type.ADD);
|
||||
playerAddPacket.getEntries().add(updatedEntry);
|
||||
session.getUpstream().sendPacket(playerAddPacket);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Geyser.getLogger().error("Failed getting skin for " + entity.getUuid(), e);
|
||||
}
|
||||
|
||||
if (skinAndCapeConsumer != null) skinAndCapeConsumer.accept(skinAndCape);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,383 +0,0 @@
|
|||
{
|
||||
"skinId" : "c18e65aa-7b21-4637-9b63-8ad63622ef01_Custom",
|
||||
"skinName" : "skin.Standard.Custom",
|
||||
"geometryId" : "geometry.humanoid.custom",
|
||||
"geometryData" :
|
||||
{
|
||||
"geometry.humanoid": {
|
||||
"bones": [
|
||||
{
|
||||
"name": "body",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -4.0, 12.0, -2.0 ],
|
||||
"size": [ 8, 12, 4 ],
|
||||
"uv": [ 16, 16 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "waist",
|
||||
"neverRender": true,
|
||||
"pivot": [ 0.0, 12.0, 0.0 ]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "head",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -4.0, 24.0, -4.0 ],
|
||||
"size": [ 8, 8, 8 ],
|
||||
"uv": [ 0, 0 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "hat",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -4.0, 24.0, -4.0 ],
|
||||
"size": [ 8, 8, 8 ],
|
||||
"uv": [ 32, 0 ],
|
||||
"inflate": 0.5
|
||||
}
|
||||
],
|
||||
"neverRender": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightArm",
|
||||
"pivot": [ -5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -8.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 40, 16 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftArm",
|
||||
"pivot": [ 5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ 4.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 40, 16 ]
|
||||
}
|
||||
],
|
||||
"mirror": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightLeg",
|
||||
"pivot": [ -1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -3.9, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 16 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftLeg",
|
||||
"pivot": [ 1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 16 ]
|
||||
}
|
||||
],
|
||||
"mirror": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"geometry.cape": {
|
||||
"texturewidth": 64,
|
||||
"textureheight": 32,
|
||||
|
||||
"bones": [
|
||||
{
|
||||
"name": "cape",
|
||||
"pivot": [ 0.0, 24.0, -3.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -5.0, 8.0, -3.0 ],
|
||||
"size": [ 10, 16, 1 ],
|
||||
"uv": [ 0, 0 ]
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
}
|
||||
]
|
||||
},
|
||||
"geometry.humanoid.custom:geometry.humanoid": {
|
||||
"bones": [
|
||||
{
|
||||
"name": "hat",
|
||||
"neverRender": false,
|
||||
"material": "alpha",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ]
|
||||
},
|
||||
{
|
||||
"name": "leftArm",
|
||||
"reset": true,
|
||||
"mirror": false,
|
||||
"pivot": [ 5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ 4.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 32, 48 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightArm",
|
||||
"reset": true,
|
||||
"pivot": [ -5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -8.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 40, 16 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightItem",
|
||||
"pivot": [ -6, 15, 1 ],
|
||||
"neverRender": true,
|
||||
"parent": "rightArm"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftSleeve",
|
||||
"pivot": [ 5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ 4.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 48, 48 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightSleeve",
|
||||
"pivot": [ -5.0, 22.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -8.0, 12.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 40, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftLeg",
|
||||
"reset": true,
|
||||
"mirror": false,
|
||||
"pivot": [ 1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 16, 48 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftPants",
|
||||
"pivot": [ 1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 48 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"pos": [ 1.9, 12, 0 ],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightPants",
|
||||
"pivot": [ -1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -3.9, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"pos": [ -1.9, 12, 0 ],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "jacket",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -4.0, 12.0, -2.0 ],
|
||||
"size": [ 8, 12, 4 ],
|
||||
"uv": [ 16, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
}
|
||||
]
|
||||
},
|
||||
"geometry.humanoid.customSlim:geometry.humanoid": {
|
||||
|
||||
"bones": [
|
||||
{
|
||||
"name": "hat",
|
||||
"neverRender": false,
|
||||
"material": "alpha"
|
||||
},
|
||||
{
|
||||
"name": "leftArm",
|
||||
"reset": true,
|
||||
"mirror": false,
|
||||
"pivot": [ 5.0, 21.5, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ 4.0, 11.5, -2.0 ],
|
||||
"size": [ 3, 12, 4 ],
|
||||
"uv": [ 32, 48 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightArm",
|
||||
"reset": true,
|
||||
"pivot": [ -5.0, 21.5, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -7.0, 11.5, -2.0 ],
|
||||
"size": [ 3, 12, 4 ],
|
||||
"uv": [ 40, 16 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"pivot": [ -6, 14.5, 1 ],
|
||||
"neverRender": true,
|
||||
"name": "rightItem",
|
||||
"parent": "rightArm"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftSleeve",
|
||||
"pivot": [ 5.0, 21.5, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ 4.0, 11.5, -2.0 ],
|
||||
"size": [ 3, 12, 4 ],
|
||||
"uv": [ 48, 48 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightSleeve",
|
||||
"pivot": [ -5.0, 21.5, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -7.0, 11.5, -2.0 ],
|
||||
"size": [ 3, 12, 4 ],
|
||||
"uv": [ 40, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftLeg",
|
||||
"reset": true,
|
||||
"mirror": false,
|
||||
"pivot": [ 1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 16, 48 ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "leftPants",
|
||||
"pivot": [ 1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 48 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "rightPants",
|
||||
"pivot": [ -1.9, 12.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -3.9, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "jacket",
|
||||
"pivot": [ 0.0, 24.0, 0.0 ],
|
||||
"cubes": [
|
||||
{
|
||||
"origin": [ -4.0, 12.0, -2.0 ],
|
||||
"size": [ 8, 12, 4 ],
|
||||
"uv": [ 16, 32 ],
|
||||
"inflate": 0.25
|
||||
}
|
||||
],
|
||||
"material": "alpha"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -49,6 +49,10 @@ debug-mode: false
|
|||
# Thread pool size
|
||||
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
|
||||
# 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/.
|
||||
|
@ -57,8 +61,4 @@ metrics:
|
|||
# If metrics should be enabled
|
||||
enabled: true
|
||||
# UUID of server, don't change!
|
||||
uuid: generateduuid
|
||||
|
||||
|
||||
|
||||
|
||||
uuid: generateduuid
|
Loading…
Reference in a new issue