Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 22:40:18 +01:00
Merge remote-tracking branch 'upstream/master' into feature/blocky
Dieser Commit ist enthalten in:
Commit
9e74e904e7
@ -195,6 +195,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
geyserConfig.loadFloodgate(this);
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
|
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
|
||||||
|
this.geyserCommandManager.init();
|
||||||
|
|
||||||
if (!INITIALIZED) {
|
if (!INITIALIZED) {
|
||||||
// Needs to be an anonymous inner class otherwise Bukkit complains about missing classes
|
// Needs to be an anonymous inner class otherwise Bukkit complains about missing classes
|
||||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||||
@ -206,9 +209,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
|
|
||||||
this.geyserCommandManager.init();
|
|
||||||
|
|
||||||
// Because Bukkit locks its command map upon startup, we need to
|
// Because Bukkit locks its command map upon startup, we need to
|
||||||
// add our plugin commands in onEnable, but populating the executor
|
// add our plugin commands in onEnable, but populating the executor
|
||||||
// can happen at any time
|
// can happen at any time
|
||||||
|
@ -100,6 +100,7 @@ public class PlayerEntity extends LivingEntity {
|
|||||||
super(session, entityId, geyserId, uuid, EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
|
super(session, entityId, geyserId, uuid, EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
|
||||||
|
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
this.nametag = username;
|
||||||
this.texturesProperty = texturesProperty;
|
this.texturesProperty = texturesProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ public class PlayerEntity extends LivingEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The name can't be updated later (the entity metadata for it is ignored), so we need to check for this now
|
// The name can't be updated later (the entity metadata for it is ignored), so we need to check for this now
|
||||||
updateDisplayName(null, false);
|
updateDisplayName(session.getWorldCache().getScoreboard().getTeamFor(username));
|
||||||
|
|
||||||
AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
|
AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
|
||||||
addPlayerPacket.setUuid(uuid);
|
addPlayerPacket.setUuid(uuid);
|
||||||
@ -315,19 +316,10 @@ public class PlayerEntity extends LivingEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//todo this will become common entity logic once UUID support is implemented for them
|
//todo this will become common entity logic once UUID support is implemented for them
|
||||||
/**
|
public void updateDisplayName(@Nullable Team team) {
|
||||||
* @param useGivenTeam even if there is no team, update the username in the entity metadata anyway, and don't look for a team
|
|
||||||
*/
|
|
||||||
public void updateDisplayName(@Nullable Team team, boolean useGivenTeam) {
|
|
||||||
if (team == null && !useGivenTeam) {
|
|
||||||
// Only search for the team if we are not supposed to use the given team
|
|
||||||
// If the given team is null, this is intentional that we are being removed from the team
|
|
||||||
team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean needsUpdate;
|
boolean needsUpdate;
|
||||||
String newDisplayName = this.username;
|
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
|
String newDisplayName;
|
||||||
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
||||||
TeamColor color = team.getColor();
|
TeamColor color = team.getColor();
|
||||||
String chatColor = MessageTranslator.toChatColor(color);
|
String chatColor = MessageTranslator.toChatColor(color);
|
||||||
@ -339,23 +331,16 @@ public class PlayerEntity extends LivingEntity {
|
|||||||
// The name is not visible to the session player; clear name
|
// The name is not visible to the session player; clear name
|
||||||
newDisplayName = "";
|
newDisplayName = "";
|
||||||
}
|
}
|
||||||
needsUpdate = useGivenTeam && !newDisplayName.equals(nametag);
|
needsUpdate = !newDisplayName.equals(this.nametag);
|
||||||
nametag = newDisplayName;
|
this.nametag = newDisplayName;
|
||||||
dirtyMetadata.put(EntityData.NAMETAG, newDisplayName);
|
|
||||||
} else if (useGivenTeam) {
|
|
||||||
// The name has reset, if it was previously something else
|
|
||||||
needsUpdate = !newDisplayName.equals(nametag);
|
|
||||||
dirtyMetadata.put(EntityData.NAMETAG, this.username);
|
|
||||||
} else {
|
} else {
|
||||||
needsUpdate = false;
|
// The name has reset, if it was previously something else
|
||||||
|
needsUpdate = !this.nametag.equals(this.username);
|
||||||
|
this.nametag = this.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsUpdate) {
|
if (needsUpdate) {
|
||||||
// Update the metadata as it won't be updated later
|
dirtyMetadata.put(EntityData.NAMETAG, this.nametag);
|
||||||
SetEntityDataPacket packet = new SetEntityDataPacket();
|
|
||||||
packet.getMetadata().put(EntityData.NAMETAG, newDisplayName);
|
|
||||||
packet.setRuntimeEntityId(geyserId);
|
|
||||||
session.sendUpstreamPacket(packet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
|||||||
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
@ -56,6 +57,13 @@ public final class Scoreboard {
|
|||||||
@Getter
|
@Getter
|
||||||
private final Map<ScoreboardPosition, Objective> objectiveSlots = new EnumMap<>(ScoreboardPosition.class);
|
private final Map<ScoreboardPosition, Objective> objectiveSlots = new EnumMap<>(ScoreboardPosition.class);
|
||||||
private final Map<String, Team> teams = new ConcurrentHashMap<>(); // updated on multiple threads
|
private final Map<String, Team> teams = new ConcurrentHashMap<>(); // updated on multiple threads
|
||||||
|
/**
|
||||||
|
* Required to preserve vanilla behavior, which also uses a map.
|
||||||
|
* Otherwise, for example, if TAB has a team for a player and vanilla has a team, "race conditions" that do not
|
||||||
|
* match vanilla could occur.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final Map<String, Team> playerToTeam = new Object2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
private int lastAddScoreCount = 0;
|
private int lastAddScoreCount = 0;
|
||||||
private int lastRemoveScoreCount = 0;
|
private int lastRemoveScoreCount = 0;
|
||||||
@ -333,12 +341,7 @@ public final class Scoreboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Team getTeamFor(String entity) {
|
public Team getTeamFor(String entity) {
|
||||||
for (Team team : teams.values()) {
|
return playerToTeam.get(entity);
|
||||||
if (team.hasEntity(entity)) {
|
|
||||||
return team;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTeam(String teamName) {
|
public void removeTeam(String teamName) {
|
||||||
@ -348,6 +351,9 @@ public final class Scoreboard {
|
|||||||
// We need to use the direct entities list here, so #refreshSessionPlayerDisplays also updates accordingly
|
// We need to use the direct entities list here, so #refreshSessionPlayerDisplays also updates accordingly
|
||||||
// With the player's lack of a team in visibility checks
|
// With the player's lack of a team in visibility checks
|
||||||
updateEntityNames(remove, remove.getEntities(), true);
|
updateEntityNames(remove, remove.getEntities(), true);
|
||||||
|
for (String name : remove.getEntities()) {
|
||||||
|
playerToTeam.remove(name, remove);
|
||||||
|
}
|
||||||
|
|
||||||
session.removeCommandEnum("Geyser_Teams", remove.getId());
|
session.removeCommandEnum("Geyser_Teams", remove.getId());
|
||||||
}
|
}
|
||||||
@ -380,7 +386,8 @@ public final class Scoreboard {
|
|||||||
for (Entity entity : session.getEntityCache().getEntities().values()) {
|
for (Entity entity : session.getEntityCache().getEntities().values()) {
|
||||||
// This more complex logic is for the future to iterate over all entities, not just players
|
// This more complex logic is for the future to iterate over all entities, not just players
|
||||||
if (entity instanceof PlayerEntity player && names.remove(player.getUsername())) {
|
if (entity instanceof PlayerEntity player && names.remove(player.getUsername())) {
|
||||||
player.updateDisplayName(team, true);
|
player.updateDisplayName(team);
|
||||||
|
player.updateBedrockMetadata();
|
||||||
if (names.isEmpty()) {
|
if (names.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -396,7 +403,8 @@ public final class Scoreboard {
|
|||||||
for (Entity entity : session.getEntityCache().getEntities().values()) {
|
for (Entity entity : session.getEntityCache().getEntities().values()) {
|
||||||
if (entity instanceof PlayerEntity player) {
|
if (entity instanceof PlayerEntity player) {
|
||||||
Team playerTeam = session.getWorldCache().getScoreboard().getTeamFor(player.getUsername());
|
Team playerTeam = session.getWorldCache().getScoreboard().getTeamFor(player.getUsername());
|
||||||
player.updateDisplayName(playerTeam, true);
|
player.updateDisplayName(playerTeam);
|
||||||
|
player.updateBedrockMetadata();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ public final class Team {
|
|||||||
if (entities.add(name)) {
|
if (entities.add(name)) {
|
||||||
added.add(name);
|
added.add(name);
|
||||||
}
|
}
|
||||||
|
scoreboard.getPlayerToTeam().put(name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (added.isEmpty()) {
|
if (added.isEmpty()) {
|
||||||
@ -93,6 +94,7 @@ public final class Team {
|
|||||||
if (entities.remove(name)) {
|
if (entities.remove(name)) {
|
||||||
removed.add(name);
|
removed.add(name);
|
||||||
}
|
}
|
||||||
|
scoreboard.getPlayerToTeam().remove(name, this);
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
@ -92,11 +92,29 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
|
if (isValidMove(session, entity.getPosition(), packet.getPosition())) {
|
||||||
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround(), packet.getMode() == MovePlayerPacket.Mode.TELEPORT);
|
||||||
if (position != null) { // A null return value cancels the packet
|
if (position != null) { // A null return value cancels the packet
|
||||||
|
boolean onGround = packet.isOnGround();
|
||||||
|
|
||||||
|
boolean teleportThroughVoidFloor;
|
||||||
|
// Compare positions here for void floor fix below before the player's position variable is set to the packet position
|
||||||
|
if (entity.getPosition().getY() >= packet.getPosition().getY()) {
|
||||||
|
int floorY = position.getFloorY();
|
||||||
|
// The void floor is offset about 40 blocks below the bottom of the world
|
||||||
|
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
||||||
|
int voidFloorLocation = bedrockDimension.minY() - 40;
|
||||||
|
teleportThroughVoidFloor = floorY <= (voidFloorLocation + 2) && floorY >= voidFloorLocation;
|
||||||
|
if (teleportThroughVoidFloor) {
|
||||||
|
// https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground.
|
||||||
|
onGround = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
teleportThroughVoidFloor = false;
|
||||||
|
}
|
||||||
|
|
||||||
Packet movePacket;
|
Packet movePacket;
|
||||||
if (rotationChanged) {
|
if (rotationChanged) {
|
||||||
// Send rotation updates as well
|
// Send rotation updates as well
|
||||||
movePacket = new ServerboundMovePlayerPosRotPacket(
|
movePacket = new ServerboundMovePlayerPosRotPacket(
|
||||||
packet.isOnGround(),
|
onGround,
|
||||||
position.getX(), position.getY(), position.getZ(),
|
position.getX(), position.getY(), position.getZ(),
|
||||||
yaw, pitch
|
yaw, pitch
|
||||||
);
|
);
|
||||||
@ -105,24 +123,16 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
entity.setHeadYaw(headYaw);
|
entity.setHeadYaw(headYaw);
|
||||||
} else {
|
} else {
|
||||||
// Rotation did not change; don't send an update with rotation
|
// Rotation did not change; don't send an update with rotation
|
||||||
movePacket = new ServerboundMovePlayerPosPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ());
|
movePacket = new ServerboundMovePlayerPosPacket(onGround, position.getX(), position.getY(), position.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare positions here for void floor fix below before the player's position variable is set to the packet position
|
|
||||||
boolean notMovingUp = entity.getPosition().getY() >= packet.getPosition().getY();
|
|
||||||
|
|
||||||
entity.setPositionManual(packet.getPosition());
|
entity.setPositionManual(packet.getPosition());
|
||||||
entity.setOnGround(packet.isOnGround());
|
entity.setOnGround(onGround);
|
||||||
|
|
||||||
// Send final movement changes
|
// Send final movement changes
|
||||||
session.sendDownstreamPacket(movePacket);
|
session.sendDownstreamPacket(movePacket);
|
||||||
|
|
||||||
if (notMovingUp) {
|
if (teleportThroughVoidFloor) {
|
||||||
int floorY = position.getFloorY();
|
|
||||||
// The void floor is offset about 40 blocks below the bottom of the world
|
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
|
||||||
int voidFloorLocation = bedrockDimension.minY() - 40;
|
|
||||||
if (floorY <= (voidFloorLocation + 2) && floorY >= voidFloorLocation) {
|
|
||||||
// Work around there being a floor at the bottom of the world and teleport the player below it
|
// Work around there being a floor at the bottom of the world and teleport the player below it
|
||||||
// Moving from below to above the void floor works fine
|
// Moving from below to above the void floor works fine
|
||||||
entity.setPosition(entity.getPosition().sub(0, 4f, 0));
|
entity.setPosition(entity.getPosition().sub(0, 4f, 0));
|
||||||
@ -134,7 +144,6 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||||||
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
||||||
session.sendUpstreamPacket(movePlayerPacket);
|
session.sendUpstreamPacket(movePlayerPacket);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
session.getSkullCache().updateVisibleSkulls();
|
session.getSkullCache().updateVisibleSkulls();
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren