improve multi threading with entities

This commit is contained in:
Bixilon 2022-03-03 23:56:50 +01:00
parent d889198573
commit bd7bb0fe74
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 108 additions and 47 deletions

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -69,15 +69,8 @@ open class BlockItem(
}
val collisionShape = placeBlockState.collisionShape + placePosition
for (entity in connection.world.entities) {
if (entity.isInvisible) {
continue
}
val aabb = entity.aabb
if (collisionShape.intersect(aabb)) {
return InteractionResults.CONSUME
}
if (connection.world.entities.isEntityIn(collisionShape)) {
return InteractionResults.CONSUME
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -13,11 +13,11 @@
package de.bixilon.minosoft.data.world
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.registries.VoxelShape
import glm_.vec3.Vec3d
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
@ -26,79 +26,122 @@ import java.util.*
class WorldEntities : Iterable<Entity> {
private val idEntityMap: Int2ObjectOpenHashMap<Entity> = Int2ObjectOpenHashMap()
private val entityIdMap: Object2IntOpenHashMap<Entity> = Object2IntOpenHashMap()
private val entityUUIDMap: MutableMap<Entity, UUID> = synchronizedMapOf()
private val uuidEntityMap: MutableMap<UUID, Entity> = synchronizedMapOf()
private val entityUUIDMap: MutableMap<Entity, UUID> = mutableMapOf()
private val uuidEntityMap: MutableMap<UUID, Entity> = mutableMapOf()
private val entities: MutableSet<Entity> = mutableSetOf()
val lock = SimpleLock()
val size: Int
get() = idEntityMap.size
get() = entities.size
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
try {
lock.lock()
entities += entity
if (entityId != null) {
idEntityMap[entityId] = entity
entityIdMap[entity] = entityId
}
if (entityUUID != null) {
uuidEntityMap[entityUUID] = entity
entityUUIDMap[entity] = entityUUID
}
} finally {
lock.unlock()
}
}
operator fun get(id: Int): Entity? {
return idEntityMap[id]
try {
lock.acquire()
return idEntityMap[id]
} finally {
lock.release()
}
}
fun getId(entity: Entity): Int? {
return entityIdMap[entity]
try {
lock.acquire()
return entityIdMap[entity]
} finally {
lock.release()
}
}
operator fun get(uuid: UUID): Entity? {
return uuidEntityMap[uuid]
try {
lock.acquire()
return uuidEntityMap[uuid]
} finally {
lock.release()
}
}
fun getUUID(entity: Entity): UUID? {
return entityUUIDMap[entity]
try {
lock.acquire()
return entityUUIDMap[entity]
} finally {
lock.release()
}
}
fun remove(entity: Entity) {
entityIdMap[entity]?.let {
idEntityMap.remove(it)
lock.lock()
if (!entities.remove(entity)) {
lock.unlock()
return
}
entityIdMap.remove(entity)
entityUUIDMap[entity]?.let {
uuidEntityMap.remove(it)
val id = entityIdMap.remove(entity)
if (id != null) {
idEntityMap.remove(id)
}
entityUUIDMap.remove(entity)
val uuid = entityUUIDMap.remove(entity)
if (uuid != null) {
uuidEntityMap.remove(uuid)
}
lock.unlock()
}
fun remove(entityId: Int) {
idEntityMap[entityId]?.let { remove(it) }
lock.lock()
val entity = idEntityMap.remove(entityId)
if (entity == null) {
lock.unlock()
return
}
entities.remove(entity)
entityIdMap.remove(entity)
val uuid = entityUUIDMap.remove(entity)
if (uuid != null) {
uuidEntityMap.remove(uuid)
}
lock.unlock()
}
fun remove(entityUUID: UUID) {
uuidEntityMap[entityUUID]?.let { remove(it) }
}
@Deprecated("ToDo: Lock")
override fun iterator(): Iterator<Entity> {
return uuidEntityMap.toSynchronizedMap().values.iterator()
return entities.iterator()
}
fun getInRadius(position: Vec3d, distance: Double, check: (Entity) -> Boolean): List<Entity> {
// ToDo: Improve performance
val ret: MutableList<Entity> = mutableListOf()
val entities = idEntityMap.toSynchronizedMap().values
val entities: MutableList<Entity> = mutableListOf()
lock.acquire()
for (entity in entities) {
for (entity in this) {
if ((entity.position - position).length() > distance) {
continue
}
if (check(entity)) {
ret += entity
entities += entity
}
}
return ret.toList()
lock.release()
return entities
}
fun getClosestInRadius(position: Vec3d, distance: Double, check: (Entity) -> Boolean): Entity? {
@ -117,6 +160,25 @@ class WorldEntities : Iterable<Entity> {
return closestEntity
}
fun isEntityIn(shape: VoxelShape): Boolean {
try {
lock.acquire()
for (entity in this) {
if (entity.isInvisible) {
continue
}
val aabb = entity.aabb
if (shape.intersect(aabb)) {
return true
}
}
} finally {
lock.release()
}
return false
}
companion object {
val CHECK_CLOSEST_PLAYER: (Entity) -> Boolean = check@{
if (it !is PlayerEntity) {

View File

@ -58,6 +58,7 @@ class TargetHandler(
var currentHit: EntityTarget? = null
val originF = Vec3(origin)
connection.world.entities.lock.acquire()
for (entity in connection.world.entities) {
if (entity is LocalPlayerEntity) {
continue
@ -73,8 +74,8 @@ class TargetHandler(
continue
}
currentHit = EntityTarget(origin + direction * target.distance, target.distance, target.direction, entity)
}
connection.world.entities.lock.release()
return currentHit
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -107,12 +107,15 @@ class EntityHitboxRenderer(
private fun updateEnabled() {
if (setAvailable) {
connection.world.entities.lock.acquire()
for (entity in connection.world.entities) {
if (entity is LocalPlayerEntity && !profile.showLocal) {
continue
}
meshes[entity] = EntityHitbox(this, entity, frustum)
}
connection.world.entities.lock.release()
} else {
for (mesh in meshes.values) {
mesh.unload()

View File

@ -163,9 +163,11 @@ class PlayConnection(
CLI.setCurrentConnection(this)
}
entityTickTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME / 5, maxDelayTime = ProtocolDefinition.TICK_TIME) {
world.entities.lock.acquire()
for (entity in world.entities) {
entity.tick()
}
world.entities.lock.release()
}
TimeWorker += entityTickTask