New matter values system checkpoint
This commit is contained in:
parent
a178c88bf2
commit
a757fcc9ab
@ -47,6 +47,7 @@ import ru.dbotthepony.mc.otm.datagen.recipes.addShapelessRecipes
|
||||
import ru.dbotthepony.mc.otm.datagen.recipes.addOreSmeltingRecipes
|
||||
import ru.dbotthepony.mc.otm.datagen.tags.TagsProvider
|
||||
import ru.dbotthepony.mc.otm.datagen.tags.addTags
|
||||
import ru.dbotthepony.mc.otm.matter.MatterDataProvider
|
||||
import ru.dbotthepony.mc.otm.registry.objects.ColoredDecorativeBlock
|
||||
import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock
|
||||
import kotlin.properties.Delegates
|
||||
@ -73,6 +74,8 @@ object DataGen {
|
||||
private set
|
||||
var researchProvider: AndroidResearchDataProvider by WriteOnce()
|
||||
private set
|
||||
var matterData: MatterDataProvider by WriteOnce()
|
||||
private set
|
||||
|
||||
fun decorativeCubeAll(vararg blocks: Block) {
|
||||
blockModelProvider.decorativeCubeAll(*blocks)
|
||||
@ -401,6 +404,7 @@ object DataGen {
|
||||
val recipeProvider = MatteryRecipeProvider(event.generator)
|
||||
val lootModifier = LootModifiers(event.generator)
|
||||
val languageProvider = MatteryLanguageProvider(event.generator)
|
||||
val matterData = MatterDataProvider(event)
|
||||
val researchProvider = AndroidResearchDataProvider(event.generator).also { it.exec { addResearchData(it, languageProvider) } }
|
||||
|
||||
this.blockModelProvider = blockModelProvider
|
||||
@ -411,6 +415,7 @@ object DataGen {
|
||||
this.lootModifier = lootModifier
|
||||
this.languageProvider = languageProvider
|
||||
this.researchProvider = researchProvider
|
||||
this.matterData = matterData
|
||||
|
||||
val tagsProvider = TagsProvider(event)
|
||||
val advancementProvider = AdvancementProvider(event)
|
||||
@ -428,6 +433,7 @@ object DataGen {
|
||||
event.generator.addProvider(true, SoundDataProvider(event))
|
||||
event.generator.addProvider(true, researchProvider)
|
||||
event.generator.addProvider(true, advancementProvider)
|
||||
event.generator.addProvider(true, matterData)
|
||||
|
||||
AddEnglishLanguage(languageProvider)
|
||||
|
||||
|
@ -39,6 +39,7 @@ import ru.dbotthepony.mc.otm.item.QuantumBatteryItem;
|
||||
import ru.dbotthepony.mc.otm.item.weapon.AbstractWeaponItem;
|
||||
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterDataKt;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterManager;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterRegistryKt;
|
||||
import ru.dbotthepony.mc.otm.network.*;
|
||||
import ru.dbotthepony.mc.otm.registry.*;
|
||||
@ -142,6 +143,8 @@ public final class OverdriveThatMatters {
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager.INSTANCE::reloadEvent);
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager.INSTANCE::syncEvent);
|
||||
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::reloadEvent);
|
||||
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onServerStopping);
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onLevelUnload);
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onWatch);
|
||||
|
@ -6,6 +6,7 @@ package ru.dbotthepony.mc.otm.core
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.ByteArrayTag
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
@ -239,6 +240,9 @@ fun FriendlyByteBuf.readBigInteger(byteLimit: Int = 128) = BigInteger(readByteAr
|
||||
operator fun IItemHandler.get(index: Int): ItemStack = getStackInSlot(index)
|
||||
|
||||
operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value)
|
||||
operator fun JsonObject.set(s: String, value: String) = add(s, JsonPrimitive(value))
|
||||
operator fun JsonObject.set(s: String, value: Number) = add(s, JsonPrimitive(value))
|
||||
operator fun JsonObject.set(s: String, value: Boolean) = add(s, JsonPrimitive(value))
|
||||
|
||||
fun <T> LazyOptional<T>.orNull(): T? {
|
||||
if (!isPresent) {
|
||||
|
@ -753,6 +753,10 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
|
||||
return toBigDecmial().divide(divisor.toBigDecmial(), PERCENTAGE_CONTEXT).toFloat()
|
||||
}
|
||||
|
||||
operator fun rem(divisor: ImpreciseFraction): ImpreciseFraction {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val serialVersionUID: Long = 287354739494574838L
|
||||
|
@ -0,0 +1,288 @@
|
||||
package ru.dbotthepony.mc.otm.matter
|
||||
|
||||
import net.minecraft.data.CachedOutput
|
||||
import net.minecraft.data.DataGenerator
|
||||
import net.minecraft.data.DataProvider
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.level.ItemLike
|
||||
import net.minecraftforge.data.event.GatherDataEvent
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.core.registryName
|
||||
import java.util.Collections
|
||||
import java.util.function.Consumer
|
||||
|
||||
open class MatterDataProvider(protected val dataGenerator: DataGenerator, val namespace: String?) : DataProvider {
|
||||
constructor(event: GatherDataEvent) : this(event.generator, event.modContainer.namespace)
|
||||
|
||||
protected val pathProvider: DataGenerator.PathProvider = dataGenerator.createPathProvider(DataGenerator.Target.DATA_PACK, MatterManager.DIRECTORY)
|
||||
protected val actions = LinkedHashMap<ResourceLocation, MatterManager.AbstractRegistryAction>()
|
||||
|
||||
sealed class Configuration(val name: ResourceLocation) {
|
||||
var errorOnFailure: Boolean = false
|
||||
var matter: ImpreciseFraction? = null
|
||||
var complexity: Double? = null
|
||||
var priority: Int? = null
|
||||
|
||||
private var _key: ResourceLocation? = null
|
||||
private var _tag: TagKey<Item>? = null
|
||||
|
||||
var key: ResourceLocation?
|
||||
get() = _key
|
||||
set(value) {
|
||||
checkNotNull(value) { "Can't set key to null" }
|
||||
_tag = null
|
||||
_key = value
|
||||
}
|
||||
|
||||
var tag: TagKey<Item>?
|
||||
get() = _tag
|
||||
set(value) {
|
||||
checkNotNull(value) { "Can't set tag to null" }
|
||||
_key = null
|
||||
_tag = value
|
||||
}
|
||||
|
||||
protected fun checkKeyTag() {
|
||||
check(_key != null || _tag != null) { "You must define either key or tag for $name" }
|
||||
}
|
||||
|
||||
protected fun checkMatterValues() {
|
||||
check(matter == null || (matter ?: throw ConcurrentModificationException()) >= ImpreciseFraction.ZERO) { "Invalid matter value: ${matter ?: throw ConcurrentModificationException()}" }
|
||||
check(complexity == null || (complexity ?: throw ConcurrentModificationException()) >= 0.0) { "Invalid matter value: ${matter ?: throw ConcurrentModificationException()}" }
|
||||
}
|
||||
|
||||
abstract fun build(): MatterManager.AbstractRegistryAction
|
||||
}
|
||||
|
||||
class InsertConfiguration(name: ResourceLocation) : Configuration(name) {
|
||||
var replaceIfExists: Boolean = false
|
||||
var comparePriority: Boolean = false
|
||||
|
||||
override fun build(): MatterManager.InsertAction {
|
||||
checkKeyTag()
|
||||
checkMatterValues()
|
||||
check(matter != null && complexity != null) { "You must define both matter value and complexity for $name" }
|
||||
|
||||
if (key != null) {
|
||||
return MatterManager.InsertAction(
|
||||
key = key ?: throw ConcurrentModificationException(),
|
||||
matter = matter,
|
||||
complexity = complexity,
|
||||
priority = priority,
|
||||
errorOnFailure = errorOnFailure,
|
||||
replaceIfExists = replaceIfExists,
|
||||
comparePriority = comparePriority
|
||||
)
|
||||
} else {
|
||||
return MatterManager.InsertAction(
|
||||
tag = tag ?: throw ConcurrentModificationException(),
|
||||
matter = matter,
|
||||
complexity = complexity,
|
||||
priority = priority,
|
||||
errorOnFailure = errorOnFailure,
|
||||
replaceIfExists = replaceIfExists,
|
||||
comparePriority = comparePriority
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteConfiguration(name: ResourceLocation) : Configuration(name) {
|
||||
override fun build(): MatterManager.DeleteAction {
|
||||
checkKeyTag()
|
||||
|
||||
if (key != null) {
|
||||
return MatterManager.DeleteAction(
|
||||
key = key ?: throw ConcurrentModificationException(),
|
||||
errorOnFailure = errorOnFailure,
|
||||
)
|
||||
} else {
|
||||
return MatterManager.DeleteAction(
|
||||
tag = tag ?: throw ConcurrentModificationException(),
|
||||
errorOnFailure = errorOnFailure,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateConfiguration(name: ResourceLocation) : Configuration(name) {
|
||||
val matterFunctions = ArrayList<MatterManager.UpdateAction.BoundFunction<ImpreciseFraction>>()
|
||||
val complexityFunctions = ArrayList<MatterManager.UpdateAction.BoundFunction<Double>>()
|
||||
val priorityFunctions = ArrayList<MatterManager.UpdateAction.BoundFunction<Int>>()
|
||||
|
||||
fun addMatterFunction(function: MatterManager.UpdateAction.Function, value: ImpreciseFraction): UpdateConfiguration {
|
||||
matterFunctions.add(MatterManager.UpdateAction.BoundFunction(function, value))
|
||||
matter = null
|
||||
return this
|
||||
}
|
||||
|
||||
fun addComplexityFunction(function: MatterManager.UpdateAction.Function, value: Double): UpdateConfiguration {
|
||||
complexityFunctions.add(MatterManager.UpdateAction.BoundFunction(function, value))
|
||||
matter = null
|
||||
return this
|
||||
}
|
||||
|
||||
fun addPriorityFunction(function: MatterManager.UpdateAction.Function, value: Int): UpdateConfiguration {
|
||||
priorityFunctions.add(MatterManager.UpdateAction.BoundFunction(function, value))
|
||||
matter = null
|
||||
return this
|
||||
}
|
||||
|
||||
override fun build(): MatterManager.UpdateAction {
|
||||
check(!(matterFunctions.isNotEmpty() && matter != null)) { "Can't have both matter value and matter value functions be defined at the same time" }
|
||||
check(!(complexityFunctions.isNotEmpty() && complexity != null)) { "Can't have both complexity and complexity functions be defined at the same time" }
|
||||
check(!(priorityFunctions.isNotEmpty() && priority != null)) { "Can't have both priority and priority functions be defined at the same time" }
|
||||
|
||||
check(
|
||||
matterFunctions.isNotEmpty() || matter != null ||
|
||||
complexityFunctions.isNotEmpty() || complexity != null ||
|
||||
priorityFunctions.isNotEmpty() || priority != null
|
||||
) { "Update configuration is completely empty" }
|
||||
|
||||
checkMatterValues()
|
||||
checkKeyTag()
|
||||
|
||||
if (key != null) {
|
||||
return MatterManager.UpdateAction(
|
||||
key = key ?: throw ConcurrentModificationException(),
|
||||
matter = matter,
|
||||
complexity = complexity,
|
||||
priority = priority,
|
||||
errorOnFailure = errorOnFailure,
|
||||
matterFunctions = matterFunctions,
|
||||
complexityFunctions = complexityFunctions,
|
||||
priorityFunctions = priorityFunctions
|
||||
)
|
||||
} else {
|
||||
return MatterManager.UpdateAction(
|
||||
tag = tag ?: throw ConcurrentModificationException(),
|
||||
matter = matter,
|
||||
complexity = complexity,
|
||||
priority = priority,
|
||||
errorOnFailure = errorOnFailure,
|
||||
matterFunctions = matterFunctions,
|
||||
complexityFunctions = complexityFunctions,
|
||||
priorityFunctions = priorityFunctions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun insert(name: ResourceLocation, configurator: InsertConfiguration.() -> Unit): MatterManager.InsertAction {
|
||||
check(!actions.containsKey(name)) { "Already has action with name $name" }
|
||||
val config = InsertConfiguration(name)
|
||||
configurator.invoke(config)
|
||||
val built = config.build()
|
||||
actions[name] = built
|
||||
return built
|
||||
}
|
||||
|
||||
fun delete(name: ResourceLocation, configurator: DeleteConfiguration.() -> Unit): MatterManager.DeleteAction {
|
||||
check(!actions.containsKey(name)) { "Already has action with name $name" }
|
||||
val config = DeleteConfiguration(name)
|
||||
configurator.invoke(config)
|
||||
val built = config.build()
|
||||
actions[name] = built
|
||||
return built
|
||||
}
|
||||
|
||||
fun update(name: ResourceLocation, configurator: UpdateConfiguration.() -> Unit): MatterManager.UpdateAction {
|
||||
check(!actions.containsKey(name)) { "Already has action with name $name" }
|
||||
val config = UpdateConfiguration(name)
|
||||
configurator.invoke(config)
|
||||
val built = config.build()
|
||||
actions[name] = built
|
||||
return built
|
||||
}
|
||||
|
||||
protected fun updateLocation(input: ResourceLocation, prefix: String): ResourceLocation {
|
||||
if (namespace != null) {
|
||||
if (input.namespace == namespace) {
|
||||
return ResourceLocation(input.namespace, prefix + input.path)
|
||||
} else {
|
||||
return ResourceLocation(namespace, prefix + input.namespace + "/" + input.path)
|
||||
}
|
||||
} else {
|
||||
return ResourceLocation(input.namespace, prefix + input.path)
|
||||
}
|
||||
}
|
||||
|
||||
fun insert(name: ItemLike, configurator: InsertConfiguration.() -> Unit): MatterManager.InsertAction {
|
||||
return insert(updateLocation(name.asItem().registryName ?: throw NullPointerException("${name.asItem()} does not have registry name!"), "item/")) {
|
||||
key = name.asItem().registryName ?: throw ConcurrentModificationException()
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(name: ItemLike, configurator: DeleteConfiguration.() -> Unit): MatterManager.DeleteAction {
|
||||
return delete(updateLocation(name.asItem().registryName ?: throw NullPointerException("${name.asItem()} does not have registry name!"), "item/")) {
|
||||
key = name.asItem().registryName ?: throw ConcurrentModificationException()
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(name: ItemLike, configurator: UpdateConfiguration.() -> Unit): MatterManager.UpdateAction {
|
||||
return update(updateLocation(name.asItem().registryName ?: throw NullPointerException("${name.asItem()} does not have registry name!"), "item/")) {
|
||||
key = name.asItem().registryName ?: throw ConcurrentModificationException()
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun insert(name: TagKey<Item>, configurator: InsertConfiguration.() -> Unit): MatterManager.InsertAction {
|
||||
return insert(updateLocation(name.location, "tag/")) {
|
||||
tag = name
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(name: TagKey<Item>, configurator: DeleteConfiguration.() -> Unit): MatterManager.DeleteAction {
|
||||
return delete(updateLocation(name.location, "tag/")) {
|
||||
tag = name
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(name: TagKey<Item>, configurator: UpdateConfiguration.() -> Unit): MatterManager.UpdateAction {
|
||||
return update(updateLocation(name.location, "tag/")) {
|
||||
tag = name
|
||||
configurator.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun insert(name: ResourceLocation, configurator: Consumer<InsertConfiguration>) = insert(name, configurator::accept)
|
||||
fun delete(name: ResourceLocation, configurator: Consumer<DeleteConfiguration>) = delete(name, configurator::accept)
|
||||
fun update(name: ResourceLocation, configurator: Consumer<UpdateConfiguration>) = update(name, configurator::accept)
|
||||
|
||||
fun insert(name: ItemLike, configurator: Consumer<InsertConfiguration>) = insert(name, configurator::accept)
|
||||
fun delete(name: ItemLike, configurator: Consumer<DeleteConfiguration>) = delete(name, configurator::accept)
|
||||
fun update(name: ItemLike, configurator: Consumer<UpdateConfiguration>) = update(name, configurator::accept)
|
||||
|
||||
fun insert(name: TagKey<Item>, configurator: Consumer<InsertConfiguration>) = insert(name, configurator::accept)
|
||||
fun delete(name: TagKey<Item>, configurator: Consumer<DeleteConfiguration>) = delete(name, configurator::accept)
|
||||
fun update(name: TagKey<Item>, configurator: Consumer<UpdateConfiguration>) = update(name, configurator::accept)
|
||||
|
||||
/**
|
||||
* Override this if you prefer The Mundane Way™ instead of calling [insert], [delete] and [update] directly
|
||||
*
|
||||
* Called inside [run]
|
||||
*/
|
||||
protected open fun addActions() {}
|
||||
|
||||
protected val added = ArrayList<MatterManager.AbstractRegistryAction>()
|
||||
val addedView: List<MatterManager.AbstractRegistryAction> = Collections.unmodifiableList(added)
|
||||
|
||||
final override fun run(output: CachedOutput) {
|
||||
addActions()
|
||||
|
||||
for ((key, value) in actions) {
|
||||
DataProvider.saveStable(output, value.toJson(), pathProvider.json(key))
|
||||
added.add(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return "Matter Data"
|
||||
}
|
||||
}
|
843
src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt
Normal file
843
src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt
Normal file
@ -0,0 +1,843 @@
|
||||
package ru.dbotthepony.mc.otm.matter
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParseException
|
||||
import com.google.gson.JsonPrimitive
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener
|
||||
import net.minecraft.tags.ItemTags
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.util.profiling.ProfilerFiller
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraftforge.event.AddReloadListenerEvent
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.core.integerDivisionDown
|
||||
import ru.dbotthepony.mc.otm.core.integerDivisionUp
|
||||
import ru.dbotthepony.mc.otm.core.registryName
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import ru.dbotthepony.mc.otm.data.stream
|
||||
|
||||
object MatterManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_matter") {
|
||||
const val DIRECTORY = "otm_matter"
|
||||
|
||||
sealed class AbstractRegistryAction {
|
||||
sealed class Condition {
|
||||
abstract fun test(): Boolean
|
||||
}
|
||||
|
||||
class CombinedCondition(val conditions: Collection<Condition>) : Condition() {
|
||||
override fun test(): Boolean {
|
||||
return conditions.all { it.test() }
|
||||
}
|
||||
}
|
||||
|
||||
val errorOnFailure: Boolean
|
||||
val tag: TagKey<Item>?
|
||||
val key: ResourceLocation?
|
||||
val matter: ImpreciseFraction?
|
||||
val complexity: Double?
|
||||
val priority: Int?
|
||||
|
||||
constructor(json: JsonObject) {
|
||||
errorOnFailure = json["error_on_failure"]?.asBoolean ?: false
|
||||
priority = json["priority"]?.asInt
|
||||
|
||||
val location = json["id"]?.asString?.let { ResourceLocation.tryParse(it) } ?: throw JsonParseException("Invalid `id` value: ${json["id"]}")
|
||||
|
||||
if (location.namespace == "#") {
|
||||
throw JsonParseException("Invalid `id` value: $location")
|
||||
}
|
||||
|
||||
if (location.namespace.startsWith("#")) {
|
||||
tag = ItemTags.create(ResourceLocation(location.toString().substring(1)))
|
||||
key = null
|
||||
} else {
|
||||
key = location
|
||||
tag = null
|
||||
}
|
||||
|
||||
try {
|
||||
matter = json["matter"]?.asString?.let(::ImpreciseFraction)
|
||||
|
||||
if (matter != null && !matter.isPositive) {
|
||||
throw JsonParseException("Can't have non-positive matter value. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
} catch(err: NumberFormatException) {
|
||||
throw JsonParseException("Invalid `matter` field: ${json["matter"]}", err)
|
||||
}
|
||||
|
||||
try {
|
||||
complexity = json["complexity"]?.asString?.toDouble()
|
||||
|
||||
if (complexity != null && complexity <= 0.0) {
|
||||
throw JsonParseException("Can't have non-positive complexity. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
} catch(err: NumberFormatException) {
|
||||
throw JsonParseException("Invalid `complexity` field: ${json["complexity"]}", err)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
tag: TagKey<Item>,
|
||||
matter: ImpreciseFraction?,
|
||||
complexity: Double?,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false
|
||||
) {
|
||||
this.tag = tag
|
||||
this.key = null
|
||||
this.matter = matter
|
||||
this.complexity = complexity
|
||||
this.priority = priority
|
||||
this.errorOnFailure = errorOnFailure
|
||||
|
||||
if (matter != null && !matter.isPositive) {
|
||||
throw IllegalArgumentException("Can't have non-positive matter value. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
|
||||
if (complexity != null && complexity <= 0.0) {
|
||||
throw IllegalArgumentException("Can't have non-positive complexity. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
key: ResourceLocation,
|
||||
matter: ImpreciseFraction?,
|
||||
complexity: Double?,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false
|
||||
) {
|
||||
this.tag = null
|
||||
this.key = key
|
||||
this.matter = matter
|
||||
this.complexity = complexity
|
||||
this.priority = priority
|
||||
this.errorOnFailure = errorOnFailure
|
||||
|
||||
if (matter != null && !matter.isPositive) {
|
||||
throw IllegalArgumentException("Can't have non-positive matter value. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
|
||||
if (complexity != null && complexity <= 0.0) {
|
||||
throw IllegalArgumentException("Can't have non-positive complexity. To remove an entry from registry please use 'delete' action instead.")
|
||||
}
|
||||
}
|
||||
|
||||
fun checkConditions(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
abstract fun update(registry: MutableCollection<MutableEntry>, modifier: ResourceLocation)
|
||||
|
||||
protected inline fun fail(reason: () -> String) {
|
||||
if (errorOnFailure) {
|
||||
throw JsonParseException(reason.invoke())
|
||||
}
|
||||
}
|
||||
|
||||
open fun toJson(): JsonObject {
|
||||
return JsonObject().also {
|
||||
if (key != null)
|
||||
it["id"] = JsonPrimitive(key.toString())
|
||||
else
|
||||
it["id"] = JsonPrimitive("#${tag!!.location}")
|
||||
|
||||
if (priority != null)
|
||||
it["priority"] = priority
|
||||
|
||||
if (matter != null)
|
||||
it["matter"] = matter.toString()
|
||||
|
||||
if (complexity != null)
|
||||
it["complexity"] = complexity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InsertAction : AbstractRegistryAction {
|
||||
val replaceIfExists: Boolean
|
||||
val comparePriority: Boolean
|
||||
|
||||
constructor(
|
||||
key: ResourceLocation,
|
||||
matter: ImpreciseFraction?,
|
||||
complexity: Double?,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false,
|
||||
replaceIfExists: Boolean = false,
|
||||
comparePriority: Boolean = false,
|
||||
) : super(key = key, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) {
|
||||
this.replaceIfExists = replaceIfExists
|
||||
this.comparePriority = comparePriority
|
||||
}
|
||||
|
||||
constructor(
|
||||
tag: TagKey<Item>,
|
||||
matter: ImpreciseFraction?,
|
||||
complexity: Double?,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false,
|
||||
replaceIfExists: Boolean = false,
|
||||
comparePriority: Boolean = false,
|
||||
) : super(tag = tag, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) {
|
||||
this.replaceIfExists = replaceIfExists
|
||||
this.comparePriority = comparePriority
|
||||
}
|
||||
|
||||
constructor(json: JsonObject) : super(json) {
|
||||
this.replaceIfExists = json["replace_if_exists"]?.asBoolean ?: false
|
||||
this.comparePriority = json["compare_priority"]?.asBoolean ?: false
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
checkNotNull(matter) { "Missing matter value, which is required for insert action" }
|
||||
checkNotNull(complexity) { "Missing complexity value, which is required for insert action" }
|
||||
|
||||
return super.toJson().also {
|
||||
it["action"] = "insert"
|
||||
it["replace_if_exists"] = replaceIfExists
|
||||
it["compare_priority"] = comparePriority
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(registry: MutableCollection<MutableEntry>, modifier: ResourceLocation) {
|
||||
checkNotNull(matter) { "Missing matter value, which is required for insert action" }
|
||||
checkNotNull(complexity) { "Missing complexity value, which is required for insert action" }
|
||||
|
||||
check(!comparePriority || priority != null) { "If compare_priority is true then priority must not be null" }
|
||||
|
||||
if (!checkConditions()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (key != null) {
|
||||
if (replaceIfExists) {
|
||||
// search & replace in parallel, if possible
|
||||
val replaced = registry.parallelStream().anyMatch {
|
||||
if (it is MutableKeyEntry && it.key == key) {
|
||||
if (!comparePriority || it.priority < priority!!) {
|
||||
it.matter = matter
|
||||
it.complexity = complexity
|
||||
it.priority = priority ?: 0
|
||||
it.modificationChain.clear()
|
||||
it.modificationChain.add(modifier)
|
||||
}
|
||||
|
||||
return@anyMatch true
|
||||
} else {
|
||||
return@anyMatch false
|
||||
}
|
||||
}
|
||||
|
||||
if (!replaced) {
|
||||
registry.add(MutableKeyEntry(key, mutableListOf(modifier), matter, complexity, priority ?: 0))
|
||||
}
|
||||
} else {
|
||||
if (registry.parallelStream().anyMatch { it is MutableKeyEntry && it.key == key }) {
|
||||
fail { "Value with key $key already exists" }
|
||||
return
|
||||
}
|
||||
|
||||
registry.add(MutableKeyEntry(key, mutableListOf(modifier), matter, complexity, priority ?: 0))
|
||||
}
|
||||
} else {
|
||||
if (replaceIfExists) {
|
||||
// search & replace in parallel, if possible
|
||||
val replaced = registry.parallelStream().anyMatch {
|
||||
if (it is MutableTagEntry && it.tag == tag) {
|
||||
if (!comparePriority || it.priority < priority!!) {
|
||||
it.matter = matter
|
||||
it.complexity = complexity
|
||||
it.priority = priority ?: 0
|
||||
it.modificationChain.clear()
|
||||
it.modificationChain.add(modifier)
|
||||
}
|
||||
|
||||
return@anyMatch true
|
||||
} else {
|
||||
return@anyMatch false
|
||||
}
|
||||
}
|
||||
|
||||
if (!replaced) {
|
||||
registry.add(MutableTagEntry(tag!!, mutableListOf(modifier), matter, complexity, priority ?: 0))
|
||||
}
|
||||
} else {
|
||||
if (registry.parallelStream().anyMatch { it is MutableTagEntry && it.tag == tag }) {
|
||||
fail { "Value with tag $tag already exists" }
|
||||
return
|
||||
}
|
||||
|
||||
registry.add(MutableTagEntry(tag!!, mutableListOf(modifier), matter, complexity, priority ?: 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteAction : AbstractRegistryAction {
|
||||
constructor(
|
||||
tag: TagKey<Item>,
|
||||
errorOnFailure: Boolean = false,
|
||||
) : super(tag = tag, errorOnFailure = errorOnFailure, matter = null, complexity = null)
|
||||
|
||||
constructor(
|
||||
key: ResourceLocation,
|
||||
errorOnFailure: Boolean = false,
|
||||
) : super(key = key, errorOnFailure = errorOnFailure, matter = null, complexity = null)
|
||||
|
||||
constructor(json: JsonObject) : super(json)
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["action"] = "delete"
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(registry: MutableCollection<MutableEntry>, modifier: ResourceLocation) {
|
||||
if (!checkConditions()) {
|
||||
return
|
||||
}
|
||||
|
||||
check(matter == null) { "Delete action can't have matter value" }
|
||||
check(complexity == null) { "Delete action can't have complexity value" }
|
||||
|
||||
if (key != null) {
|
||||
val iterator = registry.iterator()
|
||||
|
||||
for (value in iterator) {
|
||||
if (value is MutableKeyEntry && value.key == key) {
|
||||
iterator.remove()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fail { "Could not find matter value with key $key" }
|
||||
} else {
|
||||
val iterator = registry.iterator()
|
||||
|
||||
for (value in iterator) {
|
||||
if (value is MutableTagEntry && value.tag == tag) {
|
||||
iterator.remove()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fail { "Could not find matter value with tag $tag" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateAction : AbstractRegistryAction {
|
||||
enum class Function {
|
||||
ADD {
|
||||
override fun updateValue(self: Int, other: Int): Int = self + other
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self + other
|
||||
override fun updateValue(self: Double, other: Double): Double = self + other
|
||||
},
|
||||
SUBTRACT {
|
||||
override fun updateValue(self: Int, other: Int): Int = self - other
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self - other
|
||||
override fun updateValue(self: Double, other: Double): Double = self - other
|
||||
},
|
||||
MULTIPLY {
|
||||
override fun updateValue(self: Int, other: Int): Int = self * other
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self * other
|
||||
override fun updateValue(self: Double, other: Double): Double = self * other
|
||||
},
|
||||
DIVIDE {
|
||||
override fun updateValue(self: Int, other: Int): Int = self / other
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self / other
|
||||
override fun updateValue(self: Double, other: Double): Double = self / other
|
||||
},
|
||||
DIVIDE_UP {
|
||||
override fun updateValue(self: Int, other: Int): Int = integerDivisionUp(self, other)
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException("Integer division up is available only for integers")
|
||||
override fun updateValue(self: Double, other: Double): Double = throw JsonParseException("Integer division up is available only for integers")
|
||||
},
|
||||
DIVIDE_DOWN {
|
||||
override fun updateValue(self: Int, other: Int): Int = integerDivisionDown(self, other)
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException("Integer division down is available only for integers")
|
||||
override fun updateValue(self: Double, other: Double): Double = throw JsonParseException("Integer division down is available only for integers")
|
||||
},
|
||||
MODULO {
|
||||
override fun updateValue(self: Int, other: Int): Int = self % other
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self % other
|
||||
override fun updateValue(self: Double, other: Double): Double = self % other
|
||||
},
|
||||
AT_LEAST {
|
||||
override fun updateValue(self: Int, other: Int): Int = self.coerceAtLeast(other)
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtLeast(other)
|
||||
override fun updateValue(self: Double, other: Double): Double = self.coerceAtLeast(other)
|
||||
},
|
||||
AT_MOST {
|
||||
override fun updateValue(self: Int, other: Int): Int = self.coerceAtMost(other)
|
||||
override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtMost(other)
|
||||
override fun updateValue(self: Double, other: Double): Double = self.coerceAtMost(other)
|
||||
},
|
||||
;
|
||||
|
||||
protected abstract fun updateValue(self: Int, other: Int): Int
|
||||
protected abstract fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction
|
||||
protected abstract fun updateValue(self: Double, other: Double): Double
|
||||
|
||||
fun <T : Number> updateValue(self: T, other: T): T {
|
||||
return when (self) {
|
||||
is ImpreciseFraction -> updateValue(self, other)
|
||||
is Double -> updateValue(self, other)
|
||||
is Int -> updateValue(self, other)
|
||||
else -> throw RuntimeException("Unknown number type: ${self::class.qualifiedName}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BoundFunction<T : Number>(val function: Function, val value: T) {
|
||||
fun apply(self: T): T {
|
||||
return function.updateValue(self, value)
|
||||
}
|
||||
|
||||
fun toJson(): JsonObject {
|
||||
return JsonObject().also {
|
||||
it["type"] = function.name
|
||||
|
||||
if (value is Int || value is Double)
|
||||
it["value"] = value
|
||||
else
|
||||
it["value"] = value.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
inline fun <reified T : Number> getValue(value: JsonElement): T {
|
||||
return when (T::class) {
|
||||
ImpreciseFraction::class -> ImpreciseFraction(value.asString) as T
|
||||
Double::class -> value.asDouble as T
|
||||
Int::class -> value.asInt as T
|
||||
else -> throw RuntimeException("Unknown number type: ${T::class.qualifiedName}")
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Number> deserializeFunctionTree(input: JsonElement?, name: String): List<BoundFunction<T>> {
|
||||
if (input == null) {
|
||||
return listOf()
|
||||
}
|
||||
|
||||
if (input !is JsonArray) {
|
||||
throw JsonParseException("Expected $name to be JsonArray, ${input::class.qualifiedName} given")
|
||||
}
|
||||
|
||||
return input.stream().map {
|
||||
if (it !is JsonObject) {
|
||||
throw JsonParseException("All elements in function tree must be JsonObjects, ${it::class.qualifiedName} given")
|
||||
}
|
||||
|
||||
val type = it["type"]?.asString ?: throw JsonParseException("Invalid `type` value in function object")
|
||||
val value = it["value"] ?: throw JsonParseException("Missing `value` value in function object")
|
||||
|
||||
val parsedValue: T = getValue(value)
|
||||
val fn: Function
|
||||
|
||||
try {
|
||||
fn = Function.valueOf(type.uppercase())
|
||||
} catch (err: NoSuchElementException) {
|
||||
throw JsonParseException("No such function: $type", err)
|
||||
}
|
||||
|
||||
return@map BoundFunction(fn, parsedValue)
|
||||
}.collect(ImmutableList.toImmutableList())
|
||||
}
|
||||
|
||||
fun <T : Number> apply(value: T, funcs: Collection<BoundFunction<T>>): T {
|
||||
if (funcs.isEmpty()) {
|
||||
return value
|
||||
}
|
||||
|
||||
var newValue = value
|
||||
|
||||
for (func in funcs) {
|
||||
newValue = func.apply(newValue)
|
||||
}
|
||||
|
||||
return newValue
|
||||
}
|
||||
}
|
||||
|
||||
val matterFunctions: List<BoundFunction<ImpreciseFraction>>
|
||||
val complexityFunctions: List<BoundFunction<Double>>
|
||||
val priorityFunctions: List<BoundFunction<Int>>
|
||||
|
||||
constructor(json: JsonObject) : super(json) {
|
||||
matterFunctions = deserializeFunctionTree(json["matter_functions"], "matter_functions")
|
||||
complexityFunctions = deserializeFunctionTree(json["complexity_functions"], "complexity_functions")
|
||||
priorityFunctions = deserializeFunctionTree(json["priority_functions"], "priority_functions")
|
||||
}
|
||||
|
||||
constructor(
|
||||
tag: TagKey<Item>,
|
||||
matter: ImpreciseFraction? = null,
|
||||
complexity: Double? = null,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false,
|
||||
matterFunctions: List<BoundFunction<ImpreciseFraction>> = ImmutableList.of(),
|
||||
complexityFunctions: List<BoundFunction<Double>> = ImmutableList.of(),
|
||||
priorityFunctions: List<BoundFunction<Int>> = ImmutableList.of(),
|
||||
) : super(tag = tag, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) {
|
||||
check(matter != null || complexity != null || priority != null || matterFunctions.isNotEmpty() || complexityFunctions.isNotEmpty() || priorityFunctions.isNotEmpty()) {
|
||||
"Can't update existing entries without anything specified"
|
||||
}
|
||||
|
||||
this.matterFunctions = ImmutableList.copyOf(matterFunctions)
|
||||
this.complexityFunctions = ImmutableList.copyOf(complexityFunctions)
|
||||
this.priorityFunctions = ImmutableList.copyOf(priorityFunctions)
|
||||
}
|
||||
|
||||
constructor(
|
||||
key: ResourceLocation,
|
||||
matter: ImpreciseFraction? = null,
|
||||
complexity: Double? = null,
|
||||
priority: Int? = null,
|
||||
errorOnFailure: Boolean = false,
|
||||
matterFunctions: List<BoundFunction<ImpreciseFraction>> = ImmutableList.of(),
|
||||
complexityFunctions: List<BoundFunction<Double>> = ImmutableList.of(),
|
||||
priorityFunctions: List<BoundFunction<Int>> = ImmutableList.of(),
|
||||
) : super(key = key, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) {
|
||||
check(matter != null || complexity != null || priority != null || matterFunctions.isNotEmpty() || complexityFunctions.isNotEmpty() || priorityFunctions.isNotEmpty()) {
|
||||
"Can't update existing entries without anything specified"
|
||||
}
|
||||
|
||||
this.matterFunctions = ImmutableList.copyOf(matterFunctions)
|
||||
this.complexityFunctions = ImmutableList.copyOf(complexityFunctions)
|
||||
this.priorityFunctions = ImmutableList.copyOf(priorityFunctions)
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["action"] = "update"
|
||||
|
||||
if (matterFunctions.isNotEmpty()) {
|
||||
it["matter_functions"] = JsonArray().also {
|
||||
for (fn in matterFunctions) {
|
||||
it.add(fn.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (complexityFunctions.isNotEmpty()) {
|
||||
it["complexity_functions"] = JsonArray().also {
|
||||
for (fn in complexityFunctions) {
|
||||
it.add(fn.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (priorityFunctions.isNotEmpty()) {
|
||||
it["priority_functions"] = JsonArray().also {
|
||||
for (fn in priorityFunctions) {
|
||||
it.add(fn.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun apply(value: MutableEntry, modifier: ResourceLocation) {
|
||||
if (matterFunctions.isNotEmpty())
|
||||
value.matter = apply(value.matter, matterFunctions)
|
||||
else if (matter != null)
|
||||
value.matter = matter
|
||||
|
||||
if (complexityFunctions.isNotEmpty())
|
||||
value.complexity = apply(value.complexity, complexityFunctions)
|
||||
else if (complexity != null)
|
||||
value.complexity = complexity
|
||||
|
||||
if (priorityFunctions.isNotEmpty())
|
||||
value.priority = apply(value.priority, priorityFunctions)
|
||||
else if (priority != null)
|
||||
value.priority = priority
|
||||
|
||||
value.modificationChain.add(modifier)
|
||||
}
|
||||
|
||||
override fun update(registry: MutableCollection<MutableEntry>, modifier: ResourceLocation) {
|
||||
if(!(
|
||||
matter != null ||
|
||||
complexity != null ||
|
||||
priority != null ||
|
||||
matterFunctions.isNotEmpty() ||
|
||||
complexityFunctions.isNotEmpty() ||
|
||||
priorityFunctions.isNotEmpty()
|
||||
)) {
|
||||
throw JsonParseException("Can't update existing entries without anything specified")
|
||||
}
|
||||
|
||||
if (matter != null && matterFunctions.isNotEmpty()) {
|
||||
throw JsonParseException("Can't have both matter and matter functions specified at the same time")
|
||||
}
|
||||
|
||||
if (complexity != null && complexityFunctions.isNotEmpty()) {
|
||||
throw JsonParseException("Can't have both complexity and complexity functions specified at the same time")
|
||||
}
|
||||
|
||||
if (priority != null && priorityFunctions.isNotEmpty()) {
|
||||
throw JsonParseException("Can't have both priority and priority functions specified at the same time")
|
||||
}
|
||||
|
||||
if (!checkConditions()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (key != null) {
|
||||
val iterator = registry.iterator()
|
||||
|
||||
for (value in iterator) {
|
||||
if (value is MutableKeyEntry && value.key == key) {
|
||||
apply(value, modifier)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fail { "Could not find matter value with key $key" }
|
||||
} else {
|
||||
val iterator = registry.iterator()
|
||||
|
||||
for (value in iterator) {
|
||||
if (value is MutableTagEntry && value.tag == tag) {
|
||||
apply(value, modifier)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fail { "Could not find matter value with tag $tag" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MutableEntry(
|
||||
val modificationChain: MutableList<ResourceLocation>,
|
||||
var matter: ImpreciseFraction,
|
||||
var complexity: Double,
|
||||
var priority: Int
|
||||
) {
|
||||
abstract fun freeze(): Entry
|
||||
}
|
||||
|
||||
class MutableTagEntry(
|
||||
val tag: TagKey<Item>,
|
||||
modificationChain: MutableList<ResourceLocation>,
|
||||
matter: ImpreciseFraction,
|
||||
complexity: Double,
|
||||
priority: Int
|
||||
) : MutableEntry(modificationChain, matter, complexity, priority) {
|
||||
override fun freeze(): Entry {
|
||||
return TagEntry(tag, ImmutableList.copyOf(modificationChain), matter, complexity, priority)
|
||||
}
|
||||
}
|
||||
|
||||
class MutableKeyEntry(
|
||||
val key: ResourceLocation,
|
||||
modificationChain: MutableList<ResourceLocation>,
|
||||
matter: ImpreciseFraction,
|
||||
complexity: Double,
|
||||
priority: Int
|
||||
) : MutableEntry(modificationChain, matter, complexity, priority) {
|
||||
override fun freeze(): Entry {
|
||||
return KeyEntry(key, ImmutableList.copyOf(modificationChain), matter, complexity, priority)
|
||||
}
|
||||
}
|
||||
|
||||
interface IMatterValue {
|
||||
val matter: ImpreciseFraction
|
||||
val complexity: Double
|
||||
|
||||
val hasMatterValue: Boolean get() = matter.isPositive && complexity > 0.0
|
||||
}
|
||||
|
||||
sealed class Entry(
|
||||
val modificationChain: List<ResourceLocation>,
|
||||
final override val matter: ImpreciseFraction,
|
||||
final override val complexity: Double,
|
||||
val priority: Int,
|
||||
) : IMatterValue {
|
||||
companion object : Entry(listOf(), ImpreciseFraction.ZERO, 0.0, Int.MIN_VALUE)
|
||||
}
|
||||
|
||||
class TagEntry(
|
||||
val tag: TagKey<Item>,
|
||||
modificationChain: List<ResourceLocation>,
|
||||
matter: ImpreciseFraction,
|
||||
complexity: Double,
|
||||
priority: Int,
|
||||
) : Entry(modificationChain, matter, complexity, priority) {
|
||||
val bound by lazy {
|
||||
val manager = ForgeRegistries.ITEMS.tags() ?: throw NullPointerException("Forge registry of Items has no tags!")
|
||||
manager.getTag(tag)
|
||||
}
|
||||
}
|
||||
|
||||
class KeyEntry(
|
||||
val key: ResourceLocation,
|
||||
modificationChain: List<ResourceLocation>,
|
||||
matter: ImpreciseFraction,
|
||||
complexity: Double,
|
||||
priority: Int,
|
||||
) : Entry(modificationChain, matter, complexity, priority)
|
||||
|
||||
private var canCompute = false
|
||||
private val keyEntries = HashMap<ResourceLocation, KeyEntry>()
|
||||
private val tagEntries = ArrayList<TagEntry>()
|
||||
private val computedEntries = Reference2ObjectOpenHashMap<Item, Entry>()
|
||||
|
||||
operator fun get(value: Item): Entry {
|
||||
check(canCompute) { "Can't compute matter values yet, datapack wasn't loaded or is in progress of loading!" }
|
||||
|
||||
synchronized(computedEntries) {
|
||||
return computedEntries.computeIfAbsent(value, Reference2ObjectFunction {
|
||||
it as Item
|
||||
val key = it.registryName ?: throw NullPointerException("$it has no registry name!")
|
||||
|
||||
val keyEntry = keyEntries[key]
|
||||
|
||||
if (keyEntry != null) {
|
||||
return@Reference2ObjectFunction keyEntry
|
||||
}
|
||||
|
||||
for (entry in tagEntries) {
|
||||
if (entry.bound.contains(it)) {
|
||||
return@Reference2ObjectFunction entry
|
||||
}
|
||||
}
|
||||
|
||||
return@Reference2ObjectFunction Entry.Companion
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun reloadEvent(event: AddReloadListenerEvent) {
|
||||
event.addListener(this)
|
||||
}
|
||||
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
override fun prepare(
|
||||
resourceManager: ResourceManager,
|
||||
profilerFiller: ProfilerFiller
|
||||
): MutableMap<ResourceLocation, JsonElement> {
|
||||
val time = System.nanoTime()
|
||||
LOGGER.info("Beginning preparations for loading matter values")
|
||||
profilerFiller.push("otm_matter_registry_prepare")
|
||||
|
||||
try {
|
||||
val prep = super.prepare(resourceManager, profilerFiller)
|
||||
val diff = System.nanoTime() - time
|
||||
LOGGER.info("Finished preparations for loading matter values, took ${diff / 1_000_000L}ms")
|
||||
return prep
|
||||
} finally {
|
||||
profilerFiller.pop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun apply(
|
||||
map: MutableMap<ResourceLocation, JsonElement>,
|
||||
resourceManager: ResourceManager,
|
||||
profilerFiller: ProfilerFiller
|
||||
) {
|
||||
val time = System.nanoTime()
|
||||
LOGGER.info("Beginning loading matter values")
|
||||
profilerFiller.push("otm_matter_registry")
|
||||
|
||||
try {
|
||||
canCompute = false
|
||||
|
||||
keyEntries.clear()
|
||||
tagEntries.clear()
|
||||
computedEntries.clear()
|
||||
|
||||
val add = ArrayList<Pair<InsertAction, ResourceLocation>>()
|
||||
val addOrReplace = ArrayList<Pair<InsertAction, ResourceLocation>>()
|
||||
val update = ArrayList<Pair<UpdateAction, ResourceLocation>>()
|
||||
val delete = ArrayList<Pair<DeleteAction, ResourceLocation>>()
|
||||
|
||||
for ((key, json) in map) {
|
||||
if (json !is JsonObject) {
|
||||
throw JsonParseException("Matter value $key has invalid type: ${json::class.qualifiedName} ($json)")
|
||||
}
|
||||
|
||||
when (val action = json["action"]?.asString?.lowercase() ?: throw JsonParseException("Missing `action` json element in $key. Possible values are: (INSERT, DELETE and UPDATE (case-insensitive))")) {
|
||||
"insert" -> {
|
||||
val value = InsertAction(json)
|
||||
|
||||
if (value.replaceIfExists) {
|
||||
addOrReplace.add(value to key)
|
||||
} else {
|
||||
add.add(value to key)
|
||||
}
|
||||
}
|
||||
|
||||
"update" -> update.add(UpdateAction(json) to key)
|
||||
"delete" -> delete.add(DeleteAction(json) to key)
|
||||
else -> throw JsonParseException("Unknown action $action of $key")
|
||||
}
|
||||
}
|
||||
|
||||
val registry = ArrayList<MutableEntry>()
|
||||
|
||||
for (action in add)
|
||||
action.first.update(registry, action.second)
|
||||
|
||||
for (action in addOrReplace)
|
||||
action.first.update(registry, action.second)
|
||||
|
||||
for (action in delete)
|
||||
action.first.update(registry, action.second)
|
||||
|
||||
for (action in update)
|
||||
action.first.update(registry, action.second)
|
||||
|
||||
val tags = HashMap<TagKey<Item>, MutableTagEntry>()
|
||||
val keys = HashMap<ResourceLocation, MutableKeyEntry>()
|
||||
|
||||
for (entry in registry) {
|
||||
if (entry is MutableTagEntry) {
|
||||
val existing = tags[entry.tag]
|
||||
|
||||
if (existing == null || existing.priority < entry.priority) {
|
||||
tags[entry.tag] = entry
|
||||
}
|
||||
} else if (entry is MutableKeyEntry) {
|
||||
val existing = keys[entry.key]
|
||||
|
||||
if (existing == null || existing.priority < entry.priority) {
|
||||
keys[entry.key] = entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (key in keys.values) {
|
||||
keyEntries[key.key] = key.freeze() as KeyEntry
|
||||
}
|
||||
|
||||
for (tag in tags.values) {
|
||||
tagEntries.add(tag.freeze() as TagEntry)
|
||||
}
|
||||
|
||||
tagEntries.sortBy { it.priority }
|
||||
|
||||
canCompute = true
|
||||
} finally {
|
||||
profilerFiller.pop()
|
||||
}
|
||||
|
||||
val diff = System.nanoTime() - time
|
||||
LOGGER.info("Finished loading matter values, took ${diff / 1_000_000L}ms")
|
||||
}
|
||||
}
|
@ -131,14 +131,14 @@ fun getMatterValue(item: Item): MatterTuple {
|
||||
if (item is IMatterItem)
|
||||
return item.getMatterValue(ItemStack.EMPTY) ?: MatterTuple.ZERO
|
||||
|
||||
return rootEntries[item] ?: derivedEntries[item] ?: MatterTuple.ZERO
|
||||
return MatterManager[item].let { MatterTuple(it.matter, it.complexity) }
|
||||
}
|
||||
|
||||
fun getMatterValueNullable(item: Item): MatterTuple? {
|
||||
if (item is IMatterItem)
|
||||
return item.getMatterValue(ItemStack.EMPTY)
|
||||
|
||||
return rootEntries[item] ?: derivedEntries[item]
|
||||
return MatterManager[item].let { MatterTuple(it.matter, it.complexity) }
|
||||
}
|
||||
|
||||
fun hasMatterValue(item: Item): Boolean {
|
||||
|
Loading…
Reference in New Issue
Block a user