Skip to content

Commit 8538ab1

Browse files
committed
(coreLibrary)add ConfigApi.kt
(coreLibrary)rewrite PlaceHoldApi.kt (coreLibrary)document DataStoreApi.kt (coreLibrary)document AsyncApi.kt (renamed from ScheduleTaskApi.kt)
1 parent dd32e3f commit 8538ab1

File tree

7 files changed

+205
-20
lines changed

7 files changed

+205
-20
lines changed

build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66

77
group = "cf.wayzer"
88
version = "v1.x.x" //采用3位版本号v1.2.3 1为大版本 2为插件版本 3为脚本版本
9-
val libraryVersion = "1.1.2"
9+
val libraryVersion = "1.1.3"
1010
val mcVersion = "1.14-R0.1-SNAPSHOT"
1111

1212
gitVersioning.apply(closureOf<me.qoomon.gradle.gitversioning.GitVersioningPluginConfig> {
@@ -26,6 +26,7 @@ repositories {
2626
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
2727

2828
maven("https://repo.codemc.org/repository/maven-public")//nbt-api
29+
maven("https://dl.bintray.com/config4k/config4k")//config4k
2930
}
3031
sourceSets {
3132
main {
@@ -52,6 +53,7 @@ dependencies {
5253
api("cf.wayzer:PlaceHoldLib:2.0")
5354
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1")
5455
implementation("com.h2database:h2-mvstore:1.4.200")
56+
implementation("io.github.config4k:config4k:0.4.1")
5557
}
5658

5759
tasks {

src/coreBukkit.init.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ addDefaultImport("org.bukkit.ChatColor.*")
2424
generateHelper()
2525

2626
onEnable{
27+
DataStoreApi.open(Config.pluginMain.dataFolder.resolve("dataStore.db").path)
28+
ConfigBuilder.init(Config.pluginMain.dataFolder.resolve("config.conf"))
2729
Config.pluginCommand.setExecutor(PluginCommander)
2830
}
2931

32+
onDisable{
33+
DataStoreApi.close()
34+
}
35+
3036
onAfterContentEnable { child ->
3137
child.listens.forEach {
3238
Bukkit.getPluginManager().registerEvent(it.cls, child.listener, it.priority, it, Config.pluginMain, it.ignoreCancelled)

src/coreLibrary.init.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@file:MavenDepends("cf.wayzer:PlaceHoldLib:2.0","https://dl.bintray.com/way-zer/maven/")
22
@file:MavenDepends("com.h2database:h2-mvstore:1.4.200")
3+
@file:MavenDepends("io.github.config4k:config4k:0.4.1")
4+
@file:MavenDepends("com.typesafe:config:1.3.3")
35
@file:ImportByClass("kotlinx.coroutines.GlobalScope")
46
name="ScriptAgent 库模块"
57
/*

src/coreLibrary/lib/ScheduleTaskApi.kt renamed to src/coreLibrary/lib/AsyncApi.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
@file:Suppress("unused")
2+
13
package coreLibrary.lib
24

5+
/**
6+
* 异步Api
7+
* 目前有两种异步接口
8+
* Timer和协程
9+
*/
310
import kotlinx.coroutines.*
411
import java.util.*
512

src/coreLibrary/lib/ConfigApi.kt

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
@file:Suppress("MemberVisibilityCanBePrivate", "unused")
2+
3+
package coreLibrary.lib
4+
5+
/**
6+
* 配置Api
7+
* 用于定义脚本的配置项
8+
* 配置项可在文件中或者使用指令修改
9+
* @sample
10+
* val welcomeMsg by config.key("Hello Steve","The message show when player join")
11+
* println(welcomeMsg)
12+
*/
13+
import cf.wayzer.script_agent.IBaseScript
14+
import cf.wayzer.script_agent.IContentScript
15+
import cf.wayzer.script_agent.util.DSLBuilder
16+
import com.typesafe.config.*
17+
import com.typesafe.config.Config
18+
import io.github.config4k.ClassContainer
19+
import io.github.config4k.TypeReference
20+
import io.github.config4k.readers.SelectReader
21+
import java.io.File
22+
import kotlin.reflect.KClass
23+
import kotlin.reflect.KProperty
24+
25+
open class ConfigBuilder(private val path: String) {
26+
/**
27+
* @param desc only display the first line using command
28+
*/
29+
data class ConfigKey<T : Any>(val path: String, val default: T, val desc: List<String>) {
30+
fun get(): T {
31+
val v = fileConfig.extract(default::class,path) ?: return default
32+
if(default.javaClass.isInstance(v))
33+
return default.javaClass.cast(v)
34+
error("Wrong config type: $path get $v")
35+
}
36+
37+
fun set(v: T) {
38+
fileConfig = if (v == default) {
39+
if (!fileConfig.hasPath(path)) return
40+
fileConfig.withoutPath(path)
41+
} else {
42+
fileConfig.withValue(path, ConfigValueFactory.fromAnyRef(v)
43+
.withOrigin(ConfigOriginFactory.newSimple().withComments(desc)))
44+
}
45+
saveFile()
46+
}
47+
fun getString(): String {
48+
return ConfigFactory.parseMap(mapOf(path to get())).getValue(path).render()
49+
}
50+
51+
/**
52+
* @return format like [getString]
53+
* @throws IllegalArgumentException when parse fail
54+
*/
55+
fun setString(strV:String):String{
56+
val str = "$path = $strV"
57+
val v = ConfigFactory.parseString(str).extract(default::class,path)
58+
if(default.javaClass.isInstance(v)){
59+
set(default.javaClass.cast(v))
60+
return str
61+
}
62+
throw IllegalArgumentException("Parse \"$str\" fail: get $v")
63+
}
64+
65+
operator fun getValue(thisRef: Any?, prop: KProperty<*>) = get()
66+
operator fun setValue(thisRef: Any?, prop: KProperty<*>, v: T) = set(v)
67+
companion object{
68+
/**
69+
* Copy from config4k as can't use reified param
70+
*/
71+
fun <T:Any> Config.extract(cls: KClass<T>, path: String):Any?{
72+
if(!hasPath(path))return null
73+
val genericType = object : TypeReference<T>() {}.genericType()
74+
return SelectReader.getReader(ClassContainer(cls, genericType)).invoke(this,path)
75+
}
76+
}
77+
}
78+
79+
fun child(sub: String) = ConfigBuilder("$path.$sub")
80+
fun <T:Any> key(default: T, vararg desc: String) = DSLBuilder.Companion.ProvideDelegate<IBaseScript,ConfigKey<T>>{script,name->
81+
val key = ConfigKey("$path.$name", default, desc.toList())
82+
script.configs.add(key)
83+
return@ProvideDelegate key
84+
}
85+
86+
companion object {
87+
val IBaseScript.configs by DSLBuilder.dataKeyWithDefault { mutableSetOf<ConfigKey<*>>() }
88+
private lateinit var configFile: File
89+
private lateinit var fileConfig: Config
90+
fun init(configFile: File) {
91+
this.configFile = configFile
92+
reloadFile()
93+
}
94+
95+
fun reloadFile() {
96+
fileConfig = ConfigFactory.parseFile(configFile)
97+
}
98+
99+
fun saveFile() {
100+
configFile.writeText(fileConfig.root().render(ConfigRenderOptions.defaults().setOriginComments(false)))
101+
}
102+
}
103+
}
104+
105+
val globalConfig = ConfigBuilder("global")
106+
val IContentScript.config get() = ConfigBuilder("scripts.${clsName}")

src/coreLibrary/lib/DataStoreApi.kt

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,33 @@
1+
@file:Suppress("unused")
2+
13
package coreLibrary.lib
24

5+
/**
6+
* 持久储存Api
7+
* 可将该Api作为数据库使用
8+
* @sample
9+
* var DataStoreApi.DataEntity.testKey by dataStoreKey("money"){0}
10+
* playerData["fakeUUID"].run {
11+
* println(testKey)
12+
* testKey+=50
13+
* println(testKey)
14+
* }
15+
*/
316
import cf.wayzer.script_agent.IContentScript
417
import org.h2.mvstore.MVStore
5-
import org.h2.mvstore.tx.TransactionStore
618
import kotlin.reflect.KProperty
719

820
object DataStoreApi {
921
private lateinit var db: MVStore
10-
private val transDB by lazy { TransactionStore(db) }
1122

1223
class DataStoreKey<T : Any>(private val name: String, private val cls: Class<T>, private val default: DataEntity.() -> T) {
1324
operator fun getValue(t: DataEntity, prop: KProperty<*>): T {
1425
val inst = t.data[name]
15-
@Suppress("UNCHECKED_CAST")
16-
return if (inst != null && cls.isInstance(inst)) inst as T
26+
return if (cls.isInstance(inst)) cls.cast(inst)
1727
else default(t)
1828
}
1929

20-
operator fun setValue(t: RWDataEntity, prop: KProperty<*>, v: T?) {
30+
operator fun setValue(t: DataEntity, prop: KProperty<*>, v: T?) {
2131
if (v == null) t.data.remove(name)
2232
else t.data[name] = v
2333
}
@@ -31,18 +41,7 @@ object DataStoreApi {
3141
operator fun contains(key: String): Boolean = db.hasMap("$name@$key")
3242
}
3343

34-
open class DataEntity(val key: String, val data: MutableMap<String, Any>) {
35-
open fun transaction(body: RWDataEntity.() -> Unit) {
36-
transDB.begin().apply {
37-
body(RWDataEntity(key, openMap(key)))
38-
if (hasChanges()) commit()
39-
}
40-
}
41-
}
42-
43-
class RWDataEntity(key: String, data: MutableMap<String, Any>) : DataEntity(key, data) {
44-
override fun transaction(body: RWDataEntity.() -> Unit) = error("Already in transaction")
45-
}
44+
open class DataEntity(val key: String, val data: MutableMap<String, Any>)
4645

4746
fun open(filePath: String) {
4847
db = MVStore.Builder().fileName(filePath).compress().open()!!

src/coreLibrary/lib/PlaceHoldApi.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,72 @@
1+
@file:Suppress("unused")
2+
13
package coreLibrary.lib
24

5+
/**
6+
* 可用做解析带变量的字符串
7+
* 也可用于脚本间共享数据或者接口
8+
* 暴露数据或接口时,注意类型所在的生命周期
9+
*/
10+
311
import cf.wayzer.placehold.PlaceHoldApi
412
import cf.wayzer.placehold.PlaceHoldContext
13+
import cf.wayzer.placehold.TypeBinder
14+
import cf.wayzer.script_agent.IBaseScript
15+
import cf.wayzer.script_agent.util.DSLBuilder
16+
import kotlin.reflect.KProperty
517

6-
val PlaceHoldApi = PlaceHoldApi
718
typealias PlaceHoldString = PlaceHoldContext
819

9-
fun String.with(vararg arg:Pair<String,Any>):PlaceHoldString = PlaceHoldApi.getContext(this,arg.toMap())
20+
object PlaceHold {
21+
class PlaceHoldKey<T>(val name: String,private val cls:Class<T>){
22+
operator fun getValue(thisRef: Any?,prop:KProperty<*>):T{
23+
val v = PlaceHoldApi.GlobalContext.getVar(name)
24+
if(cls.isInstance(v))return cls.cast(v)
25+
error("Can't get globalVar: $name get $v")
26+
}
27+
}
28+
class TypePlaceHoldKey<R>(val name:String,private val cls:Class<R>){
29+
operator fun <T:Any> getValue(thisRef: T,prop:KProperty<*>):R{
30+
val v = PlaceHoldApi.GlobalContext.typeResolve(thisRef,name)
31+
if(cls.isInstance(v))return cls.cast(v)
32+
error("Can't get typeVar $name: FROM $thisRef GET $v")
33+
}
34+
}
35+
// Map of name to description
36+
val IBaseScript.registeredVars by DSLBuilder.dataKeyWithDefault { mutableMapOf<String,String>() }
37+
38+
/**
39+
* @param v support [cf.wayzer.placehold.DynamicVar] even [PlaceHoldString] or any value
40+
*/
41+
fun IBaseScript.register(name: String, desc: String, v: Any?) {
42+
PlaceHoldApi.registerGlobalVar(name, v)
43+
registeredVars[name]=desc
44+
}
45+
46+
/**
47+
* @see TypeBinder
48+
* @param desc describe what you want to add
49+
*/
50+
inline fun <reified T:Any> IBaseScript.registerForType(desc: String): TypeBinder<T> {
51+
registeredVars["Type@${T::class.java.simpleName}"] = desc
52+
return PlaceHoldApi.typeBinder()
53+
}
54+
/**
55+
* @sample
56+
* val tps by PlaceHold.reference<Int>("tps")
57+
* println(tps) //get variable
58+
*/
59+
inline fun <reified T> reference(name: String) = PlaceHoldKey(name,T::class.java)
60+
61+
/**
62+
* @sample
63+
* val Player.money by PlaceHold.referenceForType<Int>("money")
64+
* player.money //get variable
65+
*/
66+
inline fun <reified R> referenceForType(name: String) = TypePlaceHoldKey(name,R::class.java)
67+
}
68+
69+
/**
70+
* @param arg values support [cf.wayzer.placehold.DynamicVar] even [PlaceHoldString] or any value
71+
*/
72+
fun String.with(vararg arg: Pair<String, Any>): PlaceHoldString = PlaceHoldApi.getContext(this, arg.toMap())

0 commit comments

Comments
 (0)