-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FIXScriptUtilでのランタイム依存をIScriptRuntimeでなくす
- Loading branch information
Showing
5 changed files
with
212 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/main/java/com/anatawa12/fixRtm/scripting/IScriptRuntime.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.anatawa12.fixRtm.scripting | ||
|
||
import com.anatawa12.fixRtm.io.FIXModelPack | ||
import com.anatawa12.fixRtm.io.FIXResource | ||
import net.minecraft.util.ResourceLocation | ||
import javax.script.ScriptEngine | ||
|
||
interface IScriptRuntime<CompiledScript, Engine : ScriptEngine> { | ||
/** | ||
* @param filePath the path of script | ||
* @param resource [FIXResource] of the script | ||
* @param dependencies all dependency script name and body | ||
* @return cached [Engine] if found, returns null if cache is not found or not supported. | ||
*/ | ||
fun getCachedEngine(filePath: ResourceLocation, resource: FIXResource, dependencies: Map<ResourceLocation, String>): Engine? | ||
|
||
/** | ||
* @param location the path of script | ||
* @param script body of script | ||
* @param pack model pack of the script | ||
* @param engine the engine for which runtime compile. | ||
*/ | ||
fun compile(location: ResourceLocation, script: String, pack: FIXModelPack? = null, engine: Engine? = null): CompiledScript { | ||
val preprocessed = ScriptImporter.preprocessScript(script) | ||
val name = if (pack != null) "$location(${pack.file.name})" else "$location" | ||
return compile(preprocessed, name, engine = engine) | ||
} | ||
|
||
/** | ||
* @param script body of script | ||
* @param fileName name of the script | ||
* @param engine the engine for which runtime compile. | ||
*/ | ||
fun compile(script: String, fileName: String, engine: Engine? = null): CompiledScript | ||
|
||
fun exec(script: CompiledScript): Engine | ||
|
||
fun cache(pack: FIXModelPack, filePath: ResourceLocation, dependencies: Map<ResourceLocation, String>, engine: Engine) | ||
|
||
object AssertingRuntime : IScriptRuntime<Nothing, Nothing> { | ||
override fun getCachedEngine(filePath: ResourceLocation, resource: FIXResource, dependencies: Map<ResourceLocation, String>): Nothing? | ||
= throw AssertionError("IScriptRuntime should be never used") | ||
|
||
override fun compile(script: String, fileName: String, engine: Nothing?): Nothing | ||
= throw AssertionError("IScriptRuntime should be never used") | ||
|
||
override fun exec(script: Nothing): Nothing | ||
= throw AssertionError("IScriptRuntime should be never used") | ||
|
||
override fun cache(pack: FIXModelPack, filePath: ResourceLocation, dependencies: Map<ResourceLocation, String>, engine: Nothing) | ||
= throw AssertionError("IScriptRuntime should be never used") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
src/main/java/com/anatawa12/fixRtm/scripting/rhino/RhinoScriptRuntimeImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package com.anatawa12.fixRtm.scripting.rhino | ||
|
||
import com.anatawa12.fixRtm.caching.ModelPackBasedCache | ||
import com.anatawa12.fixRtm.fixCacheDir | ||
import com.anatawa12.fixRtm.io.FIXModelPack | ||
import com.anatawa12.fixRtm.io.FIXResource | ||
import com.anatawa12.fixRtm.scripting.ExecutedScript | ||
import com.anatawa12.fixRtm.scripting.IScriptRuntime | ||
import com.anatawa12.fixRtm.utils.DigestUtils | ||
import net.minecraft.util.ResourceLocation | ||
import org.mozilla.javascript.ImporterTopLevel | ||
import org.mozilla.javascript.Script | ||
import org.mozilla.javascript.ScriptableObject | ||
import org.mozilla.javascript.TopLevel | ||
|
||
object RhinoScriptRuntimeImpl : IScriptRuntime<Script, FIXRhinoScriptEngine> { | ||
override fun getCachedEngine(filePath: ResourceLocation, resource: FIXResource, dependencies: Map<ResourceLocation, String>): FIXRhinoScriptEngine? { | ||
return getScriptAndDoScriptByCache(filePath, resource.pack, makeDependenciesData(dependencies)) | ||
?.let { scope -> FIXRhinoScriptEngine().also { it.scope = scope } } | ||
} | ||
|
||
override fun compile(script: String, fileName: String, engine: FIXRhinoScriptEngine?): Script =usingContext { cx -> | ||
return ScriptCompiledClassCache.compile(script, fileName) | ||
} | ||
|
||
override fun exec(script: Script): FIXRhinoScriptEngine { | ||
val engine = FIXRhinoScriptEngine() | ||
usingContext { cx -> | ||
val scope = makeNewScope() | ||
|
||
script.exec(cx, scope) | ||
|
||
engine.scope = scope | ||
} | ||
|
||
return engine | ||
} | ||
|
||
override fun cache(pack: FIXModelPack, filePath: ResourceLocation, dependencies: Map<ResourceLocation, String>, engine: FIXRhinoScriptEngine) { | ||
ExecutedScriptCache.add(pack, filePath, makeExecutedScript(makeDependenciesData(dependencies), engine.scope)) | ||
} | ||
|
||
val baseScope = usingContext { | ||
val scope = TopLevel() | ||
|
||
it.initStandardObjects(scope) | ||
|
||
ImportScriptRhinoFunctionImpl.init(scope) | ||
|
||
scope.sealObject() | ||
|
||
scope | ||
} | ||
|
||
//////////////////////////////////////////////////////////////// | ||
|
||
private fun makeNewScope(): ScriptableObject = usingContext { | ||
ScriptCompiledClassCache.initContext(it) | ||
|
||
val scope = ImporterTopLevel(it, false) | ||
scope.prototype = baseScope | ||
return scope | ||
} | ||
|
||
private fun makeNewScopeWithCache(cache: ExecutedScript): ScriptableObject? = usingContext { | ||
ScriptCompiledClassCache.initContext(it) | ||
|
||
return cache.getScope(baseScope) | ||
} | ||
|
||
private fun makeExecutedScript(dependencies: Map<String, ByteArray>, scope: ScriptableObject): ExecutedScript = usingContext { | ||
ScriptCompiledClassCache.initContext(it) | ||
|
||
return ExecutedScript(dependencies, scope, baseScope) | ||
} | ||
|
||
private fun getScriptAndDoScriptByCache(filePath: ResourceLocation, pack: FIXModelPack, dependencies: Map<String, ByteArray>): ScriptableObject? { | ||
val cache = ExecutedScriptCache.getScript(pack, filePath) ?: return null | ||
|
||
// verify cache | ||
if (cache.dependencies.keys != dependencies.keys) return null | ||
|
||
for ((name, hash) in dependencies) { | ||
if (!cache.dependencies[name]!!.contentEquals(hash)) return null | ||
} | ||
|
||
// load cache | ||
|
||
val newScope = makeNewScopeWithCache(cache) | ||
if (newScope == null) { | ||
ExecutedScriptCache.discord(pack, filePath) | ||
} | ||
return newScope | ||
} | ||
|
||
private fun makeDependenciesData(dependencies: Map<ResourceLocation, String>): Map<String, ByteArray> { | ||
val data = mutableMapOf<String, ByteArray>() | ||
for ((name, script) in dependencies) { | ||
data[name.toString()] = DigestUtils.sha1(script) | ||
} | ||
return data | ||
} | ||
} | ||
|
||
object ExecutedScriptCache { | ||
private val cache = ModelPackBasedCache( | ||
fixCacheDir.resolve("excluded-script"), | ||
0x0000 to ExecutedScript.Serializer | ||
) | ||
|
||
fun getScript(pack: FIXModelPack, filePath: ResourceLocation): ExecutedScript? { | ||
return cache.get(pack, DigestUtils.sha1Hex(filePath.toString()), ExecutedScript.Serializer) | ||
} | ||
|
||
fun add(pack: FIXModelPack, filePath: ResourceLocation, executedScript: ExecutedScript) { | ||
cache.put(pack, DigestUtils.sha1Hex(filePath.toString()), executedScript) | ||
} | ||
|
||
fun discord(pack: FIXModelPack, filePath: ResourceLocation) { | ||
cache.discord(pack, DigestUtils.sha1Hex(filePath.toString())) | ||
} | ||
|
||
fun load() {} | ||
} | ||
|
||
|