New dynamic region abstraction, consumed in construction

This commit is contained in:
Ceikry
2022-05-03 23:18:11 +00:00
committed by Ryan
parent 8438ecdbd7
commit a5f9c64dbb
26 changed files with 745 additions and 177 deletions
@@ -0,0 +1,34 @@
package api.regionspec
import api.regionspec.contracts.*
import core.game.world.map.Region
import core.game.world.map.RegionChunk
import core.game.world.map.RegionPlane
import core.game.world.map.build.DynamicRegion
class RegionSpecification(val regionContract: RegionSpecContract = EmptyRegionContract(), vararg val chunkContracts: ChunkSpecContract = arrayOf(EmptyChunkContract())) {
constructor(vararg chunkContracts: ChunkSpecContract) : this(EmptyRegionContract(), *chunkContracts)
fun build(): DynamicRegion {
val dyn = regionContract.instantiateRegion()
Region.load(dyn)
chunkContracts.forEach { it.populateChunks(dyn) }
return dyn
}
}
fun fillWith(chunk: RegionChunk?): FillChunkContract {
return FillChunkContract(chunk)
}
fun fillWith(delegate: (Int, Int, Int, Region) -> RegionChunk?) : FillChunkContract {
return FillChunkContract(delegate)
}
fun copyOf(regionId: Int): RegionSpecContract {
return CloneRegionContract(regionId)
}
fun using(region: DynamicRegion) : UseExistingRegionContract {
return UseExistingRegionContract(region)
}
@@ -0,0 +1,7 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
interface ChunkSpecContract {
fun populateChunks(dyn: DynamicRegion)
}
@@ -0,0 +1,9 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
class CloneRegionContract(val regionId: Int) : RegionSpecContract {
override fun instantiateRegion(): DynamicRegion {
return DynamicRegion.create(regionId)
}
}
@@ -0,0 +1,7 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
class EmptyChunkContract : ChunkSpecContract {
override fun populateChunks(dyn: DynamicRegion) {}
}
@@ -0,0 +1,11 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
class EmptyRegionContract : RegionSpecContract {
override fun instantiateRegion(): DynamicRegion {
val borders = DynamicRegion.reserveArea(8,8)
val dyn = DynamicRegion(borders)
return dyn
}
}
@@ -0,0 +1,54 @@
package api.regionspec.contracts
import core.game.world.map.BuildRegionChunk
import core.game.world.map.Region
import core.game.world.map.RegionChunk
import core.game.world.map.build.DynamicRegion
open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract {
constructor(chunk: (Int, Int, Int, Region) -> RegionChunk?) : this(null) {this.chunkDelegate = chunk}
lateinit var sourceRegion: Region
var planes: IntArray = intArrayOf(0)
var replaceCondition: (Int,Int,Int) -> Boolean = {_,_,_ -> true}
var chunkDelegate: (Int, Int, Int, Region) -> RegionChunk? = {_,_,_,_ -> chunk}
override fun populateChunks(dyn: DynamicRegion) {
for(plane in planes) {
for(x in 0 until 8)
for(y in 0 until 8)
if(replaceCondition.invoke(x,y,plane)) {
val chunk = getChunk(x,y,plane,dyn)
dyn.replaceChunk(
plane,
x,
y,
chunk,
sourceRegion
)
afterSetting(chunk, x, y, plane, dyn)
}
}
}
open fun getChunk(x: Int, y: Int, plane: Int, dyn: DynamicRegion) : BuildRegionChunk? {
return chunkDelegate.invoke(x, y, plane, sourceRegion)?.copy(dyn.planes[plane])
}
open fun afterSetting(chunk: BuildRegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) {}
fun from(region: Region): FillChunkContract {
this.sourceRegion = region
return this
}
fun onPlanes(vararg planes: Int) : FillChunkContract {
this.planes = planes
return this
}
fun onCondition(cond: (Int,Int,Int) -> Boolean): FillChunkContract {
this.replaceCondition = cond
return this
}
}
@@ -0,0 +1,7 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
interface RegionSpecContract {
fun instantiateRegion(): DynamicRegion
}
@@ -0,0 +1,9 @@
package api.regionspec.contracts
import core.game.world.map.build.DynamicRegion
class UseExistingRegionContract(val region: DynamicRegion) : RegionSpecContract {
override fun instantiateRegion(): DynamicRegion {
return region;
}
}
@@ -137,7 +137,7 @@ class EstateAgentDialogue : DialoguePlugin {
7 -> {
if (player.inventory.contains(995, 1000)) {
player.inventory.remove(Item(995, 1000))
player.houseManager.create(HouseLocation.RIMMINGTON)
player.houseManager.createNewHouseAt(HouseLocation.RIMMINGTON)
npc(
"Thank you. Go through the Rimmington house portal",
"and you will find your house ready for you to start",
@@ -10,6 +10,7 @@ import rs09.game.system.SystemLogger
import rs09.game.world.GameSettings
import rs09.game.world.GameWorld
import java.io.File
import java.net.URL
import kotlin.system.exitProcess
/**
@@ -23,8 +24,17 @@ object ServerConfigParser {
fun parse(path: String){
confFile = File(parsePath(path))
parseFromFile(confFile)
}
fun parse(path: URL?) {
confFile = File(path!!.toURI())
parseFromFile(confFile)
}
private fun parseFromFile(confFile: File?) {
if(!confFile!!.canonicalFile.exists()){
SystemLogger.logErr("${confFile!!.canonicalFile} does not exist in the current working directory.")
SystemLogger.logErr("${confFile.canonicalFile} does not exist.")
exitProcess(0)
} else {
try {
@@ -32,7 +42,7 @@ object ServerConfigParser {
parseServerSettings()
parseGameSettings()
} catch (e: java.lang.IllegalStateException) {
SystemLogger.logErr("Passed config file is not a TOML file. Path: ${confFile!!.canonicalPath}")
SystemLogger.logErr("Passed config file is not a TOML file. Path: ${confFile.canonicalPath}")
SystemLogger.logErr("Exception received: $e")
SystemLogger.logAlert("Shutting down...")
exitProcess(0)
@@ -41,55 +41,9 @@ class MajorUpdateWorker {
Thread.sleep(600L)
while(true){
val start = System.currentTimeMillis()
val rmlist = ArrayList<Pulse>()
val list = ArrayList(GameWorld.Pulser.TASKS)
Server.heartbeat()
GlobalScope.launch {
//run our pulses
for (pulse in list) {
val b = System.currentTimeMillis()
if (pulse == null || pulse.update()) rmlist.add(pulse)
val time = System.currentTimeMillis() - b
if (time >= 100) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("CRITICALLY Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("CRITICALLY long running pulse: ${pulse.javaClass.name} - $time ms")
}
} else if (time >= 30) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("Long Running Pulse: ${pulse.javaClass.name} - $time ms")
}
}
}
//remove all null or finished pulses from the list
rmlist.forEach {
if (GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
}
rmlist.clear()
//perform our update sequence where we write masks, etc
try {
sequence.start()
sequence.run()
sequence.end()
} catch (e: Exception) {
e.printStackTrace()
}
//increment global ticks variable
GameWorld.pulse()
//disconnect all players waiting to be disconnected
Repository.disconnectionQueue.update()
GameWorld.tickListeners.forEach { it.tick() }
//tick all manager plugins
Managers.tick()
}
GlobalScope.launch { handleTickActions() }
//Handle daily restart if enabled
if(sdf.format(Date()).toInt() == 0){
@@ -123,6 +77,54 @@ class MajorUpdateWorker {
}
}
fun handleTickActions() {
val rmlist = ArrayList<Pulse>()
val list = ArrayList(GameWorld.Pulser.TASKS)
//run our pulses
for (pulse in list) {
val b = System.currentTimeMillis()
if (pulse == null || pulse.update()) rmlist.add(pulse)
val time = System.currentTimeMillis() - b
if (time >= 100) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("CRITICALLY Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("CRITICALLY long running pulse: ${pulse.javaClass.name} - $time ms")
}
} else if (time >= 30) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("Long Running Pulse: ${pulse.javaClass.name} - $time ms")
}
}
}
//remove all null or finished pulses from the list
rmlist.forEach {
if (GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
}
rmlist.clear()
//perform our update sequence where we write masks, etc
try {
sequence.start()
sequence.run()
sequence.end()
} catch (e: Exception) {
e.printStackTrace()
}
//increment global ticks variable
GameWorld.pulse()
//disconnect all players waiting to be disconnected
Repository.disconnectionQueue.update()
GameWorld.tickListeners.forEach { it.tick() }
//tick all manager plugins
Managers.tick()
}
fun start() {
if(!started){
worker.start()