Now root mechanics is properly handled by damageTiles
This commit is contained in:
parent
b50f356f7e
commit
d9de575de6
@ -3,7 +3,8 @@ package ru.dbotthepony.kstarbound.server.world
|
|||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
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 it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.future.asCompletableFuture
|
import kotlinx.coroutines.future.asCompletableFuture
|
||||||
@ -52,7 +53,6 @@ import java.util.concurrent.CopyOnWriteArrayList
|
|||||||
import java.util.concurrent.RejectedExecutionException
|
import java.util.concurrent.RejectedExecutionException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import java.util.stream.Collectors
|
|
||||||
|
|
||||||
class ServerWorld private constructor(
|
class ServerWorld private constructor(
|
||||||
val server: StarboundServer,
|
val server: StarboundServer,
|
||||||
@ -169,7 +169,9 @@ class ServerWorld private constructor(
|
|||||||
if (damage.amount <= 0.0)
|
if (damage.amount <= 0.0)
|
||||||
return TileDamageResult.NONE
|
return TileDamageResult.NONE
|
||||||
|
|
||||||
val actualPositions = ObjectArraySet<Pair<Vector2i, ServerChunk?>>()
|
data class TileToDamage(val position: Vector2i, val chunk: ServerChunk?, val roots: MutableList<TileEntity> = ArrayList(0))
|
||||||
|
|
||||||
|
val actualPositions = ObjectArraySet<TileToDamage>()
|
||||||
|
|
||||||
for (pos in positions) {
|
for (pos in positions) {
|
||||||
val wrapped = geometry.wrap(pos)
|
val wrapped = geometry.wrap(pos)
|
||||||
@ -179,58 +181,92 @@ class ServerWorld private constructor(
|
|||||||
val cell = chunk.getCell(wrapped - chunk.pos.tile)
|
val cell = chunk.getCell(wrapped - chunk.pos.tile)
|
||||||
|
|
||||||
if (cell.rootSource != null) {
|
if (cell.rootSource != null) {
|
||||||
actualPositions.add(geometry.wrap(cell.rootSource!!) to chunk)
|
actualPositions.add(TileToDamage(wrapped, chunk, entityIndex.tileEntitiesAt(geometry.wrap(cell.rootSource!!))))
|
||||||
} else {
|
} else {
|
||||||
actualPositions.add(wrapped to chunk)
|
actualPositions.add(TileToDamage(wrapped, chunk))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actualPositions.add(wrapped to chunk)
|
actualPositions.add(TileToDamage(wrapped, chunk))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var topMost = TileDamageResult.NONE
|
var topMost = TileDamageResult.NONE
|
||||||
val damagedEntities = ObjectArraySet<TileEntity>()
|
val toDamageEntities = Object2ObjectArrayMap<TileEntity, ObjectArraySet<Vector2i>>()
|
||||||
|
val entityDamageResults = HashMap<Vector2i, TileDamageResult>()
|
||||||
|
|
||||||
for ((pos, chunk) in actualPositions) {
|
for ((pos, chunk, roots) in actualPositions) {
|
||||||
var damage = damage
|
for (root in roots) {
|
||||||
var tileEntityResult = TileDamageResult.NONE
|
toDamageEntities.computeIfAbsent(root, Object2ObjectFunction { ObjectArraySet() }).add(pos)
|
||||||
|
|
||||||
val getCell = chunk?.getCell(pos - chunk.pos.tile)
|
|
||||||
|
|
||||||
if (getCell != null) {
|
|
||||||
if (getCell.dungeonId in protectedDungeonIDs) {
|
|
||||||
damage = damage.copy(type = TileDamageType.PROTECTED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isBackground) {
|
if (!isBackground) {
|
||||||
for (entity in entitiesAtTile(pos)) {
|
for (entity in entitiesAtTile(pos)) {
|
||||||
if (!damagedEntities.add(entity)) continue
|
toDamageEntities.computeIfAbsent(entity, Object2ObjectFunction { ObjectArraySet() }).add(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val occupySpaces = entity.occupySpaces.stream()
|
val killedEntities = ObjectArraySet<TileEntity>()
|
||||||
.filter { p -> actualPositions.any { it.first == p } }
|
|
||||||
.toList()
|
|
||||||
|
|
||||||
pacer?.consume(10)
|
for ((entity, damagePositions) in toDamageEntities.entries) {
|
||||||
val broken = entity.damage(occupySpaces, sourcePosition, damage)
|
var actualDamage = damage
|
||||||
|
|
||||||
if (source != null && broken) {
|
for (pos in damagePositions) {
|
||||||
source.receiveMessage("tileEntityBroken", jsonArrayOf(pos, entity.type.jsonName, (entity as? WorldObject)?.config?.key))
|
val cell = getCell(pos)
|
||||||
}
|
|
||||||
|
|
||||||
if (damage.type == TileDamageType.PROTECTED)
|
if (cell.dungeonId in protectedDungeonIDs) {
|
||||||
tileEntityResult = TileDamageResult.PROTECTED
|
actualDamage = actualDamage.copy(type = TileDamageType.PROTECTED)
|
||||||
else
|
entityDamageResults[pos] = TileDamageResult.PROTECTED
|
||||||
tileEntityResult = TileDamageResult.NORMAL
|
} 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
|
// Penetrating damage should carry through to the blocks behind this
|
||||||
// entity.
|
// entity.
|
||||||
if (tileEntityResult == TileDamageResult.NONE || damage.type.isPenetrating) {
|
if (tileEntityResult == TileDamageResult.NONE || actualDamage.type.isPenetrating) {
|
||||||
chunk ?: continue
|
chunk ?: continue
|
||||||
pacer?.consume()
|
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)
|
topMost = topMost.coerceAtLeast(result)
|
||||||
|
|
||||||
if (source != null && health?.isDead == true) {
|
if (source != null && health?.isDead == true) {
|
||||||
|
@ -717,6 +717,8 @@ class PlantEntity() : TileEntity() {
|
|||||||
} else {
|
} else {
|
||||||
remove(RemovalReason.DYING)
|
remove(RemovalReason.DYING)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
Loading…
Reference in New Issue
Block a user