Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SBX-7 Custom Items #8

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import net.minecraft.util.registry.Registry
import org.graalvm.polyglot.HostAccess.Export
import org.graalvm.polyglot.Value
import org.sandboxpowered.fabric.Main
import org.sandboxpowered.fabric.util.getMemberValue
import org.sandboxpowered.fabric.util.getMemberValueStr
import org.sandboxpowered.fabric.util.removeIf
import org.sandboxpowered.fabric.util.toJSON
import java.util.function.BiPredicate
Expand Down Expand Up @@ -55,10 +55,10 @@ class PolyglotRecipeManager(private val map: MutableMap<Identifier, JsonElement>

var predicate: BiPredicate<Identifier, JsonElement>? = null

val id = value.getMemberValue("id")
val output = value.getMemberValue("output")
val domain = value.getMemberValue("domain")
val type = value.getMemberValue("type")
val id = value.getMemberValueStr("id")
val output = value.getMemberValueStr("output")
val domain = value.getMemberValueStr("domain")
val type = value.getMemberValueStr("type")

if (id != null) {
val idPredicate = BiPredicate<Identifier, JsonElement> { identifier, _ -> identifier.toString() == id }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SandboxResourcePolyglotContext(private val resource: String, private val s
@Export
fun emit(event: String, vararg args: Any) {
if (event.contains(':')) scriptLoader.emitEventToAll(event, *args)
else scriptLoader.emitEventTo(resource, event, *args)
else scriptLoader.emitEventTo(resource, event, args = args)
}

@Export
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.sandboxpowered.fabric.api.item

import com.google.common.collect.ImmutableMap
import net.minecraft.item.Item
import net.minecraft.util.Identifier
import net.minecraft.util.Rarity
import net.minecraft.util.registry.Registry
import org.graalvm.polyglot.Value
import org.sandboxpowered.fabric.impl.item.PolyglotItem
import org.sandboxpowered.fabric.util.getMemberValue
import org.sandboxpowered.fabric.util.getMemberValueInt
import org.sandboxpowered.fabric.util.getMemberValueStr
import org.sandboxpowered.fabric.util.set

class PolyglotGlobalItemManager {
private val archetypeMap: Map<String, (Value) -> Item>
TheCodedOne marked this conversation as resolved.
Show resolved Hide resolved

init {
val builder = ImmutableMap.builder<String, (Value) -> Item>()

builder["item"] = { PolyglotItem(itemPropertiesToSettings(it), it) }

archetypeMap = builder.build()
}

private fun itemPropertiesToSettings(value: Value): Item.Settings {
val settings = Item.Settings()
if (!value.hasMember("properties")) return settings
val properties = value.getMember("properties")
properties.getMemberValueInt("maxDamage")?.let(settings::maxDamage)
properties.getMemberValueInt("maxCount")?.let(settings::maxCount)
properties.getMemberValueStr("rarity")?.let {
settings.rarity(stringToRarity(it))
}
return settings
}

private fun stringToRarity(rarity: String): Rarity = when (rarity) {
"uncommon" -> Rarity.UNCOMMON
"rare" -> Rarity.RARE
"epic" -> Rarity.EPIC
else -> Rarity.COMMON
}

fun addItem(identifier: Identifier, value: Value) {
val archetype = value.getMemberValue("archetype", "item")
if (archetype !in archetypeMap) throw UnsupportedOperationException("Unknown item archetype [$archetype]")
val item = archetypeMap[archetype]!!(value)
Registry.register(Registry.ITEM, identifier, item)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sandboxpowered.fabric.api.item

import net.minecraft.util.Identifier
import org.graalvm.polyglot.HostAccess.Export
import org.graalvm.polyglot.Value

class PolyglotItemManager(private val domain: String, private val global: PolyglotGlobalItemManager) {
@Export
fun add(id: String, value: Value) {
if (!value.hasMembers()) throw UnsupportedOperationException("Unsupported value for item registration")
global.addItem(Identifier(domain, id), value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sandboxpowered.fabric.impl.item

import net.minecraft.item.Item
import org.graalvm.polyglot.Value

class PolyglotItem(settings: Settings, value: Value) : Item(settings) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class SandboxLoader {

log.info("Loaded ${addons.size} resources")

resourceContent.keys.forEach {
polyglotLoader.emitEventTo(it, "items", false, polyglotLoader.getItemManager(it))
}

if (side == Side.SERVER) {
val json = JsonObject()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ import org.graalvm.polyglot.Context
import org.graalvm.polyglot.HostAccess
import org.graalvm.polyglot.Source
import org.sandboxpowered.fabric.api.SandboxResourcePolyglotContext
import org.sandboxpowered.fabric.api.item.PolyglotGlobalItemManager
import org.sandboxpowered.fabric.api.item.PolyglotItemManager
import org.sandboxpowered.fabric.scripting.polyglot.PolyglotFileSystem
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException

class PolyglotScriptLoader {
private val executor = Executors.newSingleThreadExecutor()
private val scriptContext: MutableMap<String, MutableMap<String, Context>> = HashMap()
private val polyglotContext: MutableMap<String, SandboxResourcePolyglotContext> = HashMap()
private val scriptContext: MutableMap<String, MutableMap<String, Context>> = hashMapOf()
private val polyglotContext: MutableMap<String, SandboxResourcePolyglotContext> = hashMapOf()
private val globalItemManager = PolyglotGlobalItemManager()
private val itemManager: MutableMap<String, PolyglotItemManager> = hashMapOf()

private fun buildContext(): Context = Context.newBuilder("js", "python")
.allowExperimentalOptions(true)
Expand All @@ -24,19 +28,22 @@ class PolyglotScriptLoader {
return scriptContext.computeIfAbsent(resource) { HashMap() }
}

private fun getPolyglotContext(resource: String): SandboxResourcePolyglotContext {
return polyglotContext.computeIfAbsent(resource) { SandboxResourcePolyglotContext(it, this) }
}
private fun getPolyglotContext(resource: String): SandboxResourcePolyglotContext =
polyglotContext.computeIfAbsent(resource) { SandboxResourcePolyglotContext(it, this) }

fun getItemManager(resource: String): PolyglotItemManager =
itemManager.computeIfAbsent(resource) { PolyglotItemManager(it, globalItemManager) }

fun emitEventToAll(event: String, vararg args: Any) {
polyglotContext.values.forEach { context ->
context.event(event) { it(args) }
}
}

fun emitEventTo(resource: String, event: String, vararg args: Any) {
fun emitEventTo(resource: String, event: String, emitToAll: Boolean = true, vararg args: Any) {
polyglotContext[resource]?.event(event) { it(args) }
emitEventToAll(resource, "$resource:$event", *args)
if (emitToAll)
emitEventToAll(resource, "$resource:$event", *args)
}

fun loadScriptContext(resource: String, scriptSource: Source) {
Expand Down
15 changes: 12 additions & 3 deletions src/main/kotlin/org/sandboxpowered/fabric/util/PolyglotUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package org.sandboxpowered.fabric.util
import com.google.gson.*
import org.graalvm.polyglot.Value

fun Value.getMemberValue(member: String): Value? = if (hasMember(member)) getMember(member) else null

fun Value.getMemberValue(identifier: String): String? =
if (hasMember(identifier)) getMember(identifier).asString() else null
fun Value.getMemberValueStr(member: String): String? = getMemberValue(member)?.asString()
fun Value.getMemberValueInt(member: String): Int? = getMemberValue(member)?.asInt()

fun Value.getMemberValue(member: String, default: String): String = getMemberValueStr(member) ?: default
fun Value.getMemberValue(member: String, default: Int): Int = getMemberValueInt(member) ?: default

fun Value.toJSON(): JsonElement = when {
hasArrayElements() -> JsonArray().apply {
Expand All @@ -18,6 +22,11 @@ fun Value.toJSON(): JsonElement = when {
}
isString -> JsonPrimitive(asString())
isBoolean -> JsonPrimitive(asBoolean())
isNumber -> JsonPrimitive(asInt())
isNumber -> when {
fitsInInt() -> JsonPrimitive(asInt())
fitsInLong() -> JsonPrimitive(asLong())
fitsInFloat() -> JsonPrimitive(asFloat())
else -> JsonNull.INSTANCE
}
else -> JsonNull.INSTANCE
}
6 changes: 6 additions & 0 deletions src/main/kotlin/org/sandboxpowered/fabric/util/map.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.sandboxpowered.fabric.util

import com.google.common.collect.ImmutableMap

/**
* Removes elements from this map if the predicate returns true
*/
Expand All @@ -9,4 +11,8 @@ inline fun <K, V> MutableMap<K, V>.removeIf(predicate: (K, V) -> Boolean) {
val (k, v) = iter.next()
if (predicate(k, v)) iter.remove()
}
}

operator fun <K, V> ImmutableMap.Builder<K, V>.set(key: K, value: V): ImmutableMap.Builder<K, V> {
return put(key, value)
}