From d9de575de60a5c79b3fe22cf527bbb7c83bfc7d7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 22 Apr 2024 17:51:21 +0700 Subject: [PATCH] Now root mechanics is properly handled by damageTiles --- .../kstarbound/server/world/ServerWorld.kt | 100 ++++++++++++------ .../world/entities/tile/PlantEntity.kt | 2 + 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt index 973854b6..0b6e8937 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt @@ -3,7 +3,8 @@ package ru.dbotthepony.kstarbound.server.world import com.google.gson.JsonElement import com.google.gson.JsonObject import it.unimi.dsi.fastutil.ints.IntArraySet -import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.ObjectArraySet import kotlinx.coroutines.async import kotlinx.coroutines.future.asCompletableFuture @@ -52,7 +53,6 @@ import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.RejectedExecutionException import java.util.concurrent.TimeUnit import java.util.function.Supplier -import java.util.stream.Collectors class ServerWorld private constructor( val server: StarboundServer, @@ -169,7 +169,9 @@ class ServerWorld private constructor( if (damage.amount <= 0.0) return TileDamageResult.NONE - val actualPositions = ObjectArraySet>() + data class TileToDamage(val position: Vector2i, val chunk: ServerChunk?, val roots: MutableList = ArrayList(0)) + + val actualPositions = ObjectArraySet() for (pos in positions) { val wrapped = geometry.wrap(pos) @@ -179,58 +181,92 @@ class ServerWorld private constructor( val cell = chunk.getCell(wrapped - chunk.pos.tile) if (cell.rootSource != null) { - actualPositions.add(geometry.wrap(cell.rootSource!!) to chunk) + actualPositions.add(TileToDamage(wrapped, chunk, entityIndex.tileEntitiesAt(geometry.wrap(cell.rootSource!!)))) } else { - actualPositions.add(wrapped to chunk) + actualPositions.add(TileToDamage(wrapped, chunk)) } } else { - actualPositions.add(wrapped to chunk) + actualPositions.add(TileToDamage(wrapped, chunk)) } } var topMost = TileDamageResult.NONE - val damagedEntities = ObjectArraySet() + val toDamageEntities = Object2ObjectArrayMap>() + val entityDamageResults = HashMap() - for ((pos, chunk) in actualPositions) { - var damage = damage - var tileEntityResult = TileDamageResult.NONE - - val getCell = chunk?.getCell(pos - chunk.pos.tile) - - if (getCell != null) { - if (getCell.dungeonId in protectedDungeonIDs) { - damage = damage.copy(type = TileDamageType.PROTECTED) - } + for ((pos, chunk, roots) in actualPositions) { + for (root in roots) { + toDamageEntities.computeIfAbsent(root, Object2ObjectFunction { ObjectArraySet() }).add(pos) } if (!isBackground) { for (entity in entitiesAtTile(pos)) { - if (!damagedEntities.add(entity)) continue + toDamageEntities.computeIfAbsent(entity, Object2ObjectFunction { ObjectArraySet() }).add(pos) + } + } + } - val occupySpaces = entity.occupySpaces.stream() - .filter { p -> actualPositions.any { it.first == p } } - .toList() + val killedEntities = ObjectArraySet() - pacer?.consume(10) - val broken = entity.damage(occupySpaces, sourcePosition, damage) + for ((entity, damagePositions) in toDamageEntities.entries) { + var actualDamage = damage - if (source != null && broken) { - source.receiveMessage("tileEntityBroken", jsonArrayOf(pos, entity.type.jsonName, (entity as? WorldObject)?.config?.key)) - } + for (pos in damagePositions) { + val cell = getCell(pos) - if (damage.type == TileDamageType.PROTECTED) - tileEntityResult = TileDamageResult.PROTECTED - else - tileEntityResult = TileDamageResult.NORMAL + if (cell.dungeonId in protectedDungeonIDs) { + actualDamage = actualDamage.copy(type = TileDamageType.PROTECTED) + entityDamageResults[pos] = TileDamageResult.PROTECTED + } else { + entityDamageResults[pos] = TileDamageResult.NORMAL + } + } + + val occupySpaces = entity.occupySpaces.stream() + .filter { p -> p in damagePositions } + .toList() + + pacer?.consume(10) + val broken = entity.damage(occupySpaces, sourcePosition, actualDamage) + + if (source != null && broken) { + source.receiveMessage("tileEntityBroken", jsonArrayOf( + damagePositions.firstOrNull { p -> actualPositions.any { it.position == p } } ?: entity.tilePosition, + entity.type.jsonName, + (entity as? WorldObject)?.config?.key)) + } + + if (broken) { + killedEntities.add(entity) + + for (pos in damagePositions) { + entityDamageResults.remove(pos) + } + } + } + + actualPositions.removeIf { + it.roots.removeIf { it in killedEntities } + it.roots.isNotEmpty() + } + + for ((pos, chunk) in actualPositions) { + var actualDamage = damage + val tileEntityResult = entityDamageResults[pos] ?: TileDamageResult.NONE + val getCell = chunk?.getCell(pos - chunk.pos.tile) + + if (getCell != null) { + if (getCell.dungeonId in protectedDungeonIDs) { + actualDamage = actualDamage.copy(type = TileDamageType.PROTECTED) } } // Penetrating damage should carry through to the blocks behind this // entity. - if (tileEntityResult == TileDamageResult.NONE || damage.type.isPenetrating) { + if (tileEntityResult == TileDamageResult.NONE || actualDamage.type.isPenetrating) { chunk ?: continue pacer?.consume() - val (result, health, tile) = chunk.damageTile(pos - chunk.pos.tile, isBackground, sourcePosition, damage, source) + val (result, health, tile) = chunk.damageTile(pos - chunk.pos.tile, isBackground, sourcePosition, actualDamage, source) topMost = topMost.coerceAtLeast(result) if (source != null && health?.isDead == true) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/PlantEntity.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/PlantEntity.kt index 32e6f5bc..7ff55924 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/PlantEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/PlantEntity.kt @@ -717,6 +717,8 @@ class PlantEntity() : TileEntity() { } else { remove(RemovalReason.DYING) } + + return true } return false