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