Skip to content

Commit

Permalink
✨ Implement /si load to reload script
Browse files Browse the repository at this point in the history
✨ Add @file:ImportScripts for script share
:sparkles: Add MapDb for DataStore
:sparkles: Add onEnable,onDisable,enabled for Item
  • Loading branch information
way-zer committed Mar 5, 2020
1 parent 41fbc0e commit 9b37f2f
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 26 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ dependencies{
compile "org.jetbrains.kotlin:kotlin-script-util:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-scripting-jvm-host:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "org.mapdb:mapdb:3.0.7"

compileOnly "org.spigotmc:spigot-api:$mc_version"
compileOnly "net.md-5:bungeecord-chat:$bc_version"
Expand Down
22 changes: 17 additions & 5 deletions src/main/kotlin/cf/wayzer/SuperItem/Commander.kt
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,23 @@ class Commander : CommandExecutor {
s.sendMessage("§c请输入Path")
return
}
if (!File(ItemManager.rootDir,args[1]).exists()){
s.sendMessage("§c请输入Path")
return
}
TODO("From path to get item name")
val file = File(ItemManager.rootDir,args[1])
if (!file.exists())
return s.sendMessage("§c请输入Path")
if(file.extension!="kts")
return s.sendMessage("§c只有脚本允许重载")
val name = file.name.removeSuffix(".superitem.kts")
ItemManager.getItem(name)?.let{
s.sendMessage("§a发现旧实例存在,尝试卸载")
ItemManager.unregisterItem(it)
s.sendMessage("§a发现旧实例存在,卸载成功")
}
s.sendMessage("§a开始加载脚本,可能会有所卡顿")
ItemManager.loadFile(file,"")?.let {
ItemManager.registerItem(it)
return s.sendMessage("§a脚本加载成功")
}
return s.sendMessage("§c脚本加载失败,查看后台以了解错误信息")
}

