improve entity id mapping

This commit is contained in:
Bixilon 2021-04-23 22:02:43 +02:00
parent 6ee7c57915
commit 6c5781513e
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
34 changed files with 116 additions and 69 deletions

View File

@ -12,10 +12,8 @@
*/
package de.bixilon.minosoft.data.world
import com.google.common.collect.HashBiMap
import de.bixilon.minosoft.data.Difficulties
import de.bixilon.minosoft.data.entities.block.BlockEntity
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.mappings.Dimension
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.mappings.blocks.BlockState
@ -34,8 +32,7 @@ import java.util.concurrent.ConcurrentHashMap
*/
class World : BiomeAccessor {
val chunks: MutableMap<Vec2i, Chunk> = Collections.synchronizedMap(ConcurrentHashMap())
val entityIdMap = HashBiMap.create<Int, Entity>()
val entityUUIDMap = HashBiMap.create<UUID, Entity>()
val entities = WorldEntities()
var isHardcore = false
var isRaining = false
var dimension: Dimension? = null
@ -80,33 +77,6 @@ class World : BiomeAccessor {
}
}
fun addEntity(entityId: Int?, entityUUID: UUID?, entity: Entity) {
entityId?.let { entityIdMap[it] = entity }
entityUUID?.let { entityUUIDMap[it] = entity }
}
fun getEntity(id: Int): Entity? {
return entityIdMap[id]
}
fun getEntity(uuid: UUID): Entity? {
return entityUUIDMap[uuid]
}
fun removeEntity(entity: Entity) {
entityIdMap.inverse().remove(entity)
entityUUIDMap.inverse().remove(entity)
}
fun removeEntity(entityId: Int) {
entityIdMap[entityId]?.let { removeEntity(it) }
}
fun removeEntity(entityUUID: UUID) {
entityUUIDMap[entityUUID]?.let { removeEntity(it) }
}
fun getBlockEntity(blockPosition: Vec3i): BlockEntity? {
return getChunk(blockPosition.chunkPosition)?.getBlockEntity(blockPosition.inChunkPosition)
}

View File

