More networking work
This commit is contained in:
parent
0eea0fa13f
commit
8671c4bfad
@ -2,7 +2,7 @@ kotlin.code.style=official
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
|
||||
|
||||
kotlinVersion=1.9.0
|
||||
kommonsVersion=1.7.8
|
||||
kommonsVersion=1.7.9
|
||||
|
||||
ffiVersion=2.2.13
|
||||
lwjglVersion=3.3.0
|
||||
|
@ -40,6 +40,7 @@ fun main() {
|
||||
|
||||
val server = IntegratedStarboundServer(File("./"))
|
||||
val client = StarboundClient.create().get()
|
||||
//val client2 = StarboundClient.create().get()
|
||||
val world = ServerWorld(server, 0L, WorldGeometry(Vector2i(3000, 2000), true, false))
|
||||
world.addChunkSource(LegacyChunkSource(db))
|
||||
world.thread.start()
|
||||
@ -81,10 +82,12 @@ fun main() {
|
||||
}
|
||||
|
||||
client.connectToLocalServer(server.channels.createLocalChannel(), UUID.randomUUID())
|
||||
//client2.connectToLocalServer(server.channels.createLocalChannel(), UUID.randomUUID())
|
||||
}
|
||||
|
||||
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||
client.camera.pos = Vector2d(238.0, 685.0)
|
||||
//client2.camera.pos = Vector2d(238.0, 685.0)
|
||||
//client.camera.pos = Vector2f(0f, 0f)
|
||||
|
||||
//ent.spawn()
|
||||
|
@ -13,7 +13,7 @@ import java.util.concurrent.locks.LockSupport
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
abstract class StarboundServer(val root: File) : Closeable {
|
||||
sealed class StarboundServer(val root: File) : Closeable {
|
||||
init {
|
||||
if (!root.exists()) {
|
||||
check(root.mkdirs()) { "Unable to create ${root.absolutePath}" }
|
||||
@ -37,7 +37,7 @@ abstract class StarboundServer(val root: File) : Closeable {
|
||||
private set
|
||||
|
||||
init {
|
||||
thread.isDaemon = true
|
||||
thread.isDaemon = this is IntegratedStarboundServer
|
||||
thread.start()
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
|
||||
if (pos !in tickets) {
|
||||
val ticket = world.permanentChunkTicket(pos)
|
||||
tickets[pos] = ticket
|
||||
ticket.addListener(ChunkListener(pos))
|
||||
ticket.listener = ChunkListener(pos)
|
||||
pendingSend.add(pos)
|
||||
}
|
||||
}
|
||||
|
@ -185,16 +185,21 @@ class ServerWorld(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChunkCreated(chunk: ServerChunk) {
|
||||
ticketMap[chunk.pos.toLong()]?.let { chunk.addListener(it) }
|
||||
}
|
||||
|
||||
override fun onChunkRemoved(chunk: ServerChunk) {
|
||||
ticketMap[chunk.pos.toLong()]?.let { chunk.removeListener(it) }
|
||||
}
|
||||
|
||||
interface ITicket {
|
||||
fun cancel()
|
||||
val isCanceled: Boolean
|
||||
val pos: ChunkPos
|
||||
val id: Int
|
||||
|
||||
val chunk: ServerChunk?
|
||||
|
||||
fun addListener(listener: IChunkListener)
|
||||
fun removeListener(listener: IChunkListener)
|
||||
var listener: IChunkListener?
|
||||
}
|
||||
|
||||
interface ITimedTicket : ITicket, Comparable<ITimedTicket> {
|
||||
@ -208,7 +213,7 @@ class ServerWorld(
|
||||
}
|
||||
}
|
||||
|
||||
private inner class TicketList(val pos: ChunkPos) : IChunkListener, IChunkMapListener<ServerChunk> {
|
||||
private inner class TicketList(val pos: ChunkPos) : IChunkListener {
|
||||
constructor(pos: Long) : this(ChunkPos(pos))
|
||||
|
||||
private var first = true
|
||||
@ -216,7 +221,6 @@ class ServerWorld(
|
||||
private val temporary = ObjectAVLTreeSet<TimedTicket>()
|
||||
private var ticks = 0
|
||||
private var nextTicketID = AtomicInteger()
|
||||
private var weAreResponsibleForLoadingTheChunk = false
|
||||
|
||||
val isValid: Boolean
|
||||
get() = temporary.isNotEmpty() || permanent.isNotEmpty()
|
||||
@ -234,33 +238,21 @@ class ServerWorld(
|
||||
}
|
||||
|
||||
override fun onEntityAdded(entity: AbstractEntity) {
|
||||
permanent.forEach { it.onEntityAdded(entity) }
|
||||
temporary.forEach { it.onEntityAdded(entity) }
|
||||
permanent.forEach { it.listener?.onEntityAdded(entity) }
|
||||
temporary.forEach { it.listener?.onEntityAdded(entity) }
|
||||
}
|
||||
|
||||
override fun onEntityRemoved(entity: AbstractEntity) {
|
||||
permanent.forEach { it.onEntityRemoved(entity) }
|
||||
temporary.forEach { it.onEntityRemoved(entity) }
|
||||
permanent.forEach { it.listener?.onEntityRemoved(entity) }
|
||||
temporary.forEach { it.listener?.onEntityRemoved(entity) }
|
||||
}
|
||||
|
||||
override fun onCellChanges(x: Int, y: Int, cell: ImmutableCell) {
|
||||
permanent.forEach { it.onCellChanges(x, y, cell) }
|
||||
temporary.forEach { it.onCellChanges(x, y, cell) }
|
||||
permanent.forEach { it.listener?.onCellChanges(x, y, cell) }
|
||||
temporary.forEach { it.listener?.onCellChanges(x, y, cell) }
|
||||
}
|
||||
|
||||
override fun onChunkCreated(chunk: ServerChunk) {
|
||||
if (chunk.pos == pos) {
|
||||
chunk.addListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChunkRemoved(chunk: ServerChunk) {
|
||||
if (chunk.pos == pos) {
|
||||
chunk.removeListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
abstract inner class AbstractTicket : ITicket, IChunkListener {
|
||||
abstract inner class AbstractTicket : ITicket {
|
||||
final override val id: Int = nextTicketID.getAndIncrement()
|
||||
final override val pos: ChunkPos
|
||||
get() = this@TicketList.pos
|
||||
@ -273,11 +265,10 @@ class ServerWorld(
|
||||
|
||||
if (geometry.x.inBoundsChunk(pos.x) && geometry.y.inBoundsChunk(pos.y)) {
|
||||
ticketLists.add(this@TicketList)
|
||||
chunkMap.addListener(this@TicketList)
|
||||
|
||||
if (chunkProviders.isNotEmpty() && chunkMap[pos] == null) {
|
||||
weAreResponsibleForLoadingTheChunk = true
|
||||
val existing = chunkMap[pos]
|
||||
|
||||
if (chunkProviders.isNotEmpty() && existing == null) {
|
||||
chainOptionalFutures(chunkProviders)
|
||||
{ if (!isValid) CompletableFuture.completedFuture(KOptional.empty()) else it.getTiles(pos) }
|
||||
.thenAccept(Consumer { tiles ->
|
||||
@ -297,8 +288,12 @@ class ServerWorld(
|
||||
}
|
||||
}, mailbox)
|
||||
})
|
||||
} else if (existing != null) {
|
||||
existing.addListener(this@TicketList)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chunkMap[pos]?.addListener(this@TicketList)
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +303,7 @@ class ServerWorld(
|
||||
lock.withLock {
|
||||
if (isCanceled) return
|
||||
isCanceled = true
|
||||
chunk?.entities?.forEach { e -> listeners.forEach { it.onEntityRemoved(e) } }
|
||||
chunk?.entities?.forEach { e -> listener?.onEntityRemoved(e) }
|
||||
onCancel()
|
||||
}
|
||||
}
|
||||
@ -317,31 +312,15 @@ class ServerWorld(
|
||||
final override val chunk: ServerChunk?
|
||||
get() = chunkMap[pos]
|
||||
|
||||
private val listeners = ReferenceLinkedOpenHashSet<IChunkListener>()
|
||||
|
||||
final override fun addListener(listener: IChunkListener) {
|
||||
if (isCanceled) return
|
||||
listeners.add(listener)
|
||||
chunk?.entities?.forEach { listener.onEntityAdded(it) }
|
||||
}
|
||||
|
||||
final override fun removeListener(listener: IChunkListener) {
|
||||
if (listeners.remove(listener)) {
|
||||
chunk?.entities?.forEach { listener.onEntityRemoved(it) }
|
||||
final override var listener: IChunkListener? = null
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
val chunk = chunk
|
||||
chunk?.entities?.forEach { e -> field?.onEntityRemoved(e) }
|
||||
chunk?.entities?.forEach { e -> value?.onEntityAdded(e) }
|
||||
field = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final override fun onEntityAdded(entity: AbstractEntity) {
|
||||
listeners.forEach { it.onEntityAdded(entity) }
|
||||
}
|
||||
|
||||
final override fun onEntityRemoved(entity: AbstractEntity) {
|
||||
listeners.forEach { it.onEntityRemoved(entity) }
|
||||
}
|
||||
|
||||
final override fun onCellChanges(x: Int, y: Int, cell: ImmutableCell) {
|
||||
listeners.forEach { it.onCellChanges(x, y, cell) }
|
||||
}
|
||||
}
|
||||
|
||||
inner class Ticket : AbstractTicket() {
|
||||
|
@ -158,11 +158,21 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
||||
}
|
||||
|
||||
fun addListener(subscriber: IChunkListener): Boolean {
|
||||
return subscribers.add(subscriber)
|
||||
if (subscribers.add(subscriber)) {
|
||||
entities.forEach { subscriber.onEntityAdded(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeListener(subscriber: IChunkListener): Boolean {
|
||||
return subscribers.remove(subscriber)
|
||||
if (subscribers.remove(subscriber)) {
|
||||
entities.forEach { subscriber.onEntityRemoved(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun addEntity(entity: AbstractEntity) {
|
||||
|
@ -53,10 +53,8 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
return chunkMap.setCell(x, y, cell)
|
||||
}
|
||||
|
||||
interface IChunkMapListener<ChunkType : Chunk<*, *>> {
|
||||
fun onChunkCreated(chunk: ChunkType) { }
|
||||
fun onChunkRemoved(chunk: ChunkType) { }
|
||||
}
|
||||
protected open fun onChunkCreated(chunk: ChunkType) { }
|
||||
protected open fun onChunkRemoved(chunk: ChunkType) { }
|
||||
|
||||
abstract inner class ChunkMap : Iterable<ChunkType> {
|
||||
abstract operator fun get(x: Int, y: Int): ChunkType?
|
||||
@ -71,16 +69,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
operator fun get(pos: ChunkPos) = get(pos.x, pos.y)
|
||||
|
||||
protected val listeners = ReferenceOpenHashSet<IChunkMapListener<ChunkType>>()
|
||||
|
||||
fun addListener(listener: IChunkMapListener<ChunkType>) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeListener(listener: IChunkMapListener<ChunkType>) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
protected fun create(x: Int, y: Int): ChunkType {
|
||||
val pos = ChunkPos(x, y)
|
||||
val chunk = chunkFactory(pos)
|
||||
@ -96,7 +84,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
ent.chunk = chunk
|
||||
}
|
||||
|
||||
listeners.forEach { it.onChunkCreated(chunk) }
|
||||
return chunk
|
||||
}
|
||||
|
||||
@ -123,7 +110,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
if (!geometry.x.inBoundsChunk(x) || !geometry.y.inBoundsChunk(y)) return null
|
||||
|
||||
val index = ChunkPos.toLong(x, y)
|
||||
val get = map[index] ?: create(x, y).also { map[index] = it }
|
||||
val get = map[index] ?: create(x, y).also { map[index] = it; onChunkCreated(it) }
|
||||
return get
|
||||
}
|
||||
|
||||
@ -146,7 +133,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.remove()
|
||||
listeners.forEach { it.onChunkRemoved(chunk) }
|
||||
onChunkRemoved(chunk)
|
||||
map.remove(index)
|
||||
}
|
||||
}
|
||||
@ -169,7 +156,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
override fun compute(x: Int, y: Int): ChunkType? {
|
||||
if (!geometry.x.inBoundsChunk(x) || !geometry.y.inBoundsChunk(y)) return null
|
||||
return map[x, y] ?: create(x, y).also { existing.add(ChunkPos(x, y)); map[x, y] = it }
|
||||
return map[x, y] ?: create(x, y).also { existing.add(ChunkPos(x, y)); map[x, y] = it; onChunkCreated(it) }
|
||||
}
|
||||
|
||||
override fun getCell(x: Int, y: Int): AbstractCell {
|
||||
@ -199,7 +186,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.remove()
|
||||
listeners.forEach { it.onChunkRemoved(chunk) }
|
||||
onChunkRemoved(chunk)
|
||||
existing.remove(ChunkPos(x, y))
|
||||
map[x, y] = null
|
||||
}
|
||||
@ -266,7 +253,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
}
|
||||
|
||||
protected abstract fun thinkInner()
|
||||
|
||||
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType
|
||||
|
||||
override fun close() {
|
||||
|
@ -17,7 +17,7 @@ import kotlin.math.acos
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
abstract class AbstractMovementController {
|
||||
abstract class AbstractMovementController() {
|
||||
abstract val world: World<*, *>
|
||||
|
||||
val localHitboxes: Stream<Poly>
|
||||
|
Loading…
Reference in New Issue
Block a user