private fun help(s: CommandSender) {
Expand Down
33 changes: 30 additions & 3 deletions src/main/kotlin/cf/wayzer/SuperItem/Item.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,38 @@ import java.util.logging.Logger
*/
abstract class Item : Listener {
open class Builder(override val packageName: String,override val name:String):Item(){
private var disableF = fun(){}
private var enableF = fun(){}
override fun loadFeatures() {}
override fun onDisable() {
super.onDisable()
disableF()
}

@Suppress("unused")
inline fun <reified T:Event>listen(ignoreCancelled:Boolean=false, priority: EventPriority = EventPriority.NORMAL, crossinline handle:(T)->Unit){
Bukkit.getServer().pluginManager.registerEvent(T::class.java,this,priority, { _, event -> if(event is T)handle(event) },pluginMain,ignoreCancelled)
override fun onEnable() {
super.onEnable()
enableF()
}

fun register(){
ItemManager.registerItem(this)
}

fun bindDisable(h:()->Unit){ disableF = h }
fun bindEnable(h:()->Unit){ enableF = h }
}
/**
* 获取默认物品
*/
abstract fun loadFeatures()
open fun onEnable(){
enabled = true
}
open fun onDisable(){
enabled = false
}

var enabled = false
val features : MutableMap<Class<*>,MutableList<Feature<*>>> = mutableMapOf()

open val name: String
Expand All @@ -45,6 +61,17 @@ abstract class Item : Listener {
val logger: Logger
get() = Logger.getLogger("SI-$packageName-$name")

fun <T:Event>listen(cls:Class<T>,ignoreCancelled:Boolean=false, priority: EventPriority = EventPriority.NORMAL, handle:(T)->Unit){
Bukkit.getServer().pluginManager.registerEvent(cls,this,priority, { _, event ->
@Suppress("UNCHECKED_CAST")
if(enabled && cls.isInstance(event))handle(event as T)
},pluginMain,ignoreCancelled)
}

inline fun <reified T:Event>listen(ignoreCancelled:Boolean=false, priority: EventPriority = EventPriority.NORMAL, noinline handle:(T)->Unit){
listen(T::class.java,ignoreCancelled, priority, handle)
}


/**
* 安全的获取指定类型的feature
Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/cf/wayzer/SuperItem/ItemManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import cf.wayzer.SuperItem.features.NBT
import cf.wayzer.SuperItem.features.Permission
import cf.wayzer.SuperItem.scripts.ScriptSupporter
import org.bukkit.Material
import org.bukkit.event.HandlerList
import org.bukkit.inventory.ItemStack
import java.io.File
import java.net.URLClassLoader
Expand Down Expand Up @@ -101,13 +102,16 @@ object ItemManager {
main.server.pluginManager.registerEvents(it.listener, main)
}
}
item.onEnable()
items[item.name] = item
main.server.pluginManager.registerEvents(item, main)
logger.info("注册物品成功: ${item.name}")
}

fun unregisterItem(item: Item){
items.remove(item.name,item)
HandlerList.unregisterAll(item)
item.onDisable()
item.features.values.flatten().forEach {
if(it is Feature.OnDisable)
it.onDisable(main)
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/cf/wayzer/SuperItem/Main.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cf.wayzer.SuperItem

import cf.wayzer.SuperItem.features.DataStore
import cf.wayzer.libraryManager.Dependency
import cf.wayzer.libraryManager.LibraryManager
import org.bukkit.plugin.java.JavaPlugin
Expand All @@ -20,6 +21,8 @@ class Main : JavaPlugin() {
}

override fun onDisable() {
DataStore.fileDB.close()
DataStore.memoryDB.close()
ItemManager.getItems().toList().forEach(ItemManager::unregisterItem)
}

Expand All @@ -37,6 +40,14 @@ class Main : JavaPlugin() {
require(Dependency("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"))
require(Dependency("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"))
require(Dependency("org.jetbrains:annotations:13.0"))

require(Dependency("org.mapdb:mapdb:3.0.7"))
require(Dependency("org.eclipse.collections:eclipse-collections:10.1.0"))
require(Dependency("org.eclipse.collections:eclipse-collections-api:10.1.0"))
require(Dependency("org.eclipse.collections:eclipse-collections-forkjoin:10.1.0"))
require(Dependency("com.google.guava:guava:28.1-jre"))
require(Dependency("net.jpountz.lz4:lz4:1.3.0"))
require(Dependency("org.mapdb:elsa:3.0.0-M5"))
loadToClassLoader(Main::class.java.classLoader)
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/cf/wayzer/SuperItem/features/DataStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cf.wayzer.SuperItem.Feature
import cf.wayzer.SuperItem.Main
import org.bukkit.metadata.FixedMetadataValue
import org.bukkit.metadata.Metadatable
import org.mapdb.DBMaker

interface DataStore<T>{
fun set(o: Metadatable,value: T?)
Expand All @@ -23,5 +24,10 @@ interface DataStore<T>{
else o.setMetadata(key,FixedMetadataValue(Main.main,value))
}
}
companion object{
val fileDB = DBMaker.fileDB(Main.main.dataFolder.resolve("data.mapdb"))
.fileMmapEnableIfSupported().transactionEnable().closeOnJvmShutdown().make()
val memoryDB = DBMaker.heapDB().make()
}
//TODO other Store: SQL and File
}
4 changes: 1 addition & 3 deletions src/main/kotlin/cf/wayzer/SuperItem/features/NBT.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import cf.wayzer.SuperItem.Feature
import cf.wayzer.SuperItem.Main
import de.tr7zw.changeme.nbtapi.NBTCompound
import de.tr7zw.changeme.nbtapi.NBTItem
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod
import org.bukkit.inventory.ItemStack
import java.util.logging.Level

Expand Down Expand Up @@ -75,8 +74,7 @@ class NBT(override vararg val defaultData: AttributeModifier) : Feature<Array<ou
fun read(item: ItemStack): NBTCompound? = NBTItem(item).let { if (it.hasNBTData()) it else null }
fun readOrCreate(item: ItemStack): NBTCompound = NBTItem(item)
fun write(item: ItemStack,nbt:NBTCompound){
val stack = ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, item)
ReflectionMethod.ITEMSTACK_SET_TAG.run(stack, nbt.compound)
item.itemMeta = (nbt as NBTItem).item.itemMeta
}
operator fun NBTCompound.set(key:String,v:Int) {
setInteger(key,v)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import java.io.File
import java.nio.file.Paths
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.FileBasedScriptSource
import kotlin.script.experimental.host.FileScriptSource
import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder
import kotlin.script.experimental.jvm.dependenciesFromClassloader
import kotlin.script.experimental.jvm.jvm
Expand All @@ -18,29 +20,53 @@ import kotlin.script.experimental.jvm.util.classpathFromClass
object CompilationConfiguration: ScriptCompilationConfiguration({
jvm {
dependenciesFromClassloader(
"kotlin-stdlib"
"kotlin-stdlib",
"mapdb"
,classLoader = ScriptLoader::class.java.classLoader)
dependenciesFromClass(Bukkit::class, Item::class)
}
defaultImports(Item::class, ImportClass::class,MavenDepends::class,Material::class)
defaultImports(Item::class, ImportClass::class,MavenDepends::class,ImportScript::class,Material::class)
defaultImports.append("cf.wayzer.SuperItem.features.*")
refineConfiguration{
onAnnotations(ImportClass::class){ context->
val annotations = context.collectedData?.get(ScriptCollectedData.foundAnnotations)?.filter { it.annotationClass== ImportClass::class }?: listOf()
val classes = annotations.map { Class.forName((it as ImportClass).name).kotlin}
val diagnostics = classes.map { ScriptDiagnostic("[Info]PluginDependency: ${it.java.name}",ScriptDiagnostic.Severity.INFO) }
ScriptCompilationConfiguration(context.compilationConfiguration) {
jvm {
dependenciesFromClass(*classes.toTypedArray())
onAnnotations(ImportClass::class,MavenDepends::class,ImportScript::class) {context->
val annotations = context.collectedData?.get(ScriptCollectedData.foundAnnotations)
val diagnostics = mutableListOf<ScriptDiagnostic>()
val scriptBaseDir = (context.script as? FileBasedScriptSource)?.file?.parentFile

val importClasses = mutableListOf<KClass<out Any>>()
val dependencies = mutableListOf<Dependency>()
val importScriptSources = mutableListOf<FileScriptSource>()

annotations?.forEach {
when(it){
is ImportClass -> {
try {
Class.forName(it.name).kotlin.also {cls->
importClasses.add(cls)
diagnostics.add(ScriptDiagnostic("[Info]PluginDependency: ${cls.java.name}",ScriptDiagnostic.Severity.INFO))
}
}catch (e : ClassNotFoundException){
diagnostics.add(ScriptDiagnostic("Can't find ImportClass: ${it.name}",ScriptDiagnostic.Severity.FATAL))
}
}
is MavenDepends -> {
Dependency(it.name,it.repo).also {d->
dependencies.add(d)
ScriptDiagnostic("[Info]MavenDependency: $d",ScriptDiagnostic.Severity.INFO)
}
}
is ImportScript -> {
importScriptSources.add(FileScriptSource(scriptBaseDir?.resolve(it.path) ?: File(it.path)))
ScriptDiagnostic("[Info]ImportScript: ${it.path}",ScriptDiagnostic.Severity.INFO)
}
}
}.asSuccess(diagnostics)
}
onAnnotations(MavenDepends::class){ context->
val annotations = context.collectedData?.get(ScriptCollectedData.foundAnnotations)?.filter { it.annotationClass== MavenDepends::class }?: listOf()
val dependencies = annotations.map {Dependency((it as MavenDepends).name,it.repo)}
val diagnostics = dependencies.map { ScriptDiagnostic("[Info]MavenDependency: $it",ScriptDiagnostic.Severity.INFO) }
}
ScriptCompilationConfiguration(context.compilationConfiguration) {
defaultImports.invoke(*importClasses.toTypedArray())
jvm {
dependenciesFromClass(*importClasses.toTypedArray())

if(dependencies.isNotEmpty())
LibraryManager(Paths.get("lib")).apply {
addAliYunMirror()
dependencies.forEach {
Expand All @@ -50,6 +76,7 @@ object CompilationConfiguration: ScriptCompilationConfiguration({
updateClasspath(loadFiles())
}
}
importScripts.append(importScriptSources)
}.asSuccess(diagnostics)
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/cf/wayzer/SuperItem/scripts/ImportScript.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package cf.wayzer.SuperItem.scripts

@Target(AnnotationTarget.FILE)
@Retention(AnnotationRetention.SOURCE)
@Repeatable
annotation class ImportScript (
val path:String
)

0 comments on commit 9b37f2f

Please sign in to comment.