@ -0,0 +1,77 @@
/*
* 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.world
import de.bixilon.minosoft.data.entities.entities.Entity
import java.util.*
import java.util.concurrent.ConcurrentHashMap
class WorldEntities : Iterable<Entity> {
private val idEntityMap: MutableMap<Int, Entity> = ConcurrentHashMap()
private val entityIdMap: MutableMap<Entity, Int> = ConcurrentHashMap()
private val entityUUIDMap: MutableMap<Entity, UUID> = ConcurrentHashMap()
private val uuidEntityMap: MutableMap<UUID, Entity> = ConcurrentHashMap()
fun add(entityId: Int?, entityUUID: UUID?, entity: Entity) {
check(entityId != null || entityUUID != null) { "Entity id and UUID is null!" }
entityId?.let {
idEntityMap[it] = entity
entityIdMap[entity] = it
}
entityUUID?.let {
uuidEntityMap[it] = entity
entityUUIDMap[entity] = it
}
}
operator fun get(id: Int): Entity? {
return idEntityMap[id]
}
fun getId(entity: Entity): Int? {
return entityIdMap[entity]!!
}
operator fun get(uuid: UUID): Entity? {
return uuidEntityMap[uuid]
}
fun getUUID(entity: Entity): UUID? {
return entityUUIDMap[entity]
}
fun remove(entity: Entity) {
entityIdMap[entity]?.let {
idEntityMap.remove(it)
}
entityIdMap.remove(entity)
entityUUIDMap[entity]?.let {
uuidEntityMap.remove(it)
}
entityUUIDMap.remove(entity)
}
fun remove(entityId: Int) {
idEntityMap[entityId]?.let { remove(it) }
}
fun remove(entityUUID: UUID) {
uuidEntityMap[entityUUID]?.let { remove(it) }
}
override fun iterator(): Iterator<Entity> {
return idEntityMap.values.iterator()
}
}

View File

@ -35,8 +35,8 @@ public class CollectItemAnimationEvent extends CancelableEvent {
public CollectItemAnimationEvent(PlayConnection connection, PacketCollectItem pkg) {
super(connection);
this.item = connection.getWorld().getEntity(pkg.getItemEntityId());
this.collector = connection.getWorld().getEntity(pkg.getCollectorEntityId());
this.item = connection.getWorld().getEntities().get(pkg.getItemEntityId());
this.collector = connection.getWorld().getEntities().get(pkg.getCollectorEntityId());
this.count = pkg.getCount();
}

View File

@ -33,7 +33,7 @@ public class EntityDespawnEvent extends PlayConnectionEvent {
public Entity[] getEntities() {
Entity[] ret = new Entity[this.entityIds.length];
for (int i = 0; i < this.entityIds.length; i++) {
ret[i] = getConnection().getWorld().getEntity(this.entityIds[i]);
ret[i] = getConnection().getWorld().getEntities().get(this.entityIds[i]);
}
return ret;
}

View File

@ -38,7 +38,7 @@ public class EntityEquipmentChangeEvent extends PlayConnectionEvent {
}
public Entity getEntity() {
return getConnection().getWorld().getEntity(this.entityId);
return getConnection().getWorld().getEntities().get(this.entityId);
}
public int getEntityId() {

View File

@ -24,6 +24,6 @@ class EntityMetaDataChangeEvent : PlayConnectionEvent {
}
constructor(connection: PlayConnection, pkg: PacketEntityMetadata) : super(connection) {
entity = connection.world.getEntity(pkg.entityId)!!
entity = connection.world.entities[pkg.entityId]!!
}
}

View File

@ -118,7 +118,7 @@ class PlayConnection(
velocityHandlerTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME / 4) {
val currentTime = System.currentTimeMillis()
val deltaTime = currentTime - velocityHandlerLastExecutionTime
for (entity in world.entityIdMap.values) {
for (entity in world.entities) {
entity.computeTimeStep(deltaTime)
}
renderer?.renderWindow?.inputHandler?.camera?.checkPosition()

View File

@ -26,7 +26,7 @@ class EntityActionC2SPacket(
val action: EntityActions,
val parameter: Int = 0, // currently used as jump boost for horse jumping
) : PlayC2SPacket {
constructor(entity: Entity, connection: PlayConnection, action: EntityActions, parameter: Int = 0) : this(connection.world.entityIdMap.inverse()[entity]!!, action, parameter)
constructor(entity: Entity, connection: PlayConnection, action: EntityActions, parameter: Int = 0) : this(connection.world.entities.getId(entity)!!, action, parameter)
override fun write(buffer: PlayOutByteBuffer) {
buffer.writeEntityId(entityId)

View File

@ -24,7 +24,7 @@ class AttackEntityC2SPacket(
override val sneaking: Boolean,
) : BaseInteractEntityC2SPacket(entityId, EntityInteractionActions.ATTACK) {
constructor(connection: PlayConnection, entity: Entity, sneaking: Boolean) : this(connection.world.entityIdMap.inverse()[entity]!!, sneaking)
constructor(connection: PlayConnection, entity: Entity, sneaking: Boolean) : this(connection.world.entities.getId(entity)!!, sneaking)
override fun write(buffer: PlayOutByteBuffer) {
super.write(buffer)

View File

@ -28,7 +28,7 @@ class InteractAtEntityC2SPacket(
override val sneaking: Boolean,
) : BaseInteractEntityC2SPacket(entityId, EntityInteractionActions.INTERACT_AT) {
constructor(connection: PlayConnection, entity: Entity, position: Vec3, hand: Hands, sneaking: Boolean) : this(connection.world.entityIdMap.inverse()[entity]!!, position, hand, sneaking)
constructor(connection: PlayConnection, entity: Entity, position: Vec3, hand: Hands, sneaking: Boolean) : this(connection.world.entities.getId(entity)!!, position, hand, sneaking)
override fun write(buffer: PlayOutByteBuffer) {
super.write(buffer)

View File

@ -28,7 +28,7 @@ class InteractEntityC2SPacket(
override val sneaking: Boolean,
) : BaseInteractEntityC2SPacket(entityId, EntityInteractionActions.INTERACT) {
constructor(connection: PlayConnection, entity: Entity, position: Vec3, hand: Hands, sneaking: Boolean) : this(connection.world.entityIdMap.inverse()[entity]!!, position, hand, sneaking)
constructor(connection: PlayConnection, entity: Entity, position: Vec3, hand: Hands, sneaking: Boolean) : this(connection.world.entities.getId(entity)!!, position, hand, sneaking)
override fun write(buffer: PlayOutByteBuffer) {
super.write(buffer)

View File

@ -46,7 +46,7 @@ public class PacketLoginSuccess extends PlayS2CPacket {
playerEntity.getTabListItem().setName(this.playerName);
playerEntity.getTabListItem().setDisplayName(ChatComponent.Companion.valueOf(this.playerName));
connection.getWorld().addEntity(null, this.uuid, playerEntity);
connection.getWorld().getEntities().add(null, this.uuid, playerEntity);
}
@Override

View File

@ -24,7 +24,7 @@ class EntityVelocityS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val velocity: Vec3 = Vec3(buffer.readShort(), buffer.readShort(), buffer.readShort()) * ProtocolDefinition.VELOCITY_CONSTANT
override fun handle(connection: PlayConnection) {
val entity = connection.world.getEntity(entityId) ?: return
val entity = connection.world.entities[entityId] ?: return
entity.velocity = velocity
}

View File

@ -38,7 +38,7 @@ public class PacketAttachEntity extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -43,7 +43,7 @@ public class PacketDestroyEntity extends PlayS2CPacket {
connection.fireEvent(new EntityDespawnEvent(connection, this));
for (int entityId : getEntityIds()) {
connection.getWorld().removeEntity(entityId);
connection.getWorld().getEntities().remove(entityId);
}
}

View File

@ -53,7 +53,7 @@ public class PacketEntityEffect extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -57,7 +57,7 @@ public class PacketEntityEquipment extends PlayS2CPacket {
public void handle(PlayConnection connection) {
connection.fireEvent(new EntityEquipmentChangeEvent(connection, this));
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -31,7 +31,7 @@ public class PacketEntityHeadRotation extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -32,7 +32,7 @@ class PacketEntityMetadata() : PlayS2CPacket() {
}
override fun handle(connection: PlayConnection) {
val entity = connection.world.getEntity(entityId) ?: return
val entity = connection.world.entities[entityId] ?: return
entity.entityMetaData = entityData
connection.fireEvent(EntityMetaDataChangeEvent(connection, entity))

View File

@ -42,7 +42,7 @@ public class PacketEntityMovement extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -47,7 +47,7 @@ public class PacketEntityMovementAndRotation extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -40,7 +40,7 @@ public class PacketEntityRotation extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -48,7 +48,7 @@ public class PacketEntityTeleport extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -144,7 +144,7 @@ class PacketJoinGame(buffer: PlayInByteBuffer) : PlayS2CPacket() {
connection.mapping.dimensionRegistry.setData(dimensions)
connection.world.dimension = dimension
connection.world.addEntity(entityId, null, playerEntity)
connection.world.entities.add(entityId, null, playerEntity)
connection.world.hashedSeed = hashedSeed
connection.world.biomeAccessor = if (connection.version.versionId < ProtocolVersions.V_19W36A) {
BlockBiomeAccessor(connection.world)

View File

@ -32,7 +32,7 @@ public class PacketRemoveEntityStatusEffect extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
Entity entity = connection.getWorld().getEntity(getEntityId());
Entity entity = connection.getWorld().getEntities().get(getEntityId());
if (entity == null) {
// thanks mojang
return;

View File

@ -45,7 +45,7 @@ public class PacketSpawnExperienceOrb extends PlayS2CPacket {
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, null, getEntity());
connection.getWorld().getEntities().add(this.entityId, null, getEntity());
}
@Override

View File

@ -82,7 +82,7 @@ public class PacketSpawnMob extends PlayS2CPacket {
@Override
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, this.entityUUID, getEntity());
connection.getWorld().getEntities().add(this.entityId, this.entityUUID, getEntity());
this.entity.setVelocity(this.velocity);
}

View File

@ -76,7 +76,7 @@ public class PacketSpawnObject extends PlayS2CPacket {
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, this.entityUUID, getEntity());
connection.getWorld().getEntities().add(this.entityId, this.entityUUID, getEntity());
this.entity.setVelocity(this.velocity);
}

View File

@ -62,7 +62,7 @@ public class PacketSpawnPainting extends PlayS2CPacket {
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, this.entityUUID, getEntity());
connection.getWorld().getEntities().add(this.entityId, this.entityUUID, getEntity());
}
@Override

View File

@ -85,7 +85,7 @@ class PacketSpawnPlayer(buffer: PlayInByteBuffer) : PlayS2CPacket() {
connection.tabList.tabListItems[entityUUID]?.let { entity.tabListItem = it }
connection.fireEvent(EntitySpawnEvent(connection, this))
connection.world.addEntity(entityId, entityUUID, entity)
connection.world.entities.add(entityId, entityUUID, entity)
}
override fun log() {

View File

@ -46,7 +46,7 @@ public class PacketSpawnWeatherEntity extends PlayS2CPacket {
public void handle(PlayConnection connection) {
connection.fireEvent(new EntitySpawnEvent(connection, this));
connection.fireEvent(new LightningBoltSpawnEvent(connection, this));
connection.getWorld().addEntity(this.entityId, null, this.entity);
connection.getWorld().getEntities().add(this.entityId, null, this.entity);
}
@Override

View File

@ -144,7 +144,7 @@ class PacketTabListItem(buffer: PlayInByteBuffer) : PlayS2CPacket() {
continue
}
val entity = connection.world.getEntity(uuid)
val entity = connection.world.entities[uuid]
val tabListItem = connection.tabList.tabListItems[uuid] ?: run {

View File

@ -32,8 +32,8 @@ public class CommandEntities extends Command {
new CommandLiteralNode("list", (connection, stack) -> {
ArrayList<Object[]> tableData = new ArrayList<>();
for (var entry : connection.getWorld().getEntityIdMap().entrySet()) {
tableData.add(new Object[]{entry.getKey(), connection.getWorld().getEntityIdMap().inverse().get(entry.getValue()), entry.getValue().getEntityType().toString(), entry.getValue().getEquipment(), entry.getValue().getPosition(), entry.getValue().getRotation()});
for (var entry : connection.getWorld().getEntities()) {
tableData.add(new Object[]{connection.getWorld().getEntities().getId(entry), connection.getWorld().getEntities().getUUID(entry), entry.getEntityType().toString(), entry.getEquipment(), entry.getPosition(), entry.getRotation()});
}
print(AsciiTable.getTable(new String[]{"ID", "UUID", "TYPE", "EQUIPMENT", "LOCATION", "ROTATION"}, tableData.toArray(new Object[0][0])));
@ -41,15 +41,15 @@ public class CommandEntities extends Command {
new CommandLiteralNode("info", new CommandArgumentNode("entityId", IntegerParser.INTEGER_PARSER, new IntegerParserProperties(0, Integer.MAX_VALUE), (connection, stack) -> {
// ToDo: entity uuids
Entity entity = connection.getWorld().getEntity(stack.getInt(0));
Entity entity = connection.getWorld().getEntities().get(stack.getInt(0));
if (entity == null) {
printError("Entity %d not found!", stack.getInt(0));
return;
}
ArrayList<Object[]> tableData = new ArrayList<>();
tableData.add(new Object[]{"Entity id", connection.getWorld().getEntityIdMap().inverse().get(entity)});
tableData.add(new Object[]{"UUID", connection.getWorld().getEntityUUIDMap().inverse().get(entity)});
tableData.add(new Object[]{"Entity id", connection.getWorld().getEntities().getId(entity)});
tableData.add(new Object[]{"UUID", connection.getWorld().getEntities().getUUID(entity)});
tableData.add(new Object[]{"Type", entity.getEntityType()});
tableData.add(new Object[]{"Class", entity.getClass().getName()});
tableData.add(new Object[]{"Location", entity.getPosition()});

View File

@ -69,8 +69,8 @@ public class CommandTabList extends Command {
ArrayList<Object[]> tableData = new ArrayList<>();
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;
PlayerEntity playerEntity = (PlayerEntity) connection.getWorld().getEntities().get(entry.getKey());
Integer entityId = playerEntity != null ? connection.getWorld().getEntities().getId(playerEntity) : null;
tableData.add(new Object[]{entry.getKey(), entityId, entry.getValue().getName(), entry.getValue().getDisplayName(), entry.getValue().getGamemode(), entry.getValue().getPing() + "ms"});
}