Class scanning now distinguishes side effectful plugins from our pure content interfaces
Server store is now loaded and parsed ***before*** side effectful plugins
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package core.game.system;
|
||||
|
||||
import api.PersistWorld;
|
||||
import api.ShutdownListener;
|
||||
import core.game.ge.GrandExchangeDatabase;
|
||||
import core.game.interaction.object.dmc.DMCHandler;
|
||||
@@ -52,6 +53,7 @@ public final class SystemTermination {
|
||||
}
|
||||
}
|
||||
GameWorld.getShutdownListeners().forEach(ShutdownListener::shutdown);
|
||||
GameWorld.getWorldPersists().forEach(PersistWorld::save);
|
||||
if(ServerConstants.DATA_PATH != null)
|
||||
save(ServerConstants.DATA_PATH);
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package api
|
||||
|
||||
interface PersistWorld : ContentInterface {
|
||||
fun save()
|
||||
fun parse()
|
||||
}
|
||||
@@ -67,8 +67,6 @@ object Server {
|
||||
}
|
||||
startTime = System.currentTimeMillis()
|
||||
val t = TimeStamp()
|
||||
SystemLogger.logInfo("Initializing Server Store...")
|
||||
SystemLogger.logInfo("Initialized ${ServerStore.counter} store files.")
|
||||
GameWorld.prompt(true)
|
||||
SQLManager.init()
|
||||
Runtime.getRuntime().addShutdownHook(ServerConstants.SHUTDOWN_HOOK)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package rs09
|
||||
|
||||
import api.PersistWorld
|
||||
import api.ShutdownListener
|
||||
import api.StartupListener
|
||||
import org.json.simple.JSONArray
|
||||
@@ -13,8 +14,8 @@ import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import javax.script.ScriptEngineManager
|
||||
|
||||
class ServerStore : StartupListener, ShutdownListener {
|
||||
override fun startup() {
|
||||
class ServerStore : PersistWorld {
|
||||
override fun parse() {
|
||||
logStartup("Parsing server store...")
|
||||
val dir = File(ServerConstants.STORE_PATH!!)
|
||||
if(!dir.exists()){
|
||||
@@ -41,9 +42,11 @@ class ServerStore : StartupListener, ShutdownListener {
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
logStartup("Initialized $counter store files.")
|
||||
}
|
||||
|
||||
override fun shutdown() {
|
||||
override fun save() {
|
||||
logShutdown("Saving server store...")
|
||||
val dir = File(ServerConstants.DATA_PATH + File.separator + "serverstore")
|
||||
if(!dir.exists()){
|
||||
|
||||
@@ -4,14 +4,12 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ConfigParser {
|
||||
fun prePlugin() {
|
||||
fun parseConfigs() {
|
||||
NPCConfigParser().load()
|
||||
ItemConfigParser().load()
|
||||
ObjectConfigParser().load()
|
||||
XteaParser().load()
|
||||
InterfaceConfigParser().load()
|
||||
}
|
||||
fun postPlugin() {
|
||||
ShopParser().load()
|
||||
DropTableParser().load()
|
||||
NPCSpawner().load()
|
||||
|
||||
@@ -13,9 +13,7 @@ import core.game.world.map.RegionManager
|
||||
import core.plugin.CorePluginTypes.StartupPlugin
|
||||
import core.tools.RandomFunction
|
||||
import core.tools.mysql.DatabaseManager
|
||||
import rs09.game.ai.general.scriptrepository.PlayerScripts
|
||||
import rs09.ServerConstants
|
||||
import rs09.game.node.entity.state.newsys.StateRepository
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.system.SystemLogger.logInfo
|
||||
import rs09.game.system.config.ConfigParser
|
||||
@@ -32,6 +30,8 @@ import kotlin.collections.ArrayList
|
||||
* @author Ceikry
|
||||
*/
|
||||
object GameWorld {
|
||||
@JvmStatic
|
||||
val worldPersists = ArrayList<PersistWorld>()
|
||||
|
||||
/**
|
||||
* The major update worker.
|
||||
@@ -160,9 +160,11 @@ object GameWorld {
|
||||
Cache.init(ServerConstants.CACHE_PATH)
|
||||
databaseManager = DatabaseManager(ServerConstants.DATABASE)
|
||||
databaseManager!!.connect()
|
||||
configParser.prePlugin()
|
||||
ClassScanner.scanAndLoad()
|
||||
configParser.postPlugin()
|
||||
ConfigParser().parseConfigs()
|
||||
ClassScanner.scanClasspath()
|
||||
ClassScanner.loadPureInterfaces()
|
||||
worldPersists.forEach { it.parse() }
|
||||
ClassScanner.loadSideEffectfulPlugins()
|
||||
startupListeners.forEach { it.startup() }
|
||||
if (run) {
|
||||
SystemManager.flag(if (settings?.isDevMode == true) SystemState.PRIVATE else SystemState.ACTIVE)
|
||||
|
||||
@@ -11,21 +11,19 @@ import core.game.node.entity.player.link.quest.QuestRepository
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.MapZone
|
||||
import core.game.world.map.zone.ZoneBuilder
|
||||
import core.game.world.map.zone.ZoneMonitor
|
||||
import core.plugin.Plugin
|
||||
import core.plugin.PluginManifest
|
||||
import core.plugin.PluginType
|
||||
import io.github.classgraph.ClassGraph
|
||||
import io.github.classgraph.ClassInfo
|
||||
import io.github.classgraph.ScanResult
|
||||
import rs09.game.ai.general.scriptrepository.PlayerScripts
|
||||
import rs09.game.interaction.InteractionListener
|
||||
import rs09.game.interaction.InterfaceListener
|
||||
import rs09.game.interaction.Listener
|
||||
import rs09.game.node.entity.player.info.login.PlayerSaveParser
|
||||
import rs09.game.node.entity.player.info.login.PlayerSaver
|
||||
import rs09.game.node.entity.skill.magic.SpellListener
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.system.command.Command
|
||||
import rs09.game.system.SystemLogger.logStartup
|
||||
import rs09.game.world.GameWorld
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
@@ -37,11 +35,14 @@ import java.util.function.Consumer
|
||||
object ClassScanner {
|
||||
var disabledPlugins = HashMap<String, Boolean>()
|
||||
/**
|
||||
* The amount of plugins loaded.
|
||||
* The amount of content interfaces loaded.
|
||||
*/
|
||||
var amountLoaded = 0
|
||||
private set
|
||||
|
||||
var numPlugins = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* The currently loaded plugin names.
|
||||
*/
|
||||
@@ -52,16 +53,20 @@ object ClassScanner {
|
||||
*/
|
||||
private val lastLoaded: String? = null
|
||||
|
||||
lateinit var scanResults: ScanResult
|
||||
|
||||
@JvmStatic fun scanClasspath() {
|
||||
scanResults = ClassGraph().enableClassInfo().enableAnnotationInfo().scan()
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the classpath for reflection-loaded content classes such as listeners, "plugins", etc
|
||||
*/
|
||||
@JvmStatic
|
||||
fun scanAndLoad() {
|
||||
fun loadPureInterfaces() {
|
||||
try {
|
||||
load()
|
||||
loadedPlugins!!.clear()
|
||||
loadedPlugins = null
|
||||
SystemLogger.logInfo("Initialized $amountLoaded plugins...")
|
||||
loadContentInterfacesFrom(scanResults)
|
||||
logStartup("Loaded $amountLoaded content interfaces.")
|
||||
} catch (t: Throwable) {
|
||||
SystemLogger.logErr("Error initializing Plugins -> " + t.localizedMessage + " for file -> " + lastLoaded)
|
||||
t.printStackTrace()
|
||||
@@ -71,13 +76,8 @@ object ClassScanner {
|
||||
}
|
||||
}
|
||||
|
||||
fun load() {
|
||||
val result = ClassGraph().enableClassInfo().enableAnnotationInfo().scan()
|
||||
result.getClassesWithAnnotation("core.plugin.Initializable").forEach(Consumer { p: ClassInfo ->
|
||||
val clazz = p.loadClass().newInstance()
|
||||
if(clazz is Plugin<*>) definePlugin(clazz)
|
||||
})
|
||||
result.getClassesImplementing("api.ContentInterface").filter { !it.isAbstract }.forEach {
|
||||
private fun loadContentInterfacesFrom(scanResults: ScanResult) {
|
||||
scanResults.getClassesImplementing("api.ContentInterface").filter { !it.isAbstract }.forEach {
|
||||
try {
|
||||
val clazz = it.loadClass().newInstance()
|
||||
if(clazz is LoginListener) GameWorld.loginListeners.add(clazz)
|
||||
@@ -85,6 +85,7 @@ object ClassScanner {
|
||||
if(clazz is TickListener) GameWorld.tickListeners.add(clazz)
|
||||
if(clazz is StartupListener) GameWorld.startupListeners.add(clazz)
|
||||
if(clazz is ShutdownListener) GameWorld.shutdownListeners.add(clazz)
|
||||
if(clazz is PersistWorld) GameWorld.worldPersists.add(clazz)
|
||||
if(clazz is InteractionListener) clazz.defineListeners().also { clazz.defineDestinationOverrides() }
|
||||
if(clazz is InterfaceListener) clazz.defineInterfaceListeners()
|
||||
if(clazz is Commands) clazz.defineCommands()
|
||||
@@ -115,12 +116,35 @@ object ClassScanner {
|
||||
SystemLogger.logInfo("Configured zone: ${clazz.javaClass.simpleName + "MapArea"}")
|
||||
MapArea.zoneMaps[clazz.javaClass.simpleName + "MapArea"] = zone
|
||||
}
|
||||
amountLoaded++
|
||||
} catch (e: Exception) {
|
||||
SystemLogger.logErr("Error loading content: ${it.simpleName}, ${e.localizedMessage}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
result.getClassesWithAnnotation("rs09.game.ai.general.scriptrepository.PlayerCompatible").forEach { res ->
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun loadSideEffectfulPlugins() {
|
||||
try {
|
||||
loadedPlugins!!.clear()
|
||||
loadPluginsFrom(scanResults)
|
||||
logStartup("We still have $numPlugins legacy plugins being loaded.")
|
||||
} catch (t: Throwable) {
|
||||
SystemLogger.logErr("Error initializing Plugins -> " + t.localizedMessage + " for file -> " + lastLoaded)
|
||||
t.printStackTrace()
|
||||
} catch (e: Exception) {
|
||||
SystemLogger.logErr("Error initializing Plugins -> " + e.localizedMessage + " for file -> " + lastLoaded)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPluginsFrom(scanResults: ScanResult) {
|
||||
scanResults.getClassesWithAnnotation("core.plugin.Initializable").forEach(Consumer { p: ClassInfo ->
|
||||
val clazz = p.loadClass().newInstance()
|
||||
if(clazz is Plugin<*>) definePlugin(clazz)
|
||||
})
|
||||
scanResults.getClassesWithAnnotation("rs09.game.ai.general.scriptrepository.PlayerCompatible").forEach { res ->
|
||||
val description = res.getAnnotationInfo("rs09.game.ai.general.scriptrepository.ScriptDescription").parameterValues[0].value as Array<String>
|
||||
val identifier = res.getAnnotationInfo("rs09.game.ai.general.scriptrepository.ScriptIdentifier").parameterValues[0].value.toString()
|
||||
val name = res.getAnnotationInfo("rs09.game.ai.general.scriptrepository.ScriptName").parameterValues[0].value.toString()
|
||||
@@ -171,7 +195,7 @@ object ClassScanner {
|
||||
else -> SystemLogger.logWarn("Unknown Manifest: " + manifest.type)
|
||||
}
|
||||
}
|
||||
amountLoaded++
|
||||
numPlugins++
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ object TestUtils {
|
||||
if(ServerConstants.DATA_PATH == null) {
|
||||
ServerConfigParser.parse(this::class.java.getResource("test.conf"))
|
||||
Cache.init(this::class.java.getResource("cache").path.toString())
|
||||
ConfigParser().prePlugin()
|
||||
ConfigParser().postPlugin()
|
||||
ConfigParser().parseConfigs()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user