From ca70916331029290c6ca310d94cffcc7cc50dfc8 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 17 Sep 2022 21:22:11 +0700 Subject: [PATCH] Android config values, move immune effect list to tags Clear immune effects before ticking player --- .../dbotthepony/mc/otm/datagen/tags/Tags.kt | 17 ++ .../mc/otm/datagen/tags/TagsProvider.kt | 13 +- .../mc/otm/OverdriveThatMatters.java | 2 - .../dbotthepony/mc/otm/ObservedConfigList.kt | 171 ++++++++++++++++++ .../dbotthepony/mc/otm/ObservedConfigValue.kt | 12 +- .../ru/dbotthepony/mc/otm/ServerConfig.kt | 20 ++ .../block/entity/AndroidStationBlockEntity.kt | 6 +- .../otm/capability/MatteryPlayerCapability.kt | 86 ++++----- .../mc/otm/client/screen/EnergyServoScreen.kt | 2 +- .../client/screen/MatterDecomposerScreen.kt | 2 +- .../ru/dbotthepony/mc/otm/core/Formatting.kt | 4 +- .../mc/otm/core/ImpreciseFraction.kt | 10 +- .../mc/otm/item/ExoSuitSlotUpgradeItem.kt | 13 +- .../dbotthepony/mc/otm/registry/LazyList.kt | 122 +++++++++++++ .../dbotthepony/mc/otm/registry/MRegistry.kt | 15 +- 15 files changed, 417 insertions(+), 78 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigList.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt index a56822b7c..22c75a964 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.datagen.tags +import net.minecraft.world.effect.MobEffects import net.minecraft.world.item.Items import net.minecraft.world.item.Tiers import ru.dbotthepony.mc.otm.registry.MBlocks @@ -97,4 +98,20 @@ fun addTags(tagsProvider: TagsProvider) { tagsProvider.witherImmune.add( MBlocks.BLACK_HOLE, ) + + tagsProvider.androidImmuneEffects.add( + MobEffects.CONDUIT_POWER, + MobEffects.HEAL, + // maybe it makes things go haywire idk + // MobEffects.HARM, + MobEffects.REGENERATION, + MobEffects.WATER_BREATHING, + MobEffects.POISON, + // even skeletons can be withered + // MobEffects.WITHER, + MobEffects.HEALTH_BOOST, + MobEffects.ABSORPTION, + MobEffects.SATURATION, + MobEffects.DOLPHINS_GRACE, + ) } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/TagsProvider.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/TagsProvider.kt index bbf0e3876..7bfa33b21 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/TagsProvider.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/TagsProvider.kt @@ -12,6 +12,7 @@ import net.minecraft.world.item.Tiers import net.minecraft.world.level.block.Block import net.minecraft.world.level.gameevent.GameEvent import net.minecraftforge.data.event.GatherDataEvent +import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.datagen.DataGen import net.minecraft.data.tags.TagsProvider as MinecraftTagsProvider @@ -57,6 +58,10 @@ class TagsProvider( private val event: GatherDataEvent ) { inner class Delegate(registry: Registry) : MinecraftTagsProvider(event.generator, registry, DataGen.MOD_ID, event.existingFileHelper) { + init { + event.generator.addProvider(true, this) + } + private val tags = HashMap, ObjectArraySet>() override fun addTags() { @@ -165,6 +170,9 @@ class TagsProvider( val blocks = Delegate(Registry.BLOCK) val items = Delegate(Registry.ITEM) + val mobEffects = Delegate(Registry.MOB_EFFECT) + + val androidImmuneEffects = mobEffects.appender(MatteryPlayerCapability.ANDROID_IMMUNE_EFFECTS) val requiresShovel = blocks.appender(BlockTags.MINEABLE_WITH_SHOVEL) val requiresAxe = blocks.appender(BlockTags.MINEABLE_WITH_AXE) @@ -216,11 +224,6 @@ class TagsProvider( val gameEvents = Delegate(Registry.GAME_EVENT) val vibrations = gameEvents.appender(GameEventTags.VIBRATIONS) - init { - event.generator.addProvider(true, blocks) - event.generator.addProvider(true, items) - } - fun requiresPickaxe(block: Block, tier: Tier? = null): TagsProvider { requiresPickaxe.add(block) diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 44798ffe6..e7d93be8b 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -122,8 +122,6 @@ public final class OverdriveThatMatters { EVENT_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::clientDisconnect); EVENT_BUS.addListener(EventPriority.LOWEST, PortableCondensationDriveItem.Companion::onPickupEvent); - MatteryPlayerCapability.Companion.registerEffects(event); - MatteryPlayerNetworkChannel.INSTANCE.register(); MenuNetworkChannel.INSTANCE.register(); WeaponNetworkChannel.INSTANCE.register(); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigList.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigList.kt new file mode 100644 index 000000000..0c2c192d0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigList.kt @@ -0,0 +1,171 @@ +package ru.dbotthepony.mc.otm + +import it.unimi.dsi.fastutil.ints.IntArrayList +import net.minecraft.resources.ResourceLocation +import net.minecraftforge.common.ForgeConfigSpec +import net.minecraftforge.registries.IForgeRegistry +import java.util.LinkedList + +abstract class ObservedConfigList(val parent: ForgeConfigSpec.ConfigValue>, private val allowNulls: Boolean = false) : AbstractMutableList(), RandomAccess { + private val rawValue: MutableList by parent + private val observedValue = LinkedList() + private val parsedView: ArrayList = ArrayList() + + protected abstract fun toString(value: V): Pair? + protected abstract fun fromString(value: String): V? + + private fun load() { + parsedView.clear() + observedValue.clear() + val removeIndexes = IntArrayList() + + for ((i, value) in rawValue.withIndex()) { + val parsedValue = fromString(value) + + if (parsedValue != null || allowNulls) { + observedValue.add(value) + } + + if (parsedValue != null) { + parsedView.add(parsedValue) + } else if (!allowNulls) { + removeIndexes.add(i) + } + } + + for (i in removeIndexes.size - 1 downTo 0) { + rawValue.removeAt(removeIndexes.getInt(i)) + } + + if (removeIndexes.isNotEmpty()) { + parent.save() + } + } + + private fun observe() { + val observedValue = observedValue + val rawValue = rawValue + + if (observedValue.size != rawValue.size) { + load() + } else { + val iter1 = rawValue.iterator() + val iter2 = observedValue.iterator() + + while (iter1.hasNext() && iter2.hasNext()) { + if (iter1.next() != iter2.next()) { + load() + return + } + } + + if (iter1.hasNext() || iter2.hasNext()) { + load() + } + } + } + + final override fun add(index: Int, element: V) { + observe() + + val (serialized, newObject) = toString(element) ?: return + + rawValue.add(index, serialized) + parsedView.add(index, newObject) + observedValue.add(index, serialized) + + parent.save() + } + + final override fun removeAt(index: Int): V { + observe() + + val old = parsedView[index] + val (serialized, _) = toString(old) ?: throw RuntimeException("Serializer did not accept element already present in list") + val oldStr = rawValue.getOrNull(index) + + if (oldStr == serialized) { + rawValue.removeAt(index) + observedValue.removeAt(index) + } else { + val serializedIndex = rawValue.indexOf(serialized) + + if (serializedIndex == -1) { + throw NoSuchElementException("Element $old is present in parsed list at index $index with serialized form of '$serialized', but it is not found in Forge's config list") + } + + rawValue.removeAt(serializedIndex) + observedValue.removeAt(serializedIndex) + } + + parsedView.removeAt(index) + + parent.save() + + return old + } + + final override fun set(index: Int, element: V): V { + observe() + + val old = parsedView[index] + + val (serializedNew, newElement) = toString(element) ?: return old + + if (old === newElement) { + return old + } + + val (serialized, _) = toString(old) ?: throw RuntimeException("Serializer did not accept element already present in list") + + check(rawValue[index] == serialized) { "Old value serialized representation $serialized does not match already stored representation ${rawValue[index]} at index $index" } + + parsedView[index] = newElement + observedValue[index] = serializedNew + rawValue[index] = serializedNew + + parent.save() + + return old + } + + final override val size: Int get() { + observe() + return parsedView.size + } + + override fun get(index: Int): V { + observe() + return parsedView[index] + } +} + +fun ForgeConfigSpec.Builder.defineObjectList( + name: String, + defaultValues: () -> List, + write: (value: T) -> Pair?, + read: (value: String) -> T? +): ObservedConfigList { + val parent = defineListAllowEmpty(name.split('.'), { defaultValues.invoke().mapNotNull { write.invoke(it)?.first }.toMutableList()}, { it is String }) as ForgeConfigSpec.ConfigValue> + + return object : ObservedConfigList(parent) { + override fun toString(value: T): Pair? { + return write.invoke(value) + } + + override fun fromString(value: String): T? { + return read.invoke(value) + } + } +} + +@Deprecated("Obviously better use tags") +fun ForgeConfigSpec.Builder.defineForgeObjectList( + name: String, + defaultValues: () -> List, + registry: IForgeRegistry +): ObservedConfigList { + return defineObjectList(name, defaultValues, + write = { (registry.getKey(it)?.toString() ?: return@defineObjectList null) to it }, + read = { registry.getValue(ResourceLocation(it)) }) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt index 9a622d49d..4aa7953a8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt @@ -12,20 +12,20 @@ abstract class ObservedConfigValue(val parent: ConfigValue) : R private var observedValue: String? = null private var cachedValue: V? = null - protected abstract fun fromValue(value: String): V? + protected abstract fun fromString(value: String): V? /** * value [V] -> newRawValue [String], newValue [V] */ - protected abstract fun toValue(value: V): Pair + protected abstract fun toString(value: V): Pair override fun get(): V { if (cachedValue == null || rawValue != observedValue) { - var deserialized = fromValue(rawValue) + var deserialized = fromString(rawValue) if (deserialized == null) { val default = parent.default - deserialized = fromValue(default) + deserialized = fromString(default) if (deserialized == null) { throw RuntimeException("Deserializer did not accept default value: $default") @@ -49,12 +49,12 @@ abstract class ObservedConfigValue(val parent: ConfigValue) : R override fun accept(value: V) { if (cachedValue == null || rawValue != observedValue) { - cachedValue = fromValue(rawValue) + cachedValue = fromString(rawValue) observedValue = rawValue } if (cachedValue != value) { - val (newRaw, newValue) = toValue(value) + val (newRaw, newValue) = toString(value) if (cachedValue != newValue) { rawValue = newRaw diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt index 4a823ad62..374abbdea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt @@ -1,8 +1,11 @@ package ru.dbotthepony.mc.otm +import net.minecraft.world.effect.MobEffect +import net.minecraft.world.effect.MobEffects import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.fml.ModLoadingContext import net.minecraftforge.fml.config.ModConfig +import net.minecraftforge.registries.ForgeRegistries import ru.dbotthepony.mc.otm.block.entity.AndroidStationBlockEntity import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity @@ -125,6 +128,23 @@ object ServerConfig { val DRIVE_VIEWER = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.DRIVE_VIEWER) val DRIVE_RACK = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.DRIVE_RACK, capacity = ImpreciseFraction(80_000)) + init { + specBuilder.pop() + + specBuilder.comment("Tweaking of android players").push("android_player") + } + + val ANDROID_ENERGY_PER_HUNGER_POINT by specBuilder.defineImpreciseFraction("energy_per_hunger", ImpreciseFraction(1000), ImpreciseFraction.ZERO) + val ANDROID_MAX_ENERGY by specBuilder.comment("Internal battery of every android has this much storage").defineImpreciseFraction("capacity", ImpreciseFraction(80_000), ImpreciseFraction.ZERO) + + init { + specBuilder.pop() + + specBuilder.comment("Tweaking of exosuits").push("exosuit_player") + } + + val INFINITE_EXOSUIT_UPGRADES: Boolean by specBuilder.comment("Allows to apply the same upgrade over and over again.", "Obviously completely breaks balance.").define("infinite_upgrades", false) + init { specBuilder.pop() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt index 0e34d6d9d..365599fec 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt @@ -20,9 +20,11 @@ import ru.dbotthepony.mc.otm.core.defineImpreciseFraction import ru.dbotthepony.mc.otm.core.ifPresentK import ru.dbotthepony.mc.otm.menu.AndroidStationMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.WriteOnce +@Suppress("ObjectPropertyName") class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { @@ -31,7 +33,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.ANDROID_STATION.name override val energy = object : WorkerEnergyStorage(this@AndroidStationBlockEntity::setChangedLight, ::CAPACITY, ::MAX_IO, { null }) { override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { @@ -96,8 +98,6 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.android_station") - private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() private var _MAX_IO: ImpreciseFractionConfigValue by WriteOnce() private var _ENERGY_PER_OPERATION: ImpreciseFractionConfigValue by WriteOnce() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index e90032f8c..076085147 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.capability import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap -import it.unimi.dsi.fastutil.objects.ObjectArraySet import net.minecraft.ChatFormatting import net.minecraft.core.Direction import net.minecraft.nbt.CompoundTag @@ -10,8 +9,8 @@ import net.minecraft.nbt.StringTag import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer +import net.minecraft.tags.TagKey import net.minecraft.world.effect.MobEffect -import net.minecraft.world.effect.MobEffects import net.minecraft.world.entity.Entity import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.MobSpawnType @@ -35,7 +34,7 @@ import net.minecraftforge.event.entity.living.LivingSpawnEvent import net.minecraftforge.event.entity.player.EntityItemPickupEvent import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.eventbus.api.Event -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent +import net.minecraftforge.registries.ForgeRegistries import org.apache.commons.lang3.mutable.MutableInt import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.* @@ -190,7 +189,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial var willBecomeAndroid by synchronizer.bool() var isAndroid by synchronizer.bool() - val androidEnergy = SynchronizedPowerWithBattery(ply, synchronizer, DEFAULT_MAX_ANDROID_POWER, DEFAULT_MAX_ANDROID_POWER) + val androidEnergy = SynchronizedPowerWithBattery(ply, synchronizer, ServerConfig.ANDROID_MAX_ENERGY, ServerConfig.ANDROID_MAX_ENERGY) fun invalidateNetworkState() { invalidateNetworkIn = 10 @@ -210,8 +209,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial shouldPlaySound = false iteration = 0 deathLog.clear() - androidEnergy.batteryLevel = DEFAULT_MAX_ANDROID_POWER - androidEnergy.maxBatteryLevel = DEFAULT_MAX_ANDROID_POWER + androidEnergy.batteryLevel = ServerConfig.ANDROID_MAX_ENERGY + androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY } fun becomeAndroidAndKill() { @@ -230,7 +229,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial iteration = 0 deathLog.clear() androidEnergy.batteryLevel = ImpreciseFraction.ZERO - androidEnergy.maxBatteryLevel = DEFAULT_MAX_ANDROID_POWER + androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY dropBattery() } @@ -521,6 +520,17 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial tickInventory() } + fun preTick() { + if (!ply.isAlive) return + + if (isAndroid) { + ForgeRegistries.MOB_EFFECTS.tags()?.getTag(ANDROID_IMMUNE_EFFECTS)?.forEach { + if (ply.hasEffect(it)) + ply.removeEffect(it) + } + } + } + fun tick() { if (!ply.isAlive) return @@ -538,10 +548,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial if (ply.airSupply < ply.maxAirSupply) ply.airSupply = ply.maxAirSupply - for (effect in UNAFFECTED_EFFECTS) - if (ply.hasEffect(effect)) - ply.removeEffect(effect) - // TODO: Maybe passive drain? // extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false); if (ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS)) { @@ -552,28 +558,28 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial val stats = ply.foodData - while (stats.foodLevel < 18 && androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) { - androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, false) + while (stats.foodLevel < 18 && androidEnergy.extractEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, true) >= ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT) { + androidEnergy.extractEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false) stats.foodLevel = stats.foodLevel + 1 } // "block" quick regeneration // also cause power to generate while in peaceful - while (stats.foodLevel > 18 && androidEnergy.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) { - androidEnergy.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, false) + while (stats.foodLevel > 18 && androidEnergy.receiveEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, true) >= ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT) { + androidEnergy.receiveEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false) stats.foodLevel = stats.foodLevel - 1 } val foodLevel = stats.foodLevel.toFloat() if (stats.saturationLevel < foodLevel) { - val extracted = androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (foodLevel - stats.saturationLevel), false) - stats.setSaturation(stats.saturationLevel + (extracted / ENERGY_FOR_HUNGER_POINT).toFloat()) + val extracted = androidEnergy.extractEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT * (foodLevel - stats.saturationLevel), false) + stats.setSaturation(stats.saturationLevel + (extracted / ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat()) } if (stats.exhaustionLevel > 0f) { - val extracted = androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (stats.exhaustionLevel / 4f), false) - stats.setExhaustion(stats.exhaustionLevel - (extracted / ENERGY_FOR_HUNGER_POINT).toFloat() * 4f) + val extracted = androidEnergy.extractEnergyInner(ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT * (stats.exhaustionLevel / 4f), false) + stats.setExhaustion(stats.exhaustionLevel - (extracted / ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat() * 4f) } for (feature in features.values) { @@ -653,37 +659,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial @Suppress("unused") companion object { - val UNAFFECTED_EFFECTS = ObjectArraySet() - - fun registerEffects(event: FMLCommonSetupEvent) { - UNAFFECTED_EFFECTS.add(MobEffects.CONDUIT_POWER) - UNAFFECTED_EFFECTS.add(MobEffects.HEAL) - // maybe it makes things go haywire idk - // UNAFFECTED_EFFECTS.add(MobEffects.HARM); - UNAFFECTED_EFFECTS.add(MobEffects.REGENERATION) - UNAFFECTED_EFFECTS.add(MobEffects.WATER_BREATHING) - UNAFFECTED_EFFECTS.add(MobEffects.POISON) - // even skeletons can be withered - // UNAFFECTED_EFFECTS.add(MobEffects.WITHER); - UNAFFECTED_EFFECTS.add(MobEffects.HEALTH_BOOST) - UNAFFECTED_EFFECTS.add(MobEffects.ABSORPTION) - UNAFFECTED_EFFECTS.add(MobEffects.SATURATION) - UNAFFECTED_EFFECTS.add(MobEffects.DOLPHINS_GRACE) - } + val ANDROID_IMMUNE_EFFECTS: TagKey = TagKey.create(ForgeRegistries.MOB_EFFECTS.registryKey, ResourceLocation(OverdriveThatMatters.MOD_ID, "android_immune_effects")) fun onPlayerTick(event: PlayerTickEvent) { - if (event.phase == TickEvent.Phase.START) - return - val ent = event.player - if (ent.level.isClientSide) { - ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { - it.tickClient() + if (event.phase == TickEvent.Phase.START) { + if (!ent.level.isClientSide) { + ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { + it.preTick() + } } } else { - ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { - it.tick() + if (ent.level.isClientSide) { + ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { + it.tickClient() + } + } else { + ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { + it.tick() + } } } } @@ -794,7 +789,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial event.original.invalidateCaps() } - val ENERGY_FOR_HUNGER_POINT = ImpreciseFraction(1000) const val SLEEP_TICKS_LIMIT = 80 private val itemPickupTicks = WeakHashMap>() @@ -839,7 +833,5 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } } - - val DEFAULT_MAX_ANDROID_POWER = ImpreciseFraction(60000) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/EnergyServoScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/EnergyServoScreen.kt index 9823da844..16cbe0c0c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/EnergyServoScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/EnergyServoScreen.kt @@ -14,7 +14,7 @@ import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalPowerGaugePanel import ru.dbotthepony.mc.otm.menu.EnergyServoMenu class EnergyServoScreen(menu: EnergyServoMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { - override fun makeMainFrame(): FramePanel>? { + override fun makeMainFrame(): FramePanel> { val frame = FramePanel.padded(this, width = AbstractSlotPanel.SIZE * 2f + HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + 8f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f, AbstractSlotPanel.SIZE, title) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatterDecomposerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatterDecomposerScreen.kt index f552c883c..a95600d33 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatterDecomposerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatterDecomposerScreen.kt @@ -13,7 +13,7 @@ import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel class MatterDecomposerScreen(p_97741_: MatterDecomposerMenu, p_97742_: Inventory, p_97743_: Component) : MatteryScreen(p_97741_, p_97742_, p_97743_) { - override fun makeMainFrame(): FramePanel> { + override fun makeMainFrame(): FramePanel> { val frame = super.makeMainFrame()!! val m = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt index c93e96d29..92154b122 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.core import com.google.common.collect.ImmutableList import net.minecraft.network.chat.Component -import net.minecraft.network.chat.MutableComponent import java.math.BigDecimal import java.math.BigInteger @@ -348,7 +347,8 @@ fun ImpreciseFraction.formatSi(decimalPlaces: Int = 2): String { fun Int.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString()) else if (suffix is Component) TextComponent(toString() + " " + suffix.string) else TextComponent(toString() + " " + suffix) + val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString()) else if (suffix is Component) TextComponent( + toString() + " " + suffix.string) else TextComponent(toString() + " " + suffix) return TranslatableComponent(prefix.formatLocaleKey, "%f.$decimalPlaces".format(this.toFloat() / prefix.int!!.toFloat()), suffix) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index 8f09996d8..1e653dbe6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -874,7 +874,7 @@ class ImpreciseFractionConfigValue( val minimum: ImpreciseFraction? = null, val maximum: ImpreciseFraction? = null, ) : ObservedConfigValue(parent) { - override fun fromValue(value: String): ImpreciseFraction? { + override fun fromString(value: String): ImpreciseFraction? { try { val parsed = ImpreciseFraction(value) @@ -890,7 +890,13 @@ class ImpreciseFractionConfigValue( } } - override fun toValue(value: ImpreciseFraction): Pair { + override fun toString(value: ImpreciseFraction): Pair { + if (minimum != null && minimum > value) { + return minimum.toString() to minimum + } else if (maximum != null && maximum < value) { + return maximum.toString() to maximum + } + return value.toString() to value } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt index 60c06e202..1717342e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt @@ -14,6 +14,7 @@ import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.UseAnim import net.minecraft.world.level.Level import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.TranslatableComponent @@ -46,7 +47,7 @@ class ExoSuitSlotUpgradeItem( } } - val alreadyHas = id != null && runIfClient(false) { + val alreadyHas = (id != null && !ServerConfig.INFINITE_EXOSUIT_UPGRADES) && runIfClient(false) { minecraft.player?.matteryPlayer?.exoSuitSlotCountModifiers?.contains(id) == true } @@ -60,7 +61,7 @@ class ExoSuitSlotUpgradeItem( override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder { val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand) - if (matteryPlayer.hasExoSuit && (id == null || id !in matteryPlayer.exoSuitSlotCountModifiers)) { + if (matteryPlayer.hasExoSuit && ((id == null || ServerConfig.INFINITE_EXOSUIT_UPGRADES) || id !in matteryPlayer.exoSuitSlotCountModifiers)) { player.startUsingItem(hand) return InteractionResultHolder.consume(player.getItemInHand(hand)) } @@ -72,7 +73,7 @@ class ExoSuitSlotUpgradeItem( if (player !is Player) return super.finishUsingItem(itemStack, level, player) val matteryPlayer = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player) - if (!matteryPlayer.hasExoSuit || (id != null && id in matteryPlayer.exoSuitSlotCountModifiers)) { + if (!matteryPlayer.hasExoSuit || (!ServerConfig.INFINITE_EXOSUIT_UPGRADES && id != null && id in matteryPlayer.exoSuitSlotCountModifiers)) { return super.finishUsingItem(itemStack, level, player) } @@ -81,7 +82,11 @@ class ExoSuitSlotUpgradeItem( if (player is ServerPlayer) { if (id != null) { - matteryPlayer.exoSuitSlotCountModifiers[id] = slotCount + if (ServerConfig.INFINITE_EXOSUIT_UPGRADES && id in matteryPlayer.exoSuitSlotCountModifiers) { + matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount + } else { + matteryPlayer.exoSuitSlotCountModifiers[id] = slotCount + } } else { matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt index 4df8a9193..12bc5416f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt @@ -24,6 +24,128 @@ class LazyList : AbstractList { } } +class ConditionalSet : AbstractSet { + // method without boxing + fun interface Condition { + fun check(): Boolean + } + + private val getters: Array> + + constructor(vararg getters: Pair) : super() { + this.getters = Array(getters.size) { getters[it] } + } + + constructor(getters: List>) : super() { + this.getters = Array(getters.size) { getters[it] } + } + + override val size: Int get() { + var i = 0 + + for (pair in getters) { + if (pair.first.check()) { + i++ + } + } + + return i + } + + override fun iterator(): Iterator { + return object : Iterator { + val parent = getters.iterator() + private var pair: Pair? = null + + private fun search() { + for (pair in parent) { + if (pair.first.check()) { + this.pair = pair + return + } + } + + this.pair = null + } + + init { + search() + } + + override fun hasNext(): Boolean { + return pair != null + } + + override fun next(): T { + val pair = pair ?: throw NoSuchElementException() + search() + return pair.second + } + } + } +} + +class ConditionalLazySet : AbstractSet { + // method without boxing + fun interface Condition { + fun check(): Boolean + } + + private val getters: Array T>> + + constructor(vararg getters: Pair T>) : super() { + this.getters = Array(getters.size) { getters[it] } + } + + constructor(getters: List T>>) : super() { + this.getters = Array(getters.size) { getters[it] } + } + + override val size: Int get() { + var i = 0 + + for (pair in getters) { + if (pair.first.check()) { + i++ + } + } + + return i + } + + override fun iterator(): Iterator { + return object : Iterator { + val parent = getters.iterator() + private var pair: Pair T>? = null + + private fun search() { + for (pair in parent) { + if (pair.first.check()) { + this.pair = pair + return + } + } + + this.pair = null + } + + init { + search() + } + + override fun hasNext(): Boolean { + return pair != null + } + + override fun next(): T { + val pair = pair ?: throw NoSuchElementException() + search() + return pair.second.invoke() + } + } + } +} + class LazyMap : AbstractMap { override val entries: Set> 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 cf9e411af..d706bfa2a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -30,6 +30,7 @@ import ru.dbotthepony.mc.otm.registry.objects.CrateProperties import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock import ru.dbotthepony.mc.otm.registry.objects.StripedColoredDecorativeBlock import java.util.function.Supplier +import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -41,15 +42,19 @@ fun Registry.register(key: ResourceLocation, value: T): Holder { return (this as WritableRegistry).register(ResourceKey.create(key(), key), value, Lifecycle.stable()) } -private class RegistryDelegate(key: String) { +private class RegistryDelegate(key: String) : ReadOnlyProperty> { private var value: Supplier?>? = null val location = ResourceLocation(OverdriveThatMatters.MOD_ID, key) val key: ResourceKey> = ResourceKey.createRegistryKey(location) - fun get(): IForgeRegistry { + fun get(): ForgeRegistry { val supp = value ?: throw IllegalStateException("Tried to access uninitialized registry $location") - return supp.get() ?: throw IllegalStateException("Accessing registry $location too early") + return supp.get() as ForgeRegistry? ?: throw IllegalStateException("Accessing registry $location too early") + } + + override fun getValue(thisRef: Any, property: KProperty<*>): ForgeRegistry { + return get() } fun build(event: NewRegistryEvent) { @@ -82,8 +87,8 @@ object MRegistry { private val features = RegistryDelegate>("android_features") private val research = RegistryDelegate>("android_research") - val ANDROID_FEATURES get() = features.get() as ForgeRegistry> - val ANDROID_RESEARCH get() = research.get() as ForgeRegistry> + val ANDROID_FEATURES by features + val ANDROID_RESEARCH by research val ANDROID_FEATURES_LOCATION get() = features.location val ANDROID_RESEARCH_LOCATION get() = research.location