diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt index 5d8dc61b8..00599e085 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt @@ -4,6 +4,9 @@ import net.minecraft.tags.ItemTags import net.minecraft.world.item.Items import net.minecraftforge.common.Tags import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.android.AndroidResearchDescriptions +import ru.dbotthepony.mc.otm.android.AndroidResearchResult +import ru.dbotthepony.mc.otm.android.AndroidResearchResults import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature import ru.dbotthepony.mc.otm.android.feature.FallDampenersFeature @@ -132,11 +135,13 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang ) ) .addItem(MItemTags.COPPER_WIRES, 4 + i * 2) - .addFeatureResult(OverdriveThatMatters.loc(MNames.LIMB_OVERCLOCKING), i) if (i > 0) { + research.addFeatureLevel(AndroidFeatures.LIMB_OVERCLOCKING) research.addPrerequisite(OverdriveThatMatters.loc(MNames.LIMB_OVERCLOCKING_LIST[i - 1]), rigid = true) research.addItem(MItemTags.GOLD_WIRES, i * 2) + } else { + research.addFeatureResult(AndroidFeatures.LIMB_OVERCLOCKING) } research.build() @@ -155,18 +160,20 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang (i + 1) * 15 ) ) - .addFeatureResult(AndroidFeatures.ATTACK_BOOST, i) .addBlocker(NANOBOTS_ARMOR) if (i > 0) { + research.addFeatureLevel(AndroidFeatures.ATTACK_BOOST) research.addPrerequisite(OverdriveThatMatters.loc(MNames.ATTACK_BOOST_LIST[i - 1]), rigid = true) + } else { + research.addFeatureResult(AndroidFeatures.ATTACK_BOOST) } research.build() }) regenList.add(run { - val regeneration = AndroidResearchType.Builder(modLocation(MNames.NANOBOTS_REGENERATION_LIST[i])) + val research = AndroidResearchType.Builder(modLocation(MNames.NANOBOTS_REGENERATION_LIST[i])) .withExperience(20 + i * 6) .withIconText(TextComponent((i + 1).toString())) .withIcon(ResearchIcons.ICON_NANOBOTS) @@ -179,15 +186,16 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang .addItem(MItems.MATTER_CAPACITOR_PARTS, 1) .addItem(Items.SUGAR, 2 + i * 2) .addItem(Tags.Items.DUSTS_REDSTONE, 2 + i * 2) - .addFeatureResult(AndroidFeatures.NANOBOTS_REGENERATION, i) if (i > 0) { - regeneration.addPrerequisite(OverdriveThatMatters.loc(MNames.NANOBOTS_REGENERATION_LIST[i - 1]), rigid = true) + research.addFeatureLevel(AndroidFeatures.NANOBOTS_REGENERATION) + research.addPrerequisite(OverdriveThatMatters.loc(MNames.NANOBOTS_REGENERATION_LIST[i - 1]), rigid = true) } else { - regeneration.addPrerequisite(OverdriveThatMatters.loc(MNames.NANOBOTS), rigid = true) + research.addPrerequisite(OverdriveThatMatters.loc(MNames.NANOBOTS), rigid = true) + research.addFeatureResult(AndroidFeatures.NANOBOTS_REGENERATION) } - regeneration.build() + research.build() }) } @@ -216,10 +224,7 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang .addItem(MItemTags.TRITANIUM_PLATES, 2 + i * 2) .addItem(Items.SUGAR, 1 + i) .addItem(MItems.ELECTROMAGNET) - .addFeatureResult(AndroidFeatures.NANOBOTS_ARMOR, 0, - transformersUp = listOf(NanobotsArmorFeature.STRENGTH_TRANSFORMER_UP.bind(level)), - transformersDown = listOf(NanobotsArmorFeature.STRENGTH_TRANSFORMER_DOWN.bind(level)), - ) + .addResult(AndroidResearchResults.NANOBOTS_ARMOR_STRENGTH) .build() }) @@ -243,10 +248,7 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang ) ) .addItem(Tags.Items.DUSTS_REDSTONE, 4 + i * 4) - .addFeatureResult(AndroidFeatures.NANOBOTS_ARMOR, 0, - transformersUp = listOf(NanobotsArmorFeature.SPEED_TRANSFORMER_UP.bind(level)), - transformersDown = listOf(NanobotsArmorFeature.SPEED_TRANSFORMER_DOWN.bind(level)), - ) + .addResult(AndroidResearchResults.NANOBOTS_ARMOR_SPEED) .build() }) } @@ -261,7 +263,7 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.SHOCKWAVE)) .withExperience(40) .withDescription(0 .. 1) - .appendDescription(ShockwaveFeature.POWER_COST_DESCRIPTION) + .withDescription(AndroidResearchDescriptions.SHOCKWAVE) .withIcon(ResearchIcons.ICON_SHOCKWAVE) .addFeatureResult(AndroidFeatures.SHOCKWAVE) .addPrerequisite(attackBoostList[2]) @@ -276,7 +278,7 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.ITEM_MAGNET)) .withExperience(28) .withDescription(0 .. 1) - .appendDescription(ItemMagnetFeature.POWER_COST_DESCRIPTION) + .withDescription(AndroidResearchDescriptions.ITEM_MAGNET) .withIcon(ResearchIcons.ICON_ITEM_MAGNET) .addFeatureResult(AndroidFeatures.ITEM_MAGNET) .addPrerequisite(STEP_ASSIST) @@ -292,9 +294,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.FALL_DAMPENERS + "_1")) .withExperience(25) .withDescription() - .appendDescription(FallDampenersFeature.DESCRIPTION.bind(1)) + .withDescription(AndroidResearchDescriptions.FALL_DAMPENERS.Instance(1)) .withIcon(ResearchIcons.ICON_FEATHER_FALLING) - .addFeatureResult(AndroidFeatures.FALL_DAMPENERS, 0) + .addFeatureResult(AndroidFeatures.FALL_DAMPENERS) .addPrerequisite(STEP_ASSIST) .addItem(MItems.ELECTROMAGNET, 2) .addItem(ItemTags.WOOL, 2) @@ -305,9 +307,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.FALL_DAMPENERS + "_2")) .withExperience(30) .withDescription() - .appendDescription(FallDampenersFeature.DESCRIPTION.bind(2)) + .withDescription(AndroidResearchDescriptions.FALL_DAMPENERS.Instance(2)) .withIcon(ResearchIcons.ICON_FEATHER_FALLING) - .addFeatureResult(AndroidFeatures.FALL_DAMPENERS, 1) + .addFeatureLevel(AndroidFeatures.FALL_DAMPENERS) .addPrerequisite(FALL_DAMPENERS_1) .addItem(MItemTags.GOLD_PLATES, 2) .addItem(MItemTags.COPPER_WIRES, 4) @@ -319,9 +321,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.FALL_DAMPENERS + "_3")) .withExperience(35) .withDescription(0 .. 1) - .appendDescription(FallDampenersFeature.DESCRIPTION.bind(3)) + .withDescription(AndroidResearchDescriptions.FALL_DAMPENERS.Instance(2)) .withIcon(ResearchIcons.ICON_FEATHER_FALLING) - .addFeatureResult(AndroidFeatures.FALL_DAMPENERS, 2) + .addFeatureLevel(AndroidFeatures.FALL_DAMPENERS) .addPrerequisite(FALL_DAMPENERS_2) .addItem(MItemTags.ADVANCED_CIRCUIT, 2) .addItem(Tags.Items.GEMS_DIAMOND, 4) @@ -337,7 +339,7 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.ENDER_TELEPORTER)) .withExperience(35) .withDescription() - .appendDescription(EnderTeleporterFeature.POWER_COST_DESCRIPTION) + .withDescription(AndroidResearchDescriptions.ENDER_TELEPORTER) .withIcon(ResearchIcons.ICON_ENDER_TELEPORT) .addFeatureResult(AndroidFeatures.ENDER_TELEPORTER) .addPrerequisite(FALL_DAMPENERS_1) @@ -368,9 +370,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.JUMP_BOOST + "_1")) .withExperience(27) .withDescription(0 .. 1) - .appendDescription(JumpBoostFeature.POWER_COST_DESCRIPTION) + .withDescription(AndroidResearchDescriptions.JUMP_BOOST) .withIcon(ResearchIcons.ICON_JUMP_BOOST) - .addFeatureResult(AndroidFeatures.JUMP_BOOST, 0) + .addFeatureResult(AndroidFeatures.JUMP_BOOST) .addItem(MItemTags.PISTONS, 2) .addItem(MItemTags.GOLD_WIRES, 4) .addItem(MItems.ELECTROMAGNET, 2) @@ -382,9 +384,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang AndroidResearchType.Builder(modLocation(MNames.JUMP_BOOST + "_2")) .withExperience(34) .withDescription() - .appendDescription(JumpBoostFeature.POWER_COST_DESCRIPTION) + .withDescription(AndroidResearchDescriptions.JUMP_BOOST) .withIcon(ResearchIcons.ICON_JUMP_BOOST) - .addFeatureResult(AndroidFeatures.JUMP_BOOST, 1) + .addFeatureLevel(AndroidFeatures.JUMP_BOOST) .addItem(MItems.ELECTRIC_PARTS, 4) .addItem(MItems.ELECTROMAGNET, 4) .addPrerequisite(JUMP_BOOST_1) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt index c9cc9e664..aa03048e3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.android import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import net.minecraft.ChatFormatting import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag @@ -15,7 +14,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.awareItemsStream import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent -import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.nbt.getCompoundList import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.nbt.set @@ -46,62 +44,19 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay return } - onUnResearch() + onRefunded() isResearched = false } - private data class RememberResearchLevel(val level: Int?) - - private val oldResearchLevel = Object2ObjectArrayMap, RememberResearchLevel>() - - fun onUnResearch() { - for (feature in type.resolvedFeatures) { - val level = oldResearchLevel[feature.feature] - val get = capability.getFeature(feature.feature) - - if (level != null && get != null) { - if (get.level == feature.level) { - if (level.level == null) { - capability.removeFeature(feature.feature) - } else { - get.level = level.level - - for (transformer in type.features.first { it.id == feature.feature.registryName }.transformersDown) { - transformer.apply(this to get) - } - } - } - } + fun onRefunded() { + for (result in type.results) { + result.onRefunded(this) } - - oldResearchLevel.clear() } fun onResearched() { - oldResearchLevel.clear() - - try { - for (feature in type.resolvedFeatures) { - var get = capability.getFeature(feature.feature) - - if (get == null) { - get = capability.addFeature(feature.feature) - get.level = feature.level - oldResearchLevel[feature.feature] = RememberResearchLevel(null) - } else { - if (get.level < feature.level) { - oldResearchLevel[feature.feature] = RememberResearchLevel(feature.level) - get.level = feature.level - } - } - - for (transformer in type.features.first { it.id == feature.feature.registryName }.transformersUp) { - transformer.apply(this to get) - } - } - } catch(err: Throwable) { - oldResearchLevel.clear() - throw err + for (result in type.results) { + result.onResearched(this) } } @@ -297,7 +252,10 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay val tooltipLines: List get() { val lines = ArrayList() lines.add(type.displayName) - lines.addAll(type.description.iterator()) + + for (line in type.description) { + line.addLines(this, lines) + } return lines } @@ -382,38 +340,10 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay override fun serializeNBT(): CompoundTag { return CompoundTag().also { it["researched"] = isResearched - - it["oldResearchLevel"] = ListTag().also { - for ((k, v) in oldResearchLevel) { - it.add(CompoundTag().also { - it["key"] = k.registryName!!.toString() - it["value"] = CompoundTag().also { - it["isPresent"] = v.level != null - - if (v.level != null) { - it["value"] = v.level - } - } - }) - } - } } } override fun deserializeNBT(nbt: CompoundTag) { isResearched = nbt.getBoolean("researched") - - oldResearchLevel.clear() - - for (tag in nbt.getCompoundList("oldResearchLevel")) { - val key = tag.getString("key") - val type = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(key)) ?: continue - val value = tag.getCompound("value") - - val isPresent = value.getBoolean("isPresent") - val int = value.getInt("value") - - oldResearchLevel[type] = RememberResearchLevel(if (isPresent) int else null) - } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt index 779263e7d..ee9b57c9a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt @@ -50,8 +50,6 @@ open class AndroidResearchDataProvider() : DataProvider { } final override fun run(output: CachedOutput): CompletableFuture<*> { - AndroidResearchManager.fireRegistrationEvent() - val set = ObjectArraySet() val added = LinkedList() val futures = ArrayList>() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDescription.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDescription.kt new file mode 100644 index 000000000..1a5c51867 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDescription.kt @@ -0,0 +1,133 @@ +package ru.dbotthepony.mc.otm.android + +import com.mojang.datafixers.util.Either +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import net.minecraftforge.eventbus.api.IEventBus +import net.minecraftforge.registries.DeferredRegister +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.client.ShiftPressedCond +import ru.dbotthepony.mc.otm.config.AndroidConfig +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.getValue +import ru.dbotthepony.mc.otm.core.util.formatPower +import ru.dbotthepony.mc.otm.data.ComponentCodec +import ru.dbotthepony.mc.otm.data.SingletonCodec +import ru.dbotthepony.mc.otm.data.simpleCodec +import ru.dbotthepony.mc.otm.registry.RegistryDelegate + +object AndroidResearchDescriptions { + private val registrar = DeferredRegister.create(AndroidResearchDescription.registryKey, OverdriveThatMatters.MOD_ID) + + init { + registrar.register("plain") { PlainAndroidResearchDescription } + } + + internal fun register(bus: IEventBus) { + registrar.register(bus) + } + + val ENDER_TELEPORTER: AndroidResearchDescription.Singleton by registrar.register("ender_teleporter") { + AndroidResearchDescription.singleton { + TranslatableComponent("otm.gui.power_cost_per_use", AndroidConfig.EnderTeleporter.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW)) } + } + + val FALL_DAMPENERS: AndroidResearchDescription.Leveled by registrar.register("fall_dampeners") { + AndroidResearchDescription.Leveled { _, _, level -> TranslatableComponent("otm.fall_dampeners.description", TextComponent("%.1f".format((AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL * level).toFloat().coerceAtLeast(0f).coerceAtMost(1f) * 100f)).withStyle(ChatFormatting.YELLOW)) } + } + + val ITEM_MAGNET: AndroidResearchDescription.Singleton by registrar.register("item_magnet") { + AndroidResearchDescription.singleton { TranslatableComponent("otm.gui.power_cost_per_tick", AndroidConfig.Magnet.POWER_DRAW.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW)) } + } + + val JUMP_BOOST: AndroidResearchDescription.Singleton by registrar.register("jump_boost") { + AndroidResearchDescription.singleton { TranslatableComponent("otm.gui.power_cost_per_use", AndroidConfig.JumpBoost.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW)) } + } + + val SHOCKWAVE: AndroidResearchDescription.Singleton by registrar.register("shockwave") { + AndroidResearchDescription.singleton { TranslatableComponent("otm.gui.power_cost_per_use", AndroidConfig.Shockwave.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW)) } + } +} + +/** + * Instance, representing ready to use description populator + */ +interface AndroidResearchDescription { + /** + * Type, representing raw description populator in registry + */ + interface Type { + val codec: Codec + } + + abstract class Singleton : AndroidResearchDescription, Type { + override val codec = SingletonCodec(this) + override val type: Type<*> + get() = this + } + + class Leveled(val callback: (research: AndroidResearch, lines: MutableList, level: Int) -> Unit) : Type { + inner class Instance(val level: Int) : AndroidResearchDescription { + override fun addLines(research: AndroidResearch, lines: MutableList) { + callback.invoke(research, lines, level) + } + + override val type: Type<*> + get() = this@Leveled + } + + override val codec: Codec by lazy { + RecordCodecBuilder.create { + it.group(Codec.INT.fieldOf("level").forGetter(Instance::level)).apply(it, ::Instance) + } + } + } + + fun addLines(research: AndroidResearch, lines: MutableList) + val type: Type<*> + + companion object { + private val delegate = RegistryDelegate>("android_research_description") + + val registry by delegate + val registryKey get() = delegate.key + + val CODEC: Codec by lazy { + registry.codec.dispatch({ it.type }, { it.codec }) + } + + internal fun register(bus: IEventBus) { + bus.addListener(delegate::build) + } + + fun singleton(callback: (research: AndroidResearch) -> Component): Singleton { + return object : Singleton() { + override fun addLines(research: AndroidResearch, lines: MutableList) { + lines.add(callback.invoke(research)) + } + } + } + } +} + +object PlainAndroidResearchDescription : AndroidResearchDescription.Type { + data class Instance(val line: Component) : AndroidResearchDescription { + override fun addLines(research: AndroidResearch, lines: MutableList) { + lines.add(line.copy()) + } + + override val type: PlainAndroidResearchDescription + get() = PlainAndroidResearchDescription + } + + fun make(line: Component) = Instance(line) + + override val codec: Codec by lazy { + Codec + .either(ComponentCodec, simpleCodec(::Instance, Instance::line, ComponentCodec)) + .xmap({ c -> c.map({ Instance(it) }, { it }) }, { c -> Either.left(c.line) }) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchManager.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchManager.kt index bddc41cd8..363d6e12d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchManager.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchManager.kt @@ -6,7 +6,6 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import net.minecraft.client.server.IntegratedServer import net.minecraft.network.FriendlyByteBuf -import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.server.packs.resources.ResourceManager import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener @@ -23,8 +22,6 @@ import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.SERVER_IS_LIVE import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.minecraft -import ru.dbotthepony.mc.otm.core.TranslatableComponent -import ru.dbotthepony.mc.otm.data.SerializedFunctionRegistry import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.RegistryNetworkChannel import ru.dbotthepony.mc.otm.network.enqueueWork @@ -33,47 +30,7 @@ import ru.dbotthepony.mc.otm.onceServer import java.util.LinkedList import java.util.function.Supplier -typealias AndroidResultTransformer = SerializedFunctionRegistry.BoundFunction, Unit> -typealias ComponentSupplier = SerializedFunctionRegistry.BoundFunction - object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable { - /** - * Feel free to register functions inside this thing from anywhere in your code - * (registration and querying is completely thread safe). - * - * Just make sure client and server has the same set of functions defined. - */ - val featureResultTransformers = SerializedFunctionRegistry, Unit>() - - /** - * Feel free to register functions inside this thing from anywhere in your code - * (registration and querying is completely thread safe). - * - * Just make sure client and server has the same set of functions defined. - */ - val descriptionFuncs = SerializedFunctionRegistry() - - fun descriptionFunc(name: ResourceLocation, base: String, vararg argument: Supplier): ComponentSupplier { - return descriptionFuncs.register(name) {-> - return@register TranslatableComponent(base, *argument.map { it.get() }.toTypedArray()) - }.bind() - } - - private var firedRegistrationEvent = false - - /** - * Event-style registration of serializable functions, for those who prefer/need it - * - * Fired *once* on [MinecraftForge.EVENT_BUS] before loading android research - */ - object RegisterFuncsEvent : Event() { - val manager get() = AndroidResearchManager - val featureResults by ::featureResultTransformers - val descriptionFunctions by ::descriptionFuncs - - fun descriptionFunc(name: ResourceLocation, base: String, vararg argument: Supplier): ComponentSupplier = AndroidResearchManager.descriptionFunc(name, base, *argument) - } - const val DIRECTORY = "otm_android_research" private val LOGGER = LogManager.getLogger() @@ -97,23 +54,11 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s var researchMap: Map = mapOf() private set - internal fun fireRegistrationEvent() { - if (!firedRegistrationEvent) { - try { - MinecraftForge.EVENT_BUS.post(RegisterFuncsEvent) - } finally { - firedRegistrationEvent = true - } - } - } - override fun apply( jsonElementMap: Map, manager: ResourceManager, profiler: ProfilerFiller ) { - fireRegistrationEvent() - val builder = ImmutableMap.builder() for ((k, v) in jsonElementMap) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchResult.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchResult.kt new file mode 100644 index 000000000..39e43b686 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchResult.kt @@ -0,0 +1,180 @@ +package ru.dbotthepony.mc.otm.android + +import com.mojang.datafixers.util.Either +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.resources.ResourceLocation +import net.minecraftforge.eventbus.api.IEventBus +import net.minecraftforge.registries.DeferredRegister +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.core.getValue +import ru.dbotthepony.mc.otm.data.SingletonCodec +import ru.dbotthepony.mc.otm.registry.AndroidFeatures +import ru.dbotthepony.mc.otm.registry.MRegistry +import ru.dbotthepony.mc.otm.registry.RegistryDelegate + +object AndroidResearchResults { + private val registrar = DeferredRegister.create(AndroidResearchResult.registryKey, OverdriveThatMatters.MOD_ID) + + init { + registrar.register("feature") { AndroidResearchResult.Feature.Companion } + registrar.register("feature_level") { AndroidResearchResult.FeatureLevel.Companion } + } + + private object NanobotsArmorStrength : AndroidResearchResult.Singleton { + override val codec: Codec = SingletonCodec(this) + override val type: AndroidResearchResult.Type<*> + get() = this + + override fun onResearched(research: AndroidResearch) { + val feature = research.capability.getFeature(AndroidFeatures.NANOBOTS_ARMOR) ?: return + feature.strength++ + } + + override fun onRefunded(research: AndroidResearch) { + val feature = research.capability.getFeature(AndroidFeatures.NANOBOTS_ARMOR) ?: return + feature.strength-- + } + } + + private object NanobotsArmorSpeed : AndroidResearchResult.Singleton { + override val codec: Codec = SingletonCodec(this) + override val type: AndroidResearchResult.Type<*> + get() = this + + override fun onResearched(research: AndroidResearch) { + val feature = research.capability.getFeature(AndroidFeatures.NANOBOTS_ARMOR) ?: return + feature.speed++ + } + + override fun onRefunded(research: AndroidResearch) { + val feature = research.capability.getFeature(AndroidFeatures.NANOBOTS_ARMOR) ?: return + feature.speed-- + } + } + + val NANOBOTS_ARMOR_STRENGTH: AndroidResearchResult.Singleton<*> by registrar.register("nanobots_armor_strength") { NanobotsArmorStrength } + val NANOBOTS_ARMOR_SPEED: AndroidResearchResult.Singleton<*> by registrar.register("nanobots_armor_speed") { NanobotsArmorSpeed } + + internal fun register(bus: IEventBus) { + registrar.register(bus) + } +} + +interface AndroidResearchResult { + interface Type { + val codec: Codec + } + + interface Singleton> : Type, AndroidResearchResult + + /** + * Adds specific android feature [id] to target, does nothing if target already has specified feature + */ + class Feature(val id: ResourceLocation, val optional: Boolean = false) : AndroidResearchResult { + val feature = MRegistry.ANDROID_FEATURES.getValue(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id") + + override val type: Type<*> + get() = Companion + + override fun onResearched(research: AndroidResearch) { + research.capability.addFeature(feature ?: return) + } + + override fun onRefunded(research: AndroidResearch) { + research.capability.removeFeature(feature ?: return) + } + + companion object : Type { + override val codec: Codec by lazy { + Codec + .either(ResourceLocation.CODEC, RecordCodecBuilder.create { // KT-52757 + it.group( + ResourceLocation.CODEC.fieldOf("id").forGetter(Feature::id), + Codec.BOOL.optionalFieldOf("optional", false).forGetter(Feature::optional) + ).apply(it, ::Feature) + }) + .xmap( + { c -> c.map({ Feature(it) }, { it }) }, + { c -> if (c.optional) Either.left(c.id) else Either.right(c) } + ) + } + } + } + + /** + * Increases level of specific android feature [id] by specified amount [levels] + */ + class FeatureLevel(val id: ResourceLocation, val optional: Boolean = false, val levels: Int = 1) : AndroidResearchResult { + val feature = MRegistry.ANDROID_FEATURES.getValue(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id") + + override val type: Type<*> + get() = Companion + + override fun onResearched(research: AndroidResearch) { + val get = research.capability.getFeature(feature ?: return) + + if (get == null) { + LOGGER.warn("Unable to advance level of android feature $id for ${research.ply} because they have no such android feature.") + } else { + get.level += levels + } + } + + override fun onRefunded(research: AndroidResearch) { + val get = research.capability.getFeature(feature ?: return) + + if (get == null) { + LOGGER.warn("Unable to decrease level of android feature $id for ${research.ply} because they have no such android feature.") + } else { + get.level += levels + } + } + + companion object : Type { + override val codec: Codec by lazy { + Codec + .either(ResourceLocation.CODEC, RecordCodecBuilder.create { // KT-52757 + it.group( + ResourceLocation.CODEC.fieldOf("id").forGetter(FeatureLevel::id), + Codec.BOOL.optionalFieldOf("optional", false).forGetter(FeatureLevel::optional), + Codec.INT.optionalFieldOf("levels", 1).forGetter(FeatureLevel::levels), + ).apply(it, ::FeatureLevel) + }) + .xmap( + { c -> c.map({ FeatureLevel(it) }, { it }) }, + { c -> if (c.optional && c.levels == 1) Either.left(c.id) else Either.right(c) } + ) + } + } + } + + val type: Type<*> + + /** + * Called when research is applied + */ + fun onResearched(research: AndroidResearch) {} + + /** + * Called when research is refunded + */ + fun onRefunded(research: AndroidResearch) {} + + companion object { + private val LOGGER = LogManager.getLogger() + private val delegate = RegistryDelegate>("android_research_result") + + val registry by delegate + val registryKey get() = delegate.key + + val CODEC: Codec by lazy { + registry.codec.dispatch({ it.type }, { it.codec }) + } + + internal fun register(bus: IEventBus) { + bus.addListener(delegate::build) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt index bf8003e45..2d150b697 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt @@ -1,13 +1,13 @@ package ru.dbotthepony.mc.otm.android import com.google.common.collect.ImmutableList -import com.google.common.collect.Streams import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.google.gson.JsonSyntaxException import com.google.gson.internal.bind.TypeAdapters +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.network.chat.ComponentContents @@ -28,10 +28,12 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.set -import ru.dbotthepony.mc.otm.core.toImmutableList import ru.dbotthepony.mc.otm.core.collect.stream +import ru.dbotthepony.mc.otm.core.fromJsonStrict +import ru.dbotthepony.mc.otm.core.toJsonStrict +import ru.dbotthepony.mc.otm.core.util.readJson +import ru.dbotthepony.mc.otm.core.util.writeJson import ru.dbotthepony.mc.otm.isClient -import ru.dbotthepony.mc.otm.registry.MRegistry import java.util.LinkedList import java.util.stream.Stream import kotlin.collections.ArrayList @@ -39,7 +41,7 @@ import kotlin.collections.HashSet private fun findPrerequisites( initial: Collection, - add: MutableSet = HashSet(), + add: MutableSet = ObjectOpenHashSet(), top: Boolean = true ): Set { for (value in initial) { @@ -55,7 +57,7 @@ private fun findPrerequisites( private fun findAllPrerequisites( initial: Collection, - add: MutableSet = HashSet(), + add: MutableSet = ObjectOpenHashSet(), ): Set { for (value in initial) { add.add(value) @@ -67,7 +69,7 @@ private fun findAllPrerequisites( private fun findAllChildren( initial: Collection, - add: MutableSet = HashSet(), + add: MutableSet = ObjectOpenHashSet(), ): Set { for (value in initial) { add.add(value) @@ -83,10 +85,9 @@ class AndroidResearchType( blockedBy: Collection, items: Collection>, - features: Collection, + results: Collection, - descriptionLines: Collection, - descriptionSuppliers: Collection = listOf(), + description: Collection, val experienceLevels: Int = 0, private val customName: Component? = null, @@ -145,74 +146,6 @@ class AndroidResearchType( } } - data class FeatureReference( - val id: ResourceLocation, - val level: Int = 0, - val isRigid: Boolean, - val transformersUp: Collection = listOf(), - val transformersDown: Collection = listOf(), - ) { - fun toJson(): JsonObject { - return JsonObject().also { - it["id"] = JsonPrimitive(id.toString()) - it["level"] = JsonPrimitive(level) - it["is_rigid"] = JsonPrimitive(isRigid) - it["functions_up"] = JsonArray().also { - for (transformer in transformersUp) { - it.add(transformer.toJson()) - } - } - - it["functions_down"] = JsonArray().also { - for (transformer in transformersDown) { - it.add(transformer.toJson()) - } - } - } - } - - fun toNetwork(buff: FriendlyByteBuf) { - buff.writeUtf(id.toString()) - buff.writeVarInt(level) - buff.writeBoolean(isRigid) - buff.writeCollection(transformersUp) { a, b -> b.toNetwork(a) } - buff.writeCollection(transformersDown) { a, b -> b.toNetwork(a) } - } - - companion object { - fun fromNetwork(buff: FriendlyByteBuf): FeatureReference { - return FeatureReference( - ResourceLocation(buff.readUtf()), - buff.readVarInt(), - buff.readBoolean(), - buff.readCollection({ LinkedList() }, AndroidResearchManager.featureResultTransformers::fromNetwork).filterNotNull().toImmutableList(), - buff.readCollection({ LinkedList() }, AndroidResearchManager.featureResultTransformers::fromNetwork).filterNotNull().toImmutableList() - ) - } - - fun fromJson(value: JsonElement): FeatureReference { - if (value is JsonPrimitive) { - return FeatureReference(ResourceLocation(value.asString), 0, true) - } else if (value is JsonObject) { - return FeatureReference( - ResourceLocation((value["id"] as? JsonPrimitive ?: throw JsonSyntaxException("Invalid `id` value")).asString), - (value["level"] as JsonPrimitive?)?.asInt ?: 0, - (value["is_rigid"] as JsonPrimitive?)?.asBoolean ?: true, - (value["functions_up"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList()), - (value["functions_down"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList()), - ) - } else { - throw JsonSyntaxException("Unknown element type ${value::class.qualifiedName}") - } - } - } - } - - data class ResolvedFeature( - val feature: AndroidFeatureType<*>, - val level: Int, - ) - val researchTreeDepth: Int by lazy { if (flatPrerequisites.isEmpty()) { return@lazy 0 @@ -248,31 +181,11 @@ class AndroidResearchType( ImmutableList.copyOf(this.blockedBy.mapNotNull { AndroidResearchManager[it.id].also { e -> if (e == null && it.isRigid) throw NoSuchElementException("Unable to find research ${it.id}") } }) } - val features: List = ImmutableList.copyOf(features) - - val resolvedFeatures: List by lazy { - ImmutableList.copyOf(features.mapNotNull { - MRegistry.ANDROID_FEATURES.getValue(it.id) - .let { e -> if (e == null && it.isRigid) - throw NoSuchElementException("Unable to find research ${it.id}") - else if (e != null) - ResolvedFeature(e, it.level) - else - null } }) - } - private val definedItems: List> = ImmutableList.copyOf(items) + val results: ImmutableList = ImmutableList.copyOf(results) val items: Stream> get() = definedItems.stream().filter { !it.first.isActuallyEmpty } - - private val descriptionLines: List = ImmutableList.copyOf(descriptionLines.map { it.copy() }) - - private val descriptionSuppliers: List = ImmutableList.copyOf(descriptionSuppliers) - - /** - * Stream containing copies of original [Component]s in list - */ - val description: Stream get() = Streams.concat(descriptionLines.stream().map { it.copy() }, descriptionSuppliers.stream().map { it.apply(Unit) }) + val description: ImmutableList = ImmutableList.copyOf(description) /** * Flat list of research preceding this research. @@ -469,14 +382,11 @@ class AndroidResearchType( fun toJson(): JsonElement { return JsonObject().also { - // it["id"] = JsonPrimitive(id.toString()) - it["prerequisites"] = JsonArray().also { for (value in prerequisites) it.add(value.toJson()) } it["blocked_by"] = JsonArray().also { for (value in blockedBy) it.add(value.toJson()) } it["required_items"] = JsonArray().also { for (item in definedItems) it.add(JsonObject().also { it["count"] = JsonPrimitive(item.second); it["ingredient"] = item.first.toJson() }) } - it["feature_result"] = JsonArray().also { for (feature in features) it.add(feature.toJson()) } - it["description"] = JsonArray().also { for (line in descriptionLines) it.add(Component.Serializer.toJsonTree(line)) } - it["description_funcs"] = JsonArray().also { for (line in descriptionSuppliers) it.add(line.toJson()) } + it["results"] = JsonArray().also { for (result in results) it.add(AndroidResearchResult.CODEC.toJsonStrict(result)) } + it["description"] = JsonArray().also { for (line in description) it.add(AndroidResearchDescription.CODEC.toJsonStrict(line)) } it["experience"] = JsonPrimitive(experienceLevels) if (skinIcon != null) { @@ -498,7 +408,6 @@ class AndroidResearchType( } fun validate() { - resolvedFeatures resolvedBlockedBy resolvedPrerequisites } @@ -508,9 +417,8 @@ class AndroidResearchType( buff.writeCollection(prerequisites) { a, b -> b.toNetwork(a) } buff.writeCollection(blockedBy) { a, b -> b.toNetwork(a) } buff.writeCollection(definedItems) { a, b -> b.first.toNetwork(a); a.writeVarInt(b.second) } - buff.writeCollection(features) { a, b -> b.toNetwork(a) } - buff.writeCollection(descriptionLines) { a, b -> a.writeComponent(b) } - buff.writeCollection(descriptionSuppliers) { a, b -> b.toNetwork(a) } + buff.writeCollection(results) { a, b -> a.writeJson(AndroidResearchResult.CODEC.toJsonStrict(b)) } + buff.writeCollection(description) { a, b -> a.writeJson(AndroidResearchDescription.CODEC.toJsonStrict(b)) } buff.writeVarInt(experienceLevels) buff.writeBoolean(customName != null) @@ -532,9 +440,8 @@ class AndroidResearchType( val prerequisites = buff.readCollection({ LinkedList() }, Reference::fromNetwork) val blockedBy = buff.readCollection({ LinkedList() }, Reference::fromNetwork) val items = buff.readCollection({ LinkedList() }, { Ingredient.fromNetwork(it) to it.readVarInt() }) - val features = buff.readCollection({ LinkedList() }, FeatureReference::fromNetwork) - val descriptionLines = buff.readCollection({ LinkedList() }, FriendlyByteBuf::readComponent) - val descriptionSuppliers = buff.readCollection({ LinkedList() }, { AndroidResearchManager.descriptionFuncs.fromNetwork(it) }) + val results = buff.readCollection({ LinkedList() }, { AndroidResearchResult.CODEC.fromJsonStrict(it.readJson()) }) + val description = buff.readCollection({ LinkedList() }, { AndroidResearchDescription.CODEC.fromJsonStrict(it.readJson()) }) val experienceLevels = buff.readVarInt() val customName = if (buff.readBoolean()) { @@ -566,9 +473,8 @@ class AndroidResearchType( prerequisites = prerequisites, blockedBy = blockedBy, items = items, - features = features, - descriptionLines = descriptionLines, - descriptionSuppliers = descriptionSuppliers.filterNotNull(), + results = results, + description = description, experienceLevels = experienceLevels, customName = customName, iconText = iconTextValue, @@ -587,7 +493,6 @@ class AndroidResearchType( val items = value["required_items"] as JsonArray? ?: JsonArray() val features = value["feature_result"] as JsonArray? ?: JsonArray() val description = value["description"] as JsonArray? ?: JsonArray() - val description_funcs = value["description_funcs"] as JsonArray? ?: JsonArray() val experience = value["experience"]?.asInt ?: 0 val customName = value["custom_name"]?.let(Component.Serializer::fromJson) val iconText = value["icon_text"]?.let(Component.Serializer::fromJson) @@ -598,15 +503,12 @@ class AndroidResearchType( id = id, prerequisites = prerequisites.stream().map { Reference.fromJson(it) }.toList(), blockedBy = blocked_by.stream().map { Reference.fromJson(it) }.toList(), - features = features.stream().map { FeatureReference.fromJson(it) }.toList(), + results = features.stream().map { AndroidResearchResult.CODEC.fromJsonStrict(it) }.toList(), items = items.stream() .map { it as? JsonObject ?: throw JsonSyntaxException("One of items is not an JsonObject") } .map { Ingredient.fromJson(it["ingredient"] ?: throw JsonSyntaxException("Missing ingredient key")) to (it["count"]?.asInt ?: throw JsonSyntaxException("Missing count key")) } .toList(), - descriptionLines = description.stream().map { Component.Serializer.fromJson(it) }.toList() as List, - descriptionSuppliers = description_funcs.stream() - .map { AndroidResearchManager.descriptionFuncs.fromJson(it) ?: throw NullPointerException("$id is missing description supplier function or it is invalid! JSON: $it") } - .toList() as List, + description = description.stream().map { AndroidResearchDescription.CODEC.fromJsonStrict(it) }.toList(), experienceLevels = experience, customName = customName, iconText = iconText, @@ -621,18 +523,18 @@ class AndroidResearchType( val id: ResourceLocation, var experience: Int = 0, var customName: Component? = null, - var description: MutableList? = null, - var descriptionSuppliers: MutableList? = null, + description: MutableList? = null, var itemIcon: Item? = null, var skinIcon: AbstractMatterySprite? = null, var iconText: Component? = null, ) { + val description = ArrayList(description ?: listOf()) + val results = ArrayList() + private val items = ArrayList>() private val prerequisites = ArrayList() private val blockers = ArrayList() - private val features = ArrayList() - fun withIconText(icon: Component? = null): Builder { this.iconText = icon return this @@ -661,19 +563,20 @@ class AndroidResearchType( return this } - fun withDescription(): Builder { - this.description = mutableListOf(TranslatableComponent("android_research.${id.namespace}.${id.path}.description")) + fun clearDescription(): Builder { + this.description.clear() return this } - fun withDescription(range: IntRange): Builder { - val result = ArrayList() + fun withDescription(): Builder { + return withDescription(TranslatableComponent("android_research.${id.namespace}.${id.path}.description")) + } + fun withDescription(range: IntRange): Builder { for (i in range) { - result.add(TranslatableComponent("android_research.${id.namespace}.${id.path}.description$i")) + withDescription(TranslatableComponent("android_research.${id.namespace}.${id.path}.description$i")) } - this.description = result return this } @@ -683,73 +586,21 @@ class AndroidResearchType( } fun withDescription(vararg description: Component): Builder { - this.description = description.toMutableList() + for (component in description) + withDescription(PlainAndroidResearchDescription.Instance(component)) + return this } fun withDescription(description: Collection): Builder { - this.description = ArrayList(description.size).also { it.addAll(description) } + for (component in description) + withDescription(PlainAndroidResearchDescription.Instance(component)) + return this } - fun appendDescription(range: IntRange): Builder { - val result = this.description ?: ArrayList() - - for (i in range) { - result.add(TranslatableComponent("android_research.${id.namespace}.${id.path}.description$i")) - } - - this.description = result - return this - } - - fun appendDescription(description: Component): Builder { - this.description = (this.description ?: mutableListOf()).also { it.add(description) } - return this - } - - fun appendDescription(vararg description: Component): Builder { - this.description = (this.description ?: mutableListOf()).also { it.addAll(description) } - return this - } - - fun appendDescription(description: Collection): Builder { - this.description = (this.description ?: mutableListOf()).also { it.addAll(description) } - return this - } - - fun withDescription(vararg description: ComponentSupplier): Builder { - this.descriptionSuppliers = description.toMutableList() - return this - } - - fun withDescriptionSupplier(description: Collection): Builder { - this.descriptionSuppliers = ArrayList(description.size).also { it.addAll(description) } - return this - } - - fun appendDescription(description: ComponentSupplier): Builder { - this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.add(description) } - return this - } - - fun appendDescriptionSupplier(description: ComponentSupplier): Builder { - this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.add(description) } - return this - } - - fun appendDescription(vararg description: ComponentSupplier): Builder { - this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) } - return this - } - - fun appendDescriptionSupplier(vararg description: ComponentSupplier): Builder { - this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) } - return this - } - - fun appendDescriptionSupplier(description: Collection): Builder { - this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) } + fun withDescription(vararg description: AndroidResearchDescription): Builder { + this.description.addAll(description) return this } @@ -776,43 +627,25 @@ class AndroidResearchType( fun addPrerequisite(type: AndroidResearchType, rigid: Boolean = true) = addPrerequisite(type.id, rigid) fun addBlocker(type: AndroidResearchType, rigid: Boolean = true) = addBlocker(type.id, rigid) - @JvmOverloads - fun addFeatureResult( - id: ResourceLocation, - level: Int = 0, - rigid: Boolean = false, - transformersUp: Collection = listOf(), - transformersDown: Collection = listOf(), - ): Builder { - features.add(FeatureReference(id, level, rigid, transformersUp, transformersDown)) + fun addResult(result: AndroidResearchResult): Builder { + results.add(result) return this } - @JvmOverloads - fun addFeatureResult( - feature: AndroidFeatureType<*>, - level: Int = 0, - rigid: Boolean = true, - transformersUp: Collection = listOf(), - transformersDown: Collection = listOf(), - ): Builder { - features.add(FeatureReference(feature.registryName ?: throw NullPointerException("Feature $feature does not have registry name"), level, rigid, transformersUp, transformersDown)) - return this + fun addFeatureResult(id: ResourceLocation, optional: Boolean = false): Builder { + return addResult(AndroidResearchResult.Feature(id, optional)) } - fun addFeatureResult( - id: ResourceLocation, - rigid: Boolean = false, - transformersUp: Collection = listOf(), - transformersDown: Collection = listOf(), - ): Builder { - features.add(FeatureReference(id, 0, rigid, transformersUp, transformersDown)) - return this + fun addFeatureResult(feature: AndroidFeatureType<*>, optional: Boolean = false): Builder { + return addFeatureResult(feature.registryName!!, optional) } - fun addFeatureResult(ref: FeatureReference): Builder { - features.add(ref) - return this + fun addFeatureLevel(id: ResourceLocation, optional: Boolean = false, levels: Int = 1): Builder { + return addResult(AndroidResearchResult.FeatureLevel(id, optional, levels)) + } + + fun addFeatureLevel(feature: AndroidFeatureType<*>, optional: Boolean = false, levels: Int = 1): Builder { + return addFeatureLevel(feature.registryName!!, optional, levels) } fun addItem(cost: ItemStack): Builder { @@ -844,9 +677,8 @@ class AndroidResearchType( prerequisites = prerequisites, blockedBy = blockers, items = items, - features = features, - descriptionLines = description ?: listOf(), - descriptionSuppliers = descriptionSuppliers ?: listOf(), + results = results, + description = description, experienceLevels = experience, customName = customName, skinIcon = skinIcon?.toJson(), diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/EnderTeleporterFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/EnderTeleporterFeature.kt index b8a30b8f5..5e5931bbb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/EnderTeleporterFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/EnderTeleporterFeature.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.android.feature import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.ChatFormatting import net.minecraft.client.Camera import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.renderer.LevelRenderer @@ -28,25 +27,22 @@ import net.minecraftforge.event.entity.living.LivingDeathEvent import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.android.AndroidActiveFeature -import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.matteryPlayer -import ru.dbotthepony.mc.otm.client.ShiftPressedCond import ru.dbotthepony.mc.otm.client.render.DynamicBufferSource import ru.dbotthepony.mc.otm.client.render.ResearchIcons -import ru.dbotthepony.mc.otm.client.render.sprite import ru.dbotthepony.mc.otm.client.render.linesIgnoreZRenderType +import ru.dbotthepony.mc.otm.client.render.sprite import ru.dbotthepony.mc.otm.config.AndroidConfig +import ru.dbotthepony.mc.otm.core.genericPositions +import ru.dbotthepony.mc.otm.core.holder +import ru.dbotthepony.mc.otm.core.isFall import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.asVector import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 -import ru.dbotthepony.mc.otm.core.util.formatPower -import ru.dbotthepony.mc.otm.core.genericPositions -import ru.dbotthepony.mc.otm.core.holder -import ru.dbotthepony.mc.otm.core.isFall import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.rotateXDegrees import ru.dbotthepony.mc.otm.core.math.rotateYDegrees @@ -54,7 +50,6 @@ import ru.dbotthepony.mc.otm.core.math.shortestDistanceBetween import ru.dbotthepony.mc.otm.core.math.times import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.registry.AndroidFeatures -import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.triggers.EnderTeleporterFallDeathTrigger import java.util.* import kotlin.math.sin @@ -399,12 +394,6 @@ class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiv val SPRITE = ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/item/black_hole.png").sprite(0f, 0f, 16f, 16f, 16f, 16f) - val POWER_COST_DESCRIPTION = - AndroidResearchManager.descriptionFunc( - ResourceLocation(OverdriveThatMatters.MOD_ID, MNames.ENDER_TELEPORTER), - "otm.gui.power_cost_per_use", - { AndroidConfig.EnderTeleporter.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW) }) - fun onEntityDeath(event: LivingDeathEvent) { val android = event.entity.matteryPlayer ?: return val server = NULLABLE_MINECRAFT_SERVER ?: return diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/FallDampenersFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/FallDampenersFeature.kt index 5cc0c71e7..dbf0004d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/FallDampenersFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/FallDampenersFeature.kt @@ -35,10 +35,4 @@ class FallDampenersFeature(capability: MatteryPlayerCapability) : AndroidFeature } } } - - companion object { - val DESCRIPTION = AndroidResearchManager.descriptionFuncs.register(ResourceLocation(OverdriveThatMatters.MOD_ID, MNames.FALL_DAMPENERS)) { level: Int -> - TranslatableComponent("otm.fall_dampeners.description", TextComponent("%.1f".format((AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL * level).toFloat().coerceAtLeast(0f).coerceAtMost(1f) * 100f)).withStyle(ChatFormatting.YELLOW)) - } - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ItemMagnetFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ItemMagnetFeature.kt index 4c7160245..46e9c4477 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ItemMagnetFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ItemMagnetFeature.kt @@ -132,12 +132,4 @@ class ItemMagnetFeature(capability: MatteryPlayerCapability) : AndroidSwitchable override fun renderIcon(graphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float) { ResearchIcons.ICON_ITEM_MAGNET.render(graphics, x, y, width, height) } - - companion object { - val POWER_COST_DESCRIPTION = - AndroidResearchManager.descriptionFunc(ResourceLocation( - OverdriveThatMatters.MOD_ID, MNames.ITEM_MAGNET), - "otm.gui.power_cost_per_tick", - { AndroidConfig.Magnet.POWER_DRAW.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW) }) - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt index 555bd86e6..4d3044802 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt @@ -125,13 +125,4 @@ class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF RenderSystem.setShaderColor(1f, 1f, 1f, 1f) } } - - - companion object { - val POWER_COST_DESCRIPTION = - AndroidResearchManager.descriptionFunc( - ResourceLocation(OverdriveThatMatters.MOD_ID, MNames.JUMP_BOOST), - "otm.gui.power_cost_per_use", - { AndroidConfig.JumpBoost.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW) }) - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt index b9a17f54a..8dc1f81db 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt @@ -106,33 +106,5 @@ class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(An 0.45f, 0.6f, ) - - val STRENGTH_TRANSFORMER_UP = AndroidResearchManager.featureResultTransformers.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_strength_up")) - { level: Int -> - if (second is NanobotsArmorFeature && (second as NanobotsArmorFeature).strength == level - 1) { - (second as NanobotsArmorFeature).strength = level - } - } - - val STRENGTH_TRANSFORMER_DOWN = AndroidResearchManager.featureResultTransformers.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_strength_down")) - { level: Int -> - if (second is NanobotsArmorFeature && (second as NanobotsArmorFeature).strength == level) { - (second as NanobotsArmorFeature).strength = level - 1 - } - } - - val SPEED_TRANSFORMER_UP = AndroidResearchManager.featureResultTransformers.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_speed_up")) - { level: Int -> - if (second is NanobotsArmorFeature && (second as NanobotsArmorFeature).speed == level - 1) { - (second as NanobotsArmorFeature).speed = level - } - } - - val SPEED_TRANSFORMER_DOWN = AndroidResearchManager.featureResultTransformers.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_speed_down")) - { level: Int -> - if (second is NanobotsArmorFeature && (second as NanobotsArmorFeature).speed == level) { - (second as NanobotsArmorFeature).speed = level - 1 - } - } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt index cc415b297..ce0fbb20c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt @@ -251,12 +251,4 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF RenderSystem.setShaderColor(1f, 1f, 1f, 1f) } } - - companion object { - val POWER_COST_DESCRIPTION = - AndroidResearchManager.descriptionFunc( - ResourceLocation(OverdriveThatMatters.MOD_ID, MNames.SHOCKWAVE), - "otm.gui.power_cost_per_use", - { AndroidConfig.Shockwave.ENERGY_COST.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.YELLOW) }) - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codecs.kt new file mode 100644 index 000000000..ef688c49c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codecs.kt @@ -0,0 +1,33 @@ +package ru.dbotthepony.mc.otm.data + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import kotlin.reflect.KProperty1 + + +fun simpleCodec(factory: (T1) -> V, field1: KProperty1, codec1: Codec): Codec { + return RecordCodecBuilder.create { + it.group( + codec1.fieldOf(field1.name).forGetter(field1::get) + ).apply(it, factory) + } +} + +fun simpleCodec(factory: (T1, T2) -> V, field1: KProperty1, codec1: Codec, field2: KProperty1, codec2: Codec): Codec { + return RecordCodecBuilder.create { + it.group( + codec1.fieldOf(field1.name).forGetter(field1::get), + codec2.fieldOf(field2.name).forGetter(field2::get), + ).apply(it, factory) + } +} + +fun simpleCodec(factory: (T1, T2, T3) -> V, field1: KProperty1, codec1: Codec, field2: KProperty1, codec2: Codec, field3: KProperty1, codec3: Codec): Codec { + return RecordCodecBuilder.create { + it.group( + codec1.fieldOf(field1.name).forGetter(field1::get), + codec2.fieldOf(field2.name).forGetter(field2::get), + codec3.fieldOf(field3.name).forGetter(field3::get), + ).apply(it, factory) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/ComponentCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ComponentCodec.kt new file mode 100644 index 000000000..9efaeb74f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ComponentCodec.kt @@ -0,0 +1,25 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonSyntaxException +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.JsonOps +import net.minecraft.network.chat.Component + +object ComponentCodec : Codec { + override fun encode(input: Component, ops: DynamicOps, prefix: T): DataResult { + return DataResult.success(JsonOps.INSTANCE.convertTo(ops, Component.Serializer.toJsonTree(input))) + } + + override fun decode(ops: DynamicOps, input: T): DataResult> { + val value = ops.convertTo(JsonOps.INSTANCE, input) + + try { + return DataResult.success(Pair(Component.Serializer.fromJson(value), ops.empty())) + } catch (err: JsonSyntaxException) { + return DataResult.error { err.message } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/SerializedFunctionRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/SerializedFunctionRegistry.kt deleted file mode 100644 index 0a916f07b..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/SerializedFunctionRegistry.kt +++ /dev/null @@ -1,225 +0,0 @@ -package ru.dbotthepony.mc.otm.data - -import com.google.gson.Gson -import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer -import com.google.gson.JsonSyntaxException -import com.google.gson.TypeAdapter -import com.google.gson.internal.bind.TypeAdapters -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import io.netty.buffer.ByteBufInputStream -import io.netty.buffer.ByteBufOutputStream -import it.unimi.dsi.fastutil.io.FastByteArrayInputStream -import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream -import net.minecraft.nbt.NbtAccounter -import net.minecraft.network.FriendlyByteBuf -import net.minecraft.resources.ResourceLocation -import ru.dbotthepony.mc.otm.core.util.readType -import ru.dbotthepony.mc.otm.core.util.readVarIntLE -import ru.dbotthepony.mc.otm.core.nbt.set -import ru.dbotthepony.mc.otm.core.set -import ru.dbotthepony.mc.otm.core.util.writeType -import ru.dbotthepony.mc.otm.core.util.writeVarIntLE -import java.io.DataInputStream -import java.io.DataOutputStream -import java.lang.reflect.Type -import java.util.Base64 -import java.util.Collections -import java.util.LinkedList - -class SerializedFunctionRegistry(val gson: Gson = Gson()) : JsonSerializer>, JsonDeserializer>, TypeAdapter>() { - fun interface AnonymousFunction { - fun invoke(receiver: R, arguments: List): T - } - - data class BoundFunction( - val function: Function, - val arguments: List - ) : java.util.function.Function { - fun toJson(): JsonElement { - return JsonObject().also { - it["function"] = function.toJson() - val stream = FastByteArrayOutputStream() - val dataStream = DataOutputStream(stream) - - stream.writeVarIntLE(arguments.size) - - for (argument in arguments) { - dataStream.writeType(argument) - } - - it["arguments"] = JsonPrimitive(Base64.getEncoder().encode(stream.array.copyOfRange(0, stream.length)).toString(Charsets.UTF_8)) - } - } - - fun toNetwork(buff: FriendlyByteBuf) { - function.toNetwork(buff) - - val stream = DataOutputStream(ByteBufOutputStream(buff)) - stream.writeVarIntLE(arguments.size) - for (argument in arguments) { - stream.writeType(argument) - } - } - - override fun apply(t: R): T { - return function.body.invoke(t, arguments) - } - } - - data class Function( - val id: ResourceLocation, - val body: AnonymousFunction, - val registry: SerializedFunctionRegistry - ) { - fun bind(vararg arguments: Any?): BoundFunction { - validate(arguments.iterator().withIndex()) - return BoundFunction(this, Collections.unmodifiableList(LinkedList().also { it.addAll(arguments) })) - } - - fun bind(arguments: List): BoundFunction { - validate(arguments.iterator().withIndex()) - return BoundFunction(this, Collections.unmodifiableList(LinkedList().also { it.addAll(arguments) })) - } - - fun toJson(): JsonElement { - return JsonPrimitive(id.toString()) - } - - fun toNetwork(buff: FriendlyByteBuf) { - buff.writeUtf(id.toString()) - } - - companion object { - private fun validate(iterator: Iterator>) { - try { - val stream = DataOutputStream(FastByteArrayOutputStream()) - - for ((i, argument) in iterator) { - try { - stream.writeType(argument) - } catch(err: Exception) { - throw IllegalArgumentException("Argument at $i can not be serialized", err) - } - } - } catch(err: Exception) { - throw IllegalArgumentException("Argument list validation failed", err) - } - } - } - } - - private val map = HashMap>() - - fun register(id: ResourceLocation, function: AnonymousFunction): Function { - synchronized(map) { - return map.computeIfAbsent(id) { Function(id, function, this) } - } - } - - fun register(id: ResourceLocation, function: R.() -> T): Function { - return register(id, AnonymousFunction { r, args -> - check(args.isEmpty()) { "Invalid amount of arguments. No arguments are required" } - function.invoke(r) - }) - } - - inline fun register(id: ResourceLocation, noinline function: R.(A) -> T): Function { - return register(id, AnonymousFunction { r, args -> - check(args.size == 1) { "Invalid amount of arguments. 1 is required" } - function.invoke( - r, - args[0] as? A ?: throw ClassCastException("Argument at 0 is supposed to be ${A::class.qualifiedName}, ${args[0]?.let { it::class.qualifiedName }} given") - ) - }) - } - - inline fun register(id: ResourceLocation, noinline function: R.(A, B) -> T): Function { - return register(id, AnonymousFunction { r, args -> - check(args.size == 2) { "Invalid amount of arguments. 2 is required" } - - function.invoke( - r, - args[0] as? A ?: throw ClassCastException("Argument at 0 is supposed to be ${A::class.qualifiedName}, ${args[0]?.let { it::class.qualifiedName }} given"), - args[1] as? B ?: throw ClassCastException("Argument at 1 is supposed to be ${B::class.qualifiedName}, ${args[1]?.let { it::class.qualifiedName }} given"), - ) - }) - } - - inline fun register(id: ResourceLocation, noinline function: R.(A, B, C) -> T): Function { - return register(id, AnonymousFunction { r, args -> - check(args.size == 3) { "Invalid amount of arguments. 3 is required" } - - function.invoke( - r, - args[0] as? A ?: throw ClassCastException("Argument at 0 is supposed to be ${A::class.qualifiedName}, ${args[0]?.let { it::class.qualifiedName }} given"), - args[1] as? B ?: throw ClassCastException("Argument at 1 is supposed to be ${B::class.qualifiedName}, ${args[1]?.let { it::class.qualifiedName }} given"), - args[2] as? C ?: throw ClassCastException("Argument at 2 is supposed to be ${B::class.qualifiedName}, ${args[2]?.let { it::class.qualifiedName }} given"), - ) - }) - } - - fun get(id: ResourceLocation): Function? { - synchronized(map) { - return map[id] - } - } - - fun fromNetwork(buff: FriendlyByteBuf): BoundFunction? { - val id = ResourceLocation(buff.readUtf()) - val stream = DataInputStream(ByteBufInputStream(buff)) - - val arguments = LinkedList() - val sizeLimit = NbtAccounter(1L shl 18 /* 256 KiB */) - - for (i in 0 until stream.readVarIntLE(sizeLimit)) { - arguments.add(stream.readType(sizeLimit)) - } - - return map[id]?.bind(arguments) - } - - fun fromJson(value: JsonElement): BoundFunction? { - if (value !is JsonObject) { - return null - } - - val id = value["function"]?.asString ?: return null - val argumentString = value["arguments"]?.asString ?: return null - val stream = DataInputStream(FastByteArrayInputStream(Base64.getDecoder().decode(argumentString))) - val arguments = LinkedList() - val sizeLimit = NbtAccounter(1L shl 18 /* 256 KiB */) - - for (i in 0 until stream.readVarIntLE(sizeLimit)) { - arguments.add(stream.readType(sizeLimit)) - } - - return map[ResourceLocation(id)]?.bind(arguments) - } - - override fun serialize(src: BoundFunction, typeOfSrc: Type, context: JsonSerializationContext): JsonElement { - return src.toJson() - } - - override fun deserialize( - json: JsonElement, - typeOfT: Type, - context: JsonDeserializationContext - ): BoundFunction { - return fromJson(json) ?: throw JsonSyntaxException("Function is invalid") - } - - override fun write(out: JsonWriter, value: BoundFunction) { - TypeAdapters.JSON_ELEMENT.write(out, value.toJson()) - } - - override fun read(`in`: JsonReader): BoundFunction { - return fromJson(TypeAdapters.JSON_ELEMENT.read(`in`)) ?: throw JsonSyntaxException("Function is invalid") - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/SingletonCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/SingletonCodec.kt new file mode 100644 index 000000000..eb2ade209 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/SingletonCodec.kt @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.data + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps + +class SingletonCodec(val value: V) : Codec { + override fun encode(input: V, ops: DynamicOps, prefix: T): DataResult { + return DataResult.success(ops.empty()) + } + + override fun decode(ops: DynamicOps, input: T? /* Так то, оно должно быть null */): DataResult> { + return DataResult.success(Pair(value, ops.empty())) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt index d729b079d..c1ee11123 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt @@ -10,20 +10,20 @@ import ru.dbotthepony.mc.otm.android.feature.* object AndroidFeatures { private val registry = DeferredRegister.create(MRegistry.ANDROID_FEATURES_KEY, OverdriveThatMatters.MOD_ID) - val AIR_BAGS: AndroidFeatureType<*> by registry.register(MNames.AIR_BAGS) { AndroidFeatureType(::DummyAndroidFeature) } - val STEP_ASSIST: AndroidFeatureType<*> by registry.register(MNames.STEP_ASSIST) { AndroidFeatureType(::StepAssistFeature) } - val LIMB_OVERCLOCKING: AndroidFeatureType<*> by registry.register(MNames.LIMB_OVERCLOCKING) { AndroidFeatureType(::LimbOverclockingFeature) } - val ATTACK_BOOST: AndroidFeatureType<*> by registry.register(MNames.ATTACK_BOOST) { AndroidFeatureType(::AttackBoostFeature) } - val NANOBOTS_REGENERATION: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::NanobotsRegenerationFeature) } - val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmorFeature) } - val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReachFeature) } - val NIGHT_VISION: AndroidFeatureType<*> by registry.register(MNames.NIGHT_VISION) { AndroidFeatureType(::NightVisionFeature) } - val SHOCKWAVE: AndroidFeatureType<*> by registry.register(MNames.SHOCKWAVE) { AndroidFeatureType(::ShockwaveFeature) } - val ITEM_MAGNET: AndroidFeatureType<*> by registry.register(MNames.ITEM_MAGNET) { AndroidFeatureType(::ItemMagnetFeature) } - val FALL_DAMPENERS: AndroidFeatureType<*> by registry.register(MNames.FALL_DAMPENERS) { AndroidFeatureType(::FallDampenersFeature) } - val PHANTOM_ATTRACTOR: AndroidFeatureType<*> by registry.register(MNames.PHANTOM_ATTRACTOR) { AndroidFeatureType(::PhantomAttractorFeature) } - val JUMP_BOOST: AndroidFeatureType<*> by registry.register(MNames.JUMP_BOOST) { AndroidFeatureType(::JumpBoostFeature) } - val ENDER_TELEPORTER: AndroidFeatureType<*> by registry.register(MNames.ENDER_TELEPORTER) { AndroidFeatureType(::EnderTeleporterFeature) } + val AIR_BAGS: AndroidFeatureType by registry.register(MNames.AIR_BAGS) { AndroidFeatureType(::DummyAndroidFeature) } + val STEP_ASSIST: AndroidFeatureType by registry.register(MNames.STEP_ASSIST) { AndroidFeatureType(::StepAssistFeature) } + val LIMB_OVERCLOCKING: AndroidFeatureType by registry.register(MNames.LIMB_OVERCLOCKING) { AndroidFeatureType(::LimbOverclockingFeature) } + val ATTACK_BOOST: AndroidFeatureType by registry.register(MNames.ATTACK_BOOST) { AndroidFeatureType(::AttackBoostFeature) } + val NANOBOTS_REGENERATION: AndroidFeatureType by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::NanobotsRegenerationFeature) } + val NANOBOTS_ARMOR: AndroidFeatureType by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmorFeature) } + val EXTENDED_REACH: AndroidFeatureType by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReachFeature) } + val NIGHT_VISION: AndroidFeatureType by registry.register(MNames.NIGHT_VISION) { AndroidFeatureType(::NightVisionFeature) } + val SHOCKWAVE: AndroidFeatureType by registry.register(MNames.SHOCKWAVE) { AndroidFeatureType(::ShockwaveFeature) } + val ITEM_MAGNET: AndroidFeatureType by registry.register(MNames.ITEM_MAGNET) { AndroidFeatureType(::ItemMagnetFeature) } + val FALL_DAMPENERS: AndroidFeatureType by registry.register(MNames.FALL_DAMPENERS) { AndroidFeatureType(::FallDampenersFeature) } + val PHANTOM_ATTRACTOR: AndroidFeatureType by registry.register(MNames.PHANTOM_ATTRACTOR) { AndroidFeatureType(::PhantomAttractorFeature) } + val JUMP_BOOST: AndroidFeatureType by registry.register(MNames.JUMP_BOOST) { AndroidFeatureType(::JumpBoostFeature) } + val ENDER_TELEPORTER: AndroidFeatureType by registry.register(MNames.ENDER_TELEPORTER) { AndroidFeatureType(::EnderTeleporterFeature) } internal fun register(bus: IEventBus) { registry.register(bus) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt index 1acaf7a3b..de5c7a32d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -16,13 +16,13 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent import net.minecraftforge.registries.NewRegistryEvent import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.android.AndroidResearchResult +import ru.dbotthepony.mc.otm.android.AndroidResearchResults import ru.dbotthepony.mc.otm.android.AndroidFeatureType +import ru.dbotthepony.mc.otm.android.AndroidResearchDescription +import ru.dbotthepony.mc.otm.android.AndroidResearchDescriptions import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature -import ru.dbotthepony.mc.otm.android.feature.FallDampenersFeature -import ru.dbotthepony.mc.otm.android.feature.ItemMagnetFeature -import ru.dbotthepony.mc.otm.android.feature.JumpBoostFeature import ru.dbotthepony.mc.otm.android.feature.NanobotsArmorFeature -import ru.dbotthepony.mc.otm.android.feature.ShockwaveFeature import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.decorative.TritaniumPressurePlate import ru.dbotthepony.mc.otm.capability.matteryEnergy @@ -208,6 +208,10 @@ object MRegistry { MCreativeTabs.initialize(bus) DecimalProvider.register(bus) + AndroidResearchDescription.register(bus) + AndroidResearchDescriptions.register(bus) + AndroidResearchResult.register(bus) + AndroidResearchResults.register(bus) MBlocks.register(bus) MBlockEntities.register(bus) @@ -224,10 +228,6 @@ object MRegistry { // call static constructors NanobotsArmorFeature.Companion - ShockwaveFeature.Companion - ItemMagnetFeature.Companion - FallDampenersFeature.Companion - JumpBoostFeature.Companion EnderTeleporterFeature.Companion }