save tab list item in PlayerEntity

This commit is contained in:
Bixilon 2021-04-07 15:27:02 +02:00
parent f1ae30e2b0
commit 074c685329
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
13 changed files with 151 additions and 128 deletions

View File

@ -47,8 +47,7 @@ abstract class Entity(
var entityMetaData: EntityMetaData = EntityMetaData(connection) var entityMetaData: EntityMetaData = EntityMetaData(connection)
@JvmField protected open val hasCollisions = true
protected var hasCollisions = true
fun forceMove(relativePosition: Vec3) { fun forceMove(relativePosition: Vec3) {
position = position + relativePosition position = position + relativePosition

View File

@ -13,7 +13,6 @@
package de.bixilon.minosoft.data.entities.entities.player package de.bixilon.minosoft.data.entities.entities.player
import de.bixilon.minosoft.data.Gamemodes import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.PlayerPropertyData
import de.bixilon.minosoft.data.entities.EntityMetaDataFields import de.bixilon.minosoft.data.entities.EntityMetaDataFields
import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.EntityMetaDataFunction import de.bixilon.minosoft.data.entities.entities.EntityMetaDataFunction
@ -22,32 +21,33 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.entities.EntityFactory import de.bixilon.minosoft.data.mappings.entities.EntityFactory
import de.bixilon.minosoft.data.mappings.entities.EntityType import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.player.Hands import de.bixilon.minosoft.data.player.Hands
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.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.nbt.tag.CompoundTag import de.bixilon.minosoft.util.nbt.tag.CompoundTag
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import java.util.*
class PlayerEntity( class PlayerEntity(
connection: PlayConnection, connection: PlayConnection,
entityType: EntityType, entityType: EntityType,
position: Vec3, position: Vec3 = Vec3(0, 0, 0),
rotation: EntityRotation, rotation: EntityRotation = EntityRotation(0.0, 0.0),
@get:EntityMetaDataFunction(name = "Name") var name: String, name: String = "TBA",
@get:EntityMetaDataFunction(name = "uuid") var uuid: UUID, properties: Map<PlayerProperties, PlayerProperty> = mapOf(),
@get:EntityMetaDataFunction(name = "Properties") val properties: HashSet<PlayerPropertyData>?, var tabListItem: TabListItem = TabListItem(name = name, gamemode = Gamemodes.SURVIVAL, properties = properties),
gamemode: Gamemodes,
) : LivingEntity(connection, entityType, position, rotation) { ) : LivingEntity(connection, entityType, position, rotation) {
private var _gamemode: Gamemodes = gamemode
var gamemode: Gamemodes
get() = _gamemode
set(value) {
hasCollisions = value != Gamemodes.SPECTATOR
_gamemode = value
}
init { @get:EntityMetaDataFunction(name = "Gamemode")
hasCollisions = gamemode != Gamemodes.SPECTATOR val gamemode: Gamemodes
} get() = tabListItem.gamemode
@get:EntityMetaDataFunction(name = "name")
val name: String
get() = tabListItem.name
override val hasCollisions: Boolean
get() = gamemode != Gamemodes.SPECTATOR
@get:EntityMetaDataFunction(name = "Absorption hearts") @get:EntityMetaDataFunction(name = "Absorption hearts")
val playerAbsorptionHearts: Float val playerAbsorptionHearts: Float

View File

@ -12,7 +12,6 @@
*/ */
package de.bixilon.minosoft.data.player package de.bixilon.minosoft.data.player
import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.accounts.Account import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
@ -28,7 +27,7 @@ class Player(
val experienceCondition = PlayerExperienceCondition() val experienceCondition = PlayerExperienceCondition()
val inventoryManager = PlayerInventoryManager() val inventoryManager = PlayerInventoryManager()
var spawnPosition: Vec3i = VecUtil.EMPTY_VEC3I var spawnPosition: Vec3i = VecUtil.EMPTY_VEC3I
val entity: PlayerEntity = PlayerEntity(connection, connection.mapping.entityRegistry.get(PlayerEntity.RESOURCE_LOCATION)!!, VecUtil.EMPTY_VEC3, EntityRotation(0.0, 0.0), account.username, account.uuid, null, Gamemodes.SPECTATOR) val entity: PlayerEntity = PlayerEntity(connection, connection.mapping.entityRegistry.get(PlayerEntity.RESOURCE_LOCATION)!!, VecUtil.EMPTY_VEC3, EntityRotation(0.0, 0.0), account.username)
@Deprecated(message = "Will be replaced with some kind of teleport manager, ...") @Deprecated(message = "Will be replaced with some kind of teleport manager, ...")
var isSpawnConfirmed = false var isSpawnConfirmed = false

View File

@ -27,9 +27,14 @@ data class TabListItem(
) { ) {
fun merge(data: TabListItemData) { fun merge(data: TabListItemData) {
specialMerge(data)
data.gamemode?.let { gamemode = it }
}
fun specialMerge(data: TabListItemData) {
data.name?.let { name = it } data.name?.let { name = it }
data.ping?.let { ping = it } data.ping?.let { ping = it }
data.gamemode?.let { gamemode = it }
data.hasDisplayName?.let { data.hasDisplayName?.let {
displayName = if (it) { displayName = if (it) {
data.displayName!! data.displayName!!

View File

@ -80,8 +80,8 @@ class World : BiomeAccessor {
} }
} }
fun addEntity(entityId: Int, entityUUID: UUID?, entity: Entity) { fun addEntity(entityId: Int?, entityUUID: UUID?, entity: Entity) {
entityIdMap[entityId] = entity entityId?.let { entityIdMap[it] = entity }
entityUUID?.let { entityUUIDMap[it] = entity } entityUUID?.let { entityUUIDMap[it] = entity }
} }

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.packets.clientbound.login; package de.bixilon.minosoft.protocol.packets.clientbound.login;
import de.bixilon.minosoft.data.text.ChatComponent;
import de.bixilon.minosoft.protocol.network.connection.PlayConnection; import de.bixilon.minosoft.protocol.network.connection.PlayConnection;
import de.bixilon.minosoft.protocol.packets.clientbound.PlayClientboundPacket; import de.bixilon.minosoft.protocol.packets.clientbound.PlayClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.ConnectionStates; import de.bixilon.minosoft.protocol.protocol.ConnectionStates;
@ -41,8 +42,11 @@ public class PacketLoginSuccess extends PlayClientboundPacket {
public void handle(PlayConnection connection) { public void handle(PlayConnection connection) {
connection.setConnectionState(ConnectionStates.PLAY); connection.setConnectionState(ConnectionStates.PLAY);
connection.getPlayer().getEntity().setUuid(getUUID()); var playerEntity = connection.getPlayer().getEntity();
connection.getPlayer().getEntity().setName(getPlayerName()); playerEntity.getTabListItem().setName(this.playerName);
playerEntity.getTabListItem().setDisplayName(ChatComponent.valueOf(this.playerName));
connection.getWorld().addEntity(null, this.uuid, playerEntity);
} }
@Override @Override

View File

@ -51,7 +51,7 @@ public class PacketChangeGameState extends PlayClientboundPacket {
switch (getReason()) { switch (getReason()) {
case STOP_RAINING -> connection.getWorld().setRaining(false); case STOP_RAINING -> connection.getWorld().setRaining(false);
case START_RAINING -> connection.getWorld().setRaining(true); case START_RAINING -> connection.getWorld().setRaining(true);
case CHANGE_GAMEMODE -> connection.getPlayer().getEntity().setGamemode(Gamemodes.byId(getIntValue())); case CHANGE_GAMEMODE -> connection.getPlayer().getEntity().getTabListItem().setGamemode(Gamemodes.byId(getIntValue()));
} }
} }

View File

@ -138,13 +138,13 @@ class PacketJoinGame(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
return return
} }
val playerEntity = connection.player.entity val playerEntity = connection.player.entity
playerEntity.gamemode = gamemode playerEntity.tabListItem.gamemode = gamemode
connection.world.isHardcore = isHardcore connection.world.isHardcore = isHardcore
connection.mapping.dimensionRegistry.setData(dimensions) connection.mapping.dimensionRegistry.setData(dimensions)
connection.world.dimension = dimension connection.world.dimension = dimension
connection.world.addEntity(entityId, connection.player.entity.uuid, playerEntity) connection.world.addEntity(entityId, null, playerEntity)
connection.world.hashedSeed = hashedSeed connection.world.hashedSeed = hashedSeed
connection.world.biomeAccessor = if (connection.version.versionId < ProtocolVersions.V_19W36A) { connection.world.biomeAccessor = if (connection.version.versionId < ProtocolVersions.V_19W36A) {
BlockBiomeAccessor(connection.world) BlockBiomeAccessor(connection.world)
@ -183,7 +183,7 @@ class PacketJoinGame(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
} }
override fun log() { override fun log() {
Log.protocol("[IN] Receiving join game packet (entityId=$entityId, gamemode=$gamemode, dimension=$dimensions, difficulty=$difficulty, hardcore=$isHardcore, viewDistance=$viewDistance)") Log.protocol("[IN] Receiving join game packet (entityId=$entityId, gamemode=$gamemode, dimension=$dimension, difficulty=$difficulty, hardcore=$isHardcore, viewDistance=$viewDistance)")
} }
companion object : ErrorHandler { companion object : ErrorHandler {

View File

@ -63,7 +63,7 @@ public class PacketPlayerPositionAndRotation extends PlayClientboundPacket {
@Override @Override
public void log() { public void log() {
Log.protocol(String.format("[IN] Received player location: (position=%s, rotation=%s, onGround=%b)", this.position, this.rotation, this.onGround)); Log.protocol(String.format("[IN] Received player position (position=%s, rotation=%s, onGround=%b)", this.position, this.rotation, this.onGround));
} }
public Vec3 getPosition() { public Vec3 getPosition() {

View File

@ -91,7 +91,7 @@ class PacketRespawn(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
connection.world.chunks.clear() connection.world.chunks.clear()
connection.world.dimension = dimension connection.world.dimension = dimension
connection.player.isSpawnConfirmed = false connection.player.isSpawnConfirmed = false
connection.player.entity.gamemode = gamemode connection.player.entity.tabListItem.gamemode = gamemode
connection.renderer?.renderWindow?.worldRenderer?.clearChunkCache() connection.renderer?.renderWindow?.worldRenderer?.clearChunkCache()
} }

View File

@ -1,95 +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.config.StaticConfiguration;
import de.bixilon.minosoft.data.Gamemodes;
import de.bixilon.minosoft.data.PlayerPropertyData;
import de.bixilon.minosoft.data.entities.EntityRotation;
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity;
import de.bixilon.minosoft.data.entities.meta.EntityMetaData;
import de.bixilon.minosoft.modding.event.events.EntitySpawnEvent;
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 glm_.vec3.Vec3;
import java.util.HashSet;
import java.util.UUID;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
public class PacketSpawnPlayer extends PlayClientboundPacket {
private final int entityId;
private final UUID entityUUID;
private final PlayerEntity entity;
public PacketSpawnPlayer(PlayInByteBuffer buffer) {
this.entityId = buffer.readVarInt();
String name = "TBA";
HashSet<PlayerPropertyData> properties = null;
if (buffer.getVersionId() < V_14W21A) {
name = buffer.readString();
this.entityUUID = UUID.fromString(buffer.readString());
properties = new HashSet<>();
int length = buffer.readVarInt();
for (int i = 0; i < length; i++) {
properties.add(new PlayerPropertyData(buffer.readString(), buffer.readString(), buffer.readString()));
}
} else {
this.entityUUID = buffer.readUUID();
}
Vec3 position;
if (buffer.getVersionId() < V_16W06A) {
position = new Vec3(buffer.readFixedPointNumberInt(), buffer.readFixedPointNumberInt(), buffer.readFixedPointNumberInt());
} else {
position = buffer.readEntityPosition();
}
short yaw = buffer.readAngle();
short pitch = buffer.readAngle();
if (buffer.getVersionId() < V_15W31A) {
buffer.getConnection().getMapping().getItemRegistry().get(buffer.readUnsignedShort()); // current item
}
EntityMetaData metaData = null;
if (buffer.getVersionId() < V_19W34A) {
metaData = buffer.readMetaData();
}
this.entity = new PlayerEntity(buffer.getConnection(), buffer.getConnection().getMapping().getEntityRegistry().get(PlayerEntity.Companion.getRESOURCE_LOCATION()), position, new EntityRotation(yaw, pitch, 0), name, this.entityUUID, properties, Gamemodes.CREATIVE); // ToDo
if (metaData != null) {
this.entity.setEntityMetaData(metaData);
if (StaticConfiguration.VERBOSE_ENTITY_META_DATA_LOGGING) {
Log.verbose(String.format("Metadata of entity %s (entityId=%d): %s", this.entity.toString(), this.entityId, this.entity.getEntityMetaDataAsString()));
}
}
}
@Override
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, this.entityUUID, this.entity);
}
@Override
public void log() {
Log.protocol(String.format("[IN] Player spawned at %s (entityId=%d, name=%s, uuid=%s)", this.entity.getPosition(), this.entityId, this.entity.getName(), this.entity.getUuid()));
}
public PlayerEntity getEntity() {
return this.entity;
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.config.StaticConfiguration
import de.bixilon.minosoft.data.PlayerPropertyData
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.entities.meta.EntityMetaData
import de.bixilon.minosoft.modding.event.events.EntitySpawnEvent
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.Util
import de.bixilon.minosoft.util.logging.Log
import glm_.vec3.Vec3
import java.util.*
class PacketSpawnPlayer(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
private val entityId: Int
private var entityUUID: UUID? = null
val entity: PlayerEntity
init {
entityId = buffer.readVarInt()
var name = "TBA"
val properties: MutableSet<PlayerPropertyData?> = mutableSetOf()
if (buffer.versionId < ProtocolVersions.V_14W21A) {
name = buffer.readString()
entityUUID = Util.getUUIDFromString(buffer.readString())
val length = buffer.readVarInt()
for (i in 0 until length) {
properties.add(PlayerPropertyData(buffer.readString(), buffer.readString(), buffer.readString()))
}
} else {
entityUUID = buffer.readUUID()
}
val position: Vec3 = if (buffer.versionId < ProtocolVersions.V_16W06A) {
Vec3(buffer.readFixedPointNumberInt(), buffer.readFixedPointNumberInt(), buffer.readFixedPointNumberInt())
} else {
buffer.readEntityPosition()
}
val yaw = buffer.readAngle()
val pitch = buffer.readAngle()
if (buffer.versionId < ProtocolVersions.V_15W31A) {
buffer.connection.mapping.itemRegistry.get(buffer.readUnsignedShort()) // current item
}
var metaData: EntityMetaData? = null
if (buffer.versionId < ProtocolVersions.V_19W34A) {
metaData = buffer.readMetaData()
}
entity = PlayerEntity(
connection = buffer.connection,
entityType = buffer.connection.mapping.entityRegistry.get(PlayerEntity.RESOURCE_LOCATION)!!,
position = position,
rotation = EntityRotation(yaw.toFloat(), pitch.toFloat(), 0.0f),
name = name,
// ToDo: properties = properties,
)
if (metaData != null) {
entity.entityMetaData = metaData
if (StaticConfiguration.VERBOSE_ENTITY_META_DATA_LOGGING) {
Log.verbose(String.format("Metadata of entity %s (entityId=%d): %s", entity.toString(), entityId, entity.entityMetaDataAsString))
}
}
}
override fun handle(connection: PlayConnection) {
connection.tabList.tabListItems[entityUUID]?.let { entity.tabListItem = it }
connection.fireEvent(EntitySpawnEvent(connection, this))
connection.world.addEntity(entityId, entityUUID, entity)
}
override fun log() {
Log.protocol("[IN] Player spawned at (position=${entity.position}, entityId=$entityId, name=${entity.name}, uuid=$entityUUID)")
}
}

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.packets.clientbound.play package de.bixilon.minosoft.protocol.packets.clientbound.play
import de.bixilon.minosoft.data.Gamemodes import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.player.PlayerProperties import de.bixilon.minosoft.data.player.PlayerProperties
import de.bixilon.minosoft.data.player.PlayerProperty import de.bixilon.minosoft.data.player.PlayerProperty
import de.bixilon.minosoft.data.player.tab.TabListItem import de.bixilon.minosoft.data.player.tab.TabListItem
@ -118,6 +119,7 @@ class PacketTabListItem(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
} }
for ((uuid, data) in items) { for ((uuid, data) in items) {
// legacy // legacy
if (connection.version.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19? if (connection.version.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19?
val item: TabListItem = if (data.remove) { val item: TabListItem = if (data.remove) {
// add or remove // add or remove
@ -141,6 +143,10 @@ class PacketTabListItem(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
connection.tabList.tabListItems.remove(uuid) connection.tabList.tabListItems.remove(uuid)
continue continue
} }
val entity = connection.world.getEntity(uuid)
val tabListItem = connection.tabList.tabListItems[uuid] ?: run { val tabListItem = connection.tabList.tabListItems[uuid] ?: run {
if (data.name == null) { if (data.name == null) {
// item not yet created // item not yet created
@ -151,7 +157,18 @@ class PacketTabListItem(buffer: PlayInByteBuffer) : PlayClientboundPacket() {
item item
} ?: continue } ?: continue
if (entity === connection.player.entity) {
entity.tabListItem.specialMerge(data)
continue
}
tabListItem.merge(data) tabListItem.merge(data)
if (entity == null || entity !is PlayerEntity) {
continue
}
entity.tabListItem = tabListItem
} }
} }