From 589d3a5499ac2940e9ec60d9e93352cc17bbfbdc Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 19 Aug 2022 18:08:38 +0700 Subject: [PATCH] Normalized lists of research --- .../mc/otm/android/AndroidResearch.kt | 8 +- .../mc/otm/android/AndroidResearchBuilder.kt | 10 +- .../mc/otm/android/AndroidResearchType.kt | 157 ++++++++++++++++-- .../otm/client/screen/AndroidStationScreen.kt | 7 +- 4 files changed, 155 insertions(+), 27 deletions(-) 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 eaa35794b..9547f923b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -141,8 +141,8 @@ abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability: isResearched = nbt.getBoolean("researched") } - inline val prerequisites get() = type.prerequisites - inline val unlocks get() = type.unlocks - inline val blockedBy get() = type.blockedBy - inline val blocking get() = type.blocking + inline val prerequisites get() = type.definedPrerequisites + inline val unlocks get() = type.flatUnlocks + inline val blockedBy get() = type.definedBlockedBy + inline val blocking get() = type.flatBlocking } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt index c6ffa3ec7..f4b6d076d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt @@ -335,7 +335,7 @@ class AndroidResearchBuilder( )) } - for (value in this.type.prerequisites) { + for (value in this.type.flatPrerequisites) { val instance = capability.getResearch(value) builder.add(TranslatableComponent("android_research.status.requires", instance.screenTooltipHeader).withStyle( @@ -346,11 +346,11 @@ class AndroidResearchBuilder( )) } - for (value in this.type.blockedBy) { + for (value in this.type.definedBlockedBy) { builder.add(TranslatableComponent("android_research.status.blocked_by", capability.getResearch(value).screenTooltipHeader).withStyle(ChatFormatting.DARK_RED)) } - for (value in this.type.blocking) { + for (value in this.type.flatBlocking) { builder.add(TranslatableComponent("android_research.status.blocks", capability.getResearch(value).screenTooltipHeader).withStyle(ChatFormatting.DARK_RED)) } @@ -367,7 +367,7 @@ class AndroidResearchBuilder( override val displayDescription: List get() = description ?: super.displayDescription - override val prerequisites: List> by lazy { + override val definedPrerequisites: List> by lazy { val builder = ImmutableList.builder>() for ((value, rigid) in prerequisites) { @@ -383,7 +383,7 @@ class AndroidResearchBuilder( builder.build() } - override val blockedBy: List> by lazy { + override val definedBlockedBy: List> by lazy { val builder = ImmutableList.builder>() for ((value, rigid) in blockers) { 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 a21b721e6..8ef3ad6c6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchType.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.android import com.google.common.collect.ImmutableList +import it.unimi.dsi.fastutil.objects.ObjectArraySet import net.minecraft.network.chat.Component import net.minecraft.network.chat.ComponentContents import net.minecraft.network.chat.MutableComponent @@ -14,17 +15,150 @@ fun interface AndroidResearchFactory { fun factory(type: AndroidResearchType<*>, capability: AndroidCapabilityPlayer): R } +private fun findPrerequisites( + initial: Collection>, + add: MutableSet> = HashSet(), + top: Boolean = true +): Set> { + for (value in initial) { + if (!top) { + add.add(value) + } + + findPrerequisites(value.definedPrerequisites, add, false) + } + + return add +} + +private fun findAllPrerequisites( + initial: Collection>, + add: MutableSet> = HashSet(), +): Set> { + for (value in initial) { + add.add(value) + findAllPrerequisites(value.flatPrerequisites, add) + } + + return add +} + +private fun findAllChildren( + initial: Collection>, + add: MutableSet> = HashSet(), +): Set> { + for (value in initial) { + add.add(value) + findAllChildren(value.flatUnlocks, add) + } + + return add +} + open class AndroidResearchType( protected val factory: AndroidResearchFactory ) { - open val prerequisites: List> get() = emptyList() - open val blockedBy: List> get() = emptyList() + val researchTreeDepth: Int by lazy { + if (flatPrerequisites.isEmpty()) { + return@lazy 0 + } - val blocking: List> by lazy { + var depth = 1 + + for (value in flatPrerequisites) { + depth = depth.coerceAtLeast(value.researchTreeDepth + 1) + } + + return@lazy depth + } + + /** + * Prerequisites as-is + */ + open val definedPrerequisites: List> get() = emptyList() + + /** + * Blocked by list as-is + */ + open val definedBlockedBy: List> get() = emptyList() + + /** + * Flat list of research preceding this research. + * + * This list won't contain research following the same research path twice (guaranteed to be flat). + * + * E.g. + * + * * C depends on B + * * B depends on A + * + * C specify both B and A as it's prerequisites, [flatPrerequisites] will contain only B, when [definedPrerequisites] will contain + * both B and A + */ + val flatPrerequisites: List> by lazy { + val parentPrerequisites = findPrerequisites(definedPrerequisites) + val builder = ImmutableList.builder>() + + for (value in definedPrerequisites) { + if (value !in parentPrerequisites) { + builder.add(value) + } + } + + builder.build() + } + + /** + * All prerequisite research, including indirect ones + */ + val allPrerequisites: List> by lazy { + ImmutableList.copyOf(findAllPrerequisites(flatPrerequisites)) + } + + /** + * Flat list of research blocked by this research. + * + * This list won't contain children of any blocked research (guaranteed to be flat). + * + * E.g. + * + * * C depends on B + * * B is blocked by A + * * C is blocked by A + * + * Both C and B specify A as it's blockers, [flatBlocking] will contain only B, because C is blocked by A through B. + */ + val flatBlocking: List> by lazy { val list = ImmutableList.builder>() for (research in MRegistry.ANDROID_RESEARCH) { - if (research.blockedBy.contains(this)) { + if (this in research.definedBlockedBy) { + var hit = false + + for (parent in research.allPrerequisites) { + if (this in parent.definedBlockedBy) { + hit = true + break + } + } + + if (!hit) { + list.add(research) + } + } + } + + return@lazy list.build() + } + + /** + * All research directly unlocked by this research. + */ + val flatUnlocks: List> by lazy { + val list = ImmutableList.builder>() + + for (research in MRegistry.ANDROID_RESEARCH) { + if (this in research.flatPrerequisites) { list.add(research) } } @@ -32,16 +166,11 @@ open class AndroidResearchType( return@lazy list.build() } - val unlocks: List> by lazy { - val list = ImmutableList.builder>() - - for (research in MRegistry.ANDROID_RESEARCH) { - if (research.prerequisites.contains(this)) { - list.add(research) - } - } - - return@lazy list.build() + /** + * All research unlocked by this research, including indirect ones + */ + val allUnlocks: List> by lazy { + ImmutableList.copyOf(findAllChildren(flatUnlocks)) } fun factory(capability: AndroidCapabilityPlayer) = factory.factory(this, capability) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt index 86c8911d2..1590e1d49 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt @@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.core.RGBAColor import ru.dbotthepony.mc.otm.menu.AndroidStationMenu import ru.dbotthepony.mc.otm.network.AndroidNetworkChannel import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket -import ru.dbotthepony.mc.otm.network.MatteryNetworking import ru.dbotthepony.mc.otm.registry.MRegistry import java.util.* @@ -130,12 +129,12 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I createdButtonsIdx[level]++ rowsWidth[level] += 22f - for (_research in research.unlocks) { + for (_research in research.flatUnlocks) { dive(cap, _research, level + 1) } if (level > 0) { - for (_research in research.prerequisites) { + for (_research in research.definedPrerequisites) { dive(cap, _research, level - 1) } } @@ -164,7 +163,7 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I nextX = 0f for (research in MRegistry.ANDROID_RESEARCH.values) { - if (research.prerequisites.size == 0) { + if (research.definedPrerequisites.size == 0) { dive(it, research, 0) var max = 0f