refactor tab list

This commit is contained in:
Bixilon 2021-04-06 23:41:16 +02:00
parent 4c1a9ba223
commit 804a49f319
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
12 changed files with 266 additions and 380 deletions

View File

@ -19,7 +19,7 @@ public enum Gamemodes {
ADVENTURE,
SPECTATOR;
private static final Gamemodes[] GAME_MODES = values();
public static final Gamemodes[] GAME_MODES = values();
public static Gamemodes byId(int id) {
return GAME_MODES[id];

View File

@ -1,106 +0,0 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.player.tab;
import de.bixilon.minosoft.data.Gamemodes;
import de.bixilon.minosoft.data.player.PlayerProperties;
import de.bixilon.minosoft.data.player.PlayerProperty;
import de.bixilon.minosoft.data.text.ChatComponent;
import java.util.HashMap;
import java.util.UUID;
// The holder for the data on <tab>
public class PlayerListItem {
// required fields
private final UUID uuid;
private final String name;
private final boolean legacy;
int ping;
// optional fields
Gamemodes gamemode;
ChatComponent displayName;
HashMap<PlayerProperties, PlayerProperty> properties;
/**
* Legacy (1.7.10)
*
* @param name Player name
* @param ping Ping in milliseconds
*/
public PlayerListItem(UUID uuid, String name, int ping) {
this.uuid = uuid;
this.name = name;
this.ping = ping;
this.legacy = true;
}
public PlayerListItem(UUID uuid, String name, int ping, Gamemodes gamemode, ChatComponent displayName, HashMap<PlayerProperties, PlayerProperty> properties) {
this.uuid = uuid;
this.name = name;
this.ping = ping;
this.gamemode = gamemode;
this.displayName = displayName;
this.properties = properties;
this.legacy = false;
}
public UUID getUUID() {
return this.uuid;
}
public String getName() {
return this.name;
}
public int getPing() {
return this.ping;
}
public void setPing(int ping) {
this.ping = ping;
}
public Gamemodes getGamemode() {
return this.gamemode;
}
public void setGamemode(Gamemodes gamemode) {
this.gamemode = gamemode;
}
public ChatComponent getDisplayName() {
return (hasDisplayName() ? this.displayName : ChatComponent.valueOf(this.name));
}
public void setDisplayName(ChatComponent displayName) {
this.displayName = displayName;
}
public boolean hasDisplayName() {
return this.displayName != null;
}
public HashMap<PlayerProperties, PlayerProperty> getProperties() {
return this.properties;
}
public PlayerProperty getProperty(PlayerProperties property) {
return this.properties.get(property);
}
public boolean isLegacy() {
return this.legacy;
}
}

View File

@ -1,104 +0,0 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.player.tab;
import de.bixilon.minosoft.data.Gamemodes;
import de.bixilon.minosoft.data.player.PlayerProperties;
import de.bixilon.minosoft.data.player.PlayerProperty;
import de.bixilon.minosoft.data.text.ChatComponent;
import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketPlayerListItem;
import java.util.HashMap;
import java.util.UUID;
// The holder for the data on <tab>
public class PlayerListItemBulk {
// required fieldsp
private final UUID uuid;
private final String name;
private final boolean legacy;
private final int ping;
// optional fields
private final Gamemodes gamemode;
private final ChatComponent displayName;
private final HashMap<PlayerProperties, PlayerProperty> properties;
private final PacketPlayerListItem.PlayerListItemActions action;
public PlayerListItemBulk(String name, int ping, PacketPlayerListItem.PlayerListItemActions action) {
this.action = action;
this.uuid = UUID.randomUUID();
this.name = name;
this.ping = ping;
this.gamemode = null;
this.displayName = null;
this.properties = null;
this.legacy = true;
}
public PlayerListItemBulk(UUID uuid, String name, int ping, Gamemodes gamemode, ChatComponent displayName, HashMap<PlayerProperties, PlayerProperty> properties, PacketPlayerListItem.PlayerListItemActions action) {
this.uuid = uuid;
this.name = name;
this.ping = ping;
this.gamemode = gamemode;
this.displayName = displayName;
this.properties = properties;
this.action = action;
this.legacy = false;
}
public UUID getUUID() {
return this.uuid;
}
public String getName() {
return this.name;
}
public int getPing() {
return this.ping;
}
public Gamemodes getGamemode() {
return this.gamemode;
}
public ChatComponent getDisplayName() {
return (hasDisplayName() ? this.displayName : ChatComponent.valueOf(this.name));
}
public boolean hasDisplayName() {
return this.displayName != null;
}
public HashMap<PlayerProperties, PlayerProperty> getProperties() {
return this.properties;
}
public PlayerProperty getProperty(PlayerProperties property) {
return this.properties.get(property);
}
public boolean isLegacy() {
return this.legacy;
}
public PacketPlayerListItem.PlayerListItemActions getAction() {
return this.action;
}
@Override
public String toString() {
return String.format("uuid=%s, action=%s, name=%s, gamemode=%s, ping=%d, displayName=%s", getUUID(), getAction(), getName(), getGamemode(), getPing(), getDisplayName());
}
}

View File

@ -17,7 +17,7 @@ import de.bixilon.minosoft.data.text.ChatComponent
import java.util.*
class TabList {
val playerList: MutableMap<UUID, PlayerListItem> = mutableMapOf()
val tabListItems: MutableMap<UUID, TabListItem> = mutableMapOf()
var header = ChatComponent.valueOf("")!!
var footer = ChatComponent.valueOf("")!!
}

View File

@ -0,0 +1,42 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.player.tab
import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.player.PlayerProperties
import de.bixilon.minosoft.data.player.PlayerProperty
import de.bixilon.minosoft.data.text.ChatComponent
data class TabListItem(
var name: String,
var ping: Int = -1,
var gamemode: Gamemodes = Gamemodes.SURVIVAL,
var displayName: ChatComponent = ChatComponent.valueOf(name),
var properties: Map<PlayerProperties, PlayerProperty> = mutableMapOf(),
) {
fun merge(data: TabListItemData) {
data.name?.let { name = it }
data.ping?.let { ping = it }
data.gamemode?.let { gamemode = it }
data.hasDisplayName?.let {
displayName = if (it) {
data.displayName!!
} else {
ChatComponent.valueOf(name)
}
}
data.properties?.let { properties = it }
}
}

View File

@ -0,0 +1,29 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.player.tab
import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.player.PlayerProperties
import de.bixilon.minosoft.data.player.PlayerProperty
import de.bixilon.minosoft.data.text.ChatComponent
data class TabListItemData(
val name: String? = null,
var ping: Int? = null,
var gamemode: Gamemodes? = null,
var hasDisplayName: Boolean? = null,
var displayName: ChatComponent? = null,
val properties: Map<PlayerProperties, PlayerProperty>? = null,
var remove: Boolean = false, // used for legacy tab list
)

View File

@ -13,26 +13,27 @@
package de.bixilon.minosoft.modding.event.events;
import de.bixilon.minosoft.data.player.tab.PlayerListItemBulk;
import de.bixilon.minosoft.data.player.tab.TabListItemData;
import de.bixilon.minosoft.protocol.network.connection.PlayConnection;
import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketPlayerListItem;
import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketTabListItem;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
public class PlayerListItemChangeEvent extends CancelableEvent {
private final ArrayList<PlayerListItemBulk> playerList;
private final Map<UUID, TabListItemData> items;
public PlayerListItemChangeEvent(PlayConnection connection, ArrayList<PlayerListItemBulk> playerList) {
public PlayerListItemChangeEvent(PlayConnection connection, Map<UUID, TabListItemData> items) {
super(connection);
this.playerList = playerList;
this.items = items;
}
public PlayerListItemChangeEvent(PlayConnection connection, PacketPlayerListItem pkg) {
public PlayerListItemChangeEvent(PlayConnection connection, PacketTabListItem pkg) {
super(connection);
this.playerList = pkg.getPlayerList();
this.items = pkg.getItems();
}
public ArrayList<PlayerListItemBulk> getPlayerList() {
return this.playerList;
public Map<UUID, TabListItemData> getItems() {
return this.items;
}
}

View File

@ -1,151 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.packets.clientbound.play;
import de.bixilon.minosoft.data.Gamemodes;
import de.bixilon.minosoft.data.player.PlayerProperties;
import de.bixilon.minosoft.data.player.PlayerProperty;
import de.bixilon.minosoft.data.player.tab.PlayerListItem;
import de.bixilon.minosoft.data.player.tab.PlayerListItemBulk;
import de.bixilon.minosoft.data.text.ChatComponent;
import de.bixilon.minosoft.modding.event.events.PlayerListItemChangeEvent;
import de.bixilon.minosoft.protocol.network.connection.PlayConnection;
import de.bixilon.minosoft.protocol.packets.clientbound.PlayClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer;
import de.bixilon.minosoft.util.logging.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W04A;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W19A;
public class PacketPlayerListItem extends PlayClientboundPacket {
private final ArrayList<PlayerListItemBulk> playerList = new ArrayList<>();
public PacketPlayerListItem(PlayInByteBuffer buffer) {
if (buffer.getVersionId() < V_14W19A) { // ToDo: 19?
String name = buffer.readString();
int ping;
if (buffer.getVersionId() < V_14W04A) {
ping = buffer.readUnsignedShort();
} else {
ping = buffer.readVarInt();
}
PlayerListItemActions action = (buffer.readBoolean() ? PlayerListItemActions.UPDATE_LATENCY : PlayerListItemActions.REMOVE_PLAYER);
this.playerList.add(new PlayerListItemBulk(name, ping, action));
return;
}
PlayerListItemActions action = PlayerListItemActions.byId(buffer.readVarInt());
int count = buffer.readVarInt();
for (int i = 0; i < count; i++) {
UUID uuid = buffer.readUUID();
PlayerListItemBulk listItemBulk;
// UUID uuid, String name, int ping, GameMode gamemode, TextComponent displayName, HashMap< PlayerProperties, PlayerProperty > properties, PacketPlayerInfo.PlayerInfoAction action) {
switch (action) {
case ADD -> {
String name = buffer.readString();
int propertiesCount = buffer.readVarInt();
HashMap<PlayerProperties, PlayerProperty> playerProperties = new HashMap<>();
for (int p = 0; p < propertiesCount; p++) {
PlayerProperty property = new PlayerProperty(PlayerProperties.byName(buffer.readString()), buffer.readString(), (buffer.readBoolean() ? buffer.readString() : null));
playerProperties.put(property.getProperty(), property);
}
Gamemodes gamemode = Gamemodes.byId(buffer.readVarInt());
int ping = buffer.readVarInt();
ChatComponent displayName = (buffer.readBoolean() ? buffer.readChatComponent() : null);
listItemBulk = new PlayerListItemBulk(uuid, name, ping, gamemode, displayName, playerProperties, action);
}
case UPDATE_GAMEMODE -> listItemBulk = new PlayerListItemBulk(uuid, null, 0, Gamemodes.byId(buffer.readVarInt()), null, null, action);
case UPDATE_LATENCY -> listItemBulk = new PlayerListItemBulk(uuid, null, buffer.readVarInt(), null, null, null, action);
case UPDATE_DISPLAY_NAME -> listItemBulk = new PlayerListItemBulk(uuid, null, 0, null, (buffer.readBoolean() ? buffer.readChatComponent() : null), null, action);
case REMOVE_PLAYER -> listItemBulk = new PlayerListItemBulk(uuid, null, 0, null, null, null, action);
default -> listItemBulk = null;
}
this.playerList.add(listItemBulk);
}
}
@Override
public void handle(PlayConnection connection) {
if (connection.fireEvent(new PlayerListItemChangeEvent(connection, this))) {
return;
}
for (PlayerListItemBulk bulk : getPlayerList()) {
PlayerListItem item = connection.getTabList().getPlayerList().get(bulk.getUUID());
if (bulk.getAction() != PlayerListItemActions.ADD && item == null && !bulk.isLegacy()) {
// Aaaaah. Fuck this shit. The server sends us bullshit!
continue;
}
switch (bulk.getAction()) {
case ADD -> connection.getTabList().getPlayerList().put(bulk.getUUID(), new PlayerListItem(bulk.getUUID(), bulk.getName(), bulk.getPing(), bulk.getGamemode(), bulk.getDisplayName(), bulk.getProperties()));
case UPDATE_LATENCY -> {
if (bulk.isLegacy()) {
// add or update
if (item == null) {
// create
UUID uuid = UUID.randomUUID();
connection.getTabList().getPlayerList().put(uuid, new PlayerListItem(uuid, bulk.getName(), bulk.getPing()));
} else {
// update ping
item.setPing(bulk.getPing());
}
continue;
}
connection.getTabList().getPlayerList().get(bulk.getUUID()).setPing(bulk.getPing());
}
case REMOVE_PLAYER -> {
if (bulk.isLegacy()) {
if (item == null) {
// not initialized yet
continue;
}
// ToDo: connection.getTabList().getPlayerList().remove(connection.getTabList().getPlayerList(bulk.getName()).getUUID());
continue;
}
connection.getTabList().getPlayerList().remove(bulk.getUUID());
}
case UPDATE_GAMEMODE -> item.setGamemode(bulk.getGamemode());
case UPDATE_DISPLAY_NAME -> item.setDisplayName(bulk.getDisplayName());
}
}
}
@Override
public void log() {
for (PlayerListItemBulk property : this.playerList) {
Log.protocol(String.format("[IN] Received player list item bulk (%s)", property));
}
}
public ArrayList<PlayerListItemBulk> getPlayerList() {
return this.playerList;
}
public enum PlayerListItemActions {
ADD,
UPDATE_GAMEMODE,
UPDATE_LATENCY,
UPDATE_DISPLAY_NAME,
REMOVE_PLAYER;
private static final PlayerListItemActions[] PLAYER_LIST_ITEM_ACTIONS = values();
public static PlayerListItemActions byId(int id) {
return PLAYER_LIST_ITEM_ACTIONS[id];
}
}
}

View File

@ -0,0 +1,175 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.packets.clientbound.play
import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.player.PlayerProperties
import de.bixilon.minosoft.data.player.PlayerProperty
import de.bixilon.minosoft.data.player.tab.TabListItem
import de.bixilon.minosoft.data.player.tab.TabListItemData
import de.bixilon.minosoft.modding.event.events.PlayerListItemChangeEvent
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.clientbound.PlayClientboundPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
import de.bixilon.minosoft.util.logging.Log
import java.nio.charset.StandardCharsets
import java.util.*
class PacketTabListItem(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
val items: MutableMap<UUID, TabListItemData> = mutableMapOf()
init {
if (buffer.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19?
val name: String = buffer.readString()
val ping: Int = if (buffer.versionId < ProtocolVersions.V_14W04A) {
buffer.readUnsignedShort()
} else {
buffer.readVarInt()
}
val action = if (buffer.readBoolean()) {
PlayerListItemActions.UPDATE_LATENCY
} else {
PlayerListItemActions.REMOVE_PLAYER
}
val uuid: UUID = UUID.nameUUIDFromBytes(name.toByteArray(StandardCharsets.UTF_8))
val item = TabListItemData(name = name, ping = ping, remove = action == PlayerListItemActions.REMOVE_PLAYER)
items[uuid] = item
} else {
val action = PlayerListItemActions.VALUES[buffer.readVarInt()]
val count: Int = buffer.readVarInt()
for (i in 0 until count) {
val uuid: UUID = buffer.readUUID()
val data: TabListItemData
when (action) {
PlayerListItemActions.ADD -> {
val name = buffer.readString()
val playerProperties: MutableMap<PlayerProperties, PlayerProperty> = mutableMapOf()
for (index in 0 until buffer.readVarInt()) {
val property = PlayerProperty(
PlayerProperties.byName(buffer.readString()),
buffer.readString(),
if (buffer.readBoolean()) {
buffer.readString()
} else {
null
},
)
playerProperties[property.property] = property
}
val gamemode = Gamemodes.GAME_MODES[buffer.readVarInt()]
val ping = buffer.readVarInt()
val hasDisplayName = buffer.readBoolean()
val displayName = if (hasDisplayName) {
buffer.readChatComponent()
} else {
null
}
data = TabListItemData(
name = name,
properties = playerProperties,
gamemode = gamemode,
ping = ping,
hasDisplayName = hasDisplayName,
displayName = displayName,
)
}
PlayerListItemActions.UPDATE_GAMEMODE -> {
data = TabListItemData(gamemode = Gamemodes.GAME_MODES[buffer.readVarInt()])
}
PlayerListItemActions.UPDATE_LATENCY -> {
data = TabListItemData(ping = buffer.readVarInt())
}
PlayerListItemActions.UPDATE_DISPLAY_NAME -> {
val hasDisplayName = buffer.readBoolean()
val displayName = if (hasDisplayName) {
buffer.readChatComponent()
} else {
null
}
data = TabListItemData(
hasDisplayName = hasDisplayName,
displayName = displayName,
)
}
PlayerListItemActions.REMOVE_PLAYER -> {
data = TabListItemData(remove = true)
}
}
items[uuid] = data
}
}
}
override fun handle(connection: PlayConnection) {
if (connection.fireEvent(PlayerListItemChangeEvent(connection, this))) {
return
}
for ((uuid, data) in items) {
// legacy
if (connection.version.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19?
val item: TabListItem = if (data.remove) {
// add or remove
connection.tabList.tabListItems[uuid]?.let {
connection.tabList.tabListItems.remove(uuid)
it
} ?: let {
// add
val itemToAdd = TabListItem(name = data.name!!)
connection.tabList.tabListItems[uuid] = itemToAdd
itemToAdd
}
} else {
connection.tabList.tabListItems[uuid]!!
}
item.merge(data)
continue
}
if (data.remove) {
connection.tabList.tabListItems.remove(uuid)
continue
}
val tabListItem = connection.tabList.tabListItems[uuid] ?: run {
if (data.name == null) {
// item not yet created
return@run null
}
val item = TabListItem(name = data.name)
connection.tabList.tabListItems[uuid] = item
item
} ?: continue
tabListItem.merge(data)
}
}
override fun log() {
Log.protocol("[IN] Received tab list items: $items")
}
enum class PlayerListItemActions {
ADD,
UPDATE_GAMEMODE,
UPDATE_LATENCY,
UPDATE_DISPLAY_NAME,
REMOVE_PLAYER,
;
companion object {
val VALUES = values()
}
}
}

View File

@ -193,7 +193,7 @@ class PacketTypes {
PLAY_CRAFT_RECIPE_RESPONSE({ PacketCraftRecipeResponse(it) }),
PLAY_PLAYER_ABILITIES({ PacketPlayerAbilitiesReceiving(it) }),
PLAY_COMBAT_EVENT({ CombatEventPacketFactory.createPacket(it) }),
PLAY_PLAYER_LIST_ITEM({ PacketPlayerListItem(it) }),
PLAY_TAB_LIST_ITEM({ PacketTabListItem(it) }),
PLAY_FACE_PLAYER({ PacketFacePlayer(it) }),
PLAY_PLAYER_POSITION_AND_ROTATION({ PacketPlayerPositionAndRotation(it) }),
PLAY_UNLOCK_RECIPES({ PacketUnlockRecipes(it) }),

View File

@ -17,7 +17,7 @@ import com.github.freva.asciitable.AsciiTable;
import de.bixilon.minosoft.data.commands.CommandLiteralNode;
import de.bixilon.minosoft.data.commands.CommandNode;
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity;
import de.bixilon.minosoft.data.player.tab.PlayerListItem;
import de.bixilon.minosoft.data.player.tab.TabListItem;
import java.util.ArrayList;
import java.util.Iterator;
@ -31,7 +31,7 @@ public class CommandTabList extends Command {
new CommandLiteralNode("list", (connection, stack) -> {
print(connection.getTabList().getHeader().getANSIColoredMessage());
int entries = connection.getTabList().getPlayerList().size();
int entries = connection.getTabList().getTabListItems().size();
int columns = (entries / 20) + 1;
if (columns > 4) {
columns = 4;
@ -43,7 +43,7 @@ public class CommandTabList extends Command {
ArrayList<Object[]> tableData = new ArrayList<>();
Iterator<PlayerListItem> playerListItems = connection.getTabList().getPlayerList().values().iterator();
Iterator<TabListItem> playerListItems = connection.getTabList().getTabListItems().values().iterator();
for (int row = 0; row < rows; row++) {
ArrayList<Object> current = new ArrayList<>();
for (int column = 0; column < columns; column++) {
@ -68,8 +68,8 @@ public class CommandTabList extends Command {
ArrayList<Object[]> tableData = new ArrayList<>();
for (var entry : connection.getTabList().getPlayerList().entrySet()) {
PlayerEntity playerEntity = (PlayerEntity) connection.getWorld().getEntity(entry.getValue().getUUID());
for (var entry : connection.getTabList().getTabListItems().entrySet()) {
PlayerEntity playerEntity = (PlayerEntity) connection.getWorld().getEntity(entry.getKey());
Integer entityId = playerEntity != null ? connection.getWorld().getEntityIdMap().inverse().get(playerEntity) : null;
tableData.add(new Object[]{entry.getKey(), entityId, entry.getValue().getName(), entry.getValue().getDisplayName(), entry.getValue().getGamemode(), entry.getValue().getPing() + "ms"});
}

File diff suppressed because one or more lines are too long