diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index b7797fb52..673379cff 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -982,6 +982,15 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { + gui("exopack.accept_wireless_charge", "Accept wireless charging") + gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging") + + gui("charge_androids", "Charge Androids") + gui("dont_charge_androids", "Do not charge Androids") + + gui("charge_exopacks", "Charge Exopacks") + gui("dont_charge_exopacks", "Do not charge Exopacks") + gui("multiblock.formed", "Multiblock is formed: %s") gui("flywheel.current_loss_t", "Current energy loss per tick:") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 0efb16145..ae0d7b49b 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -975,6 +975,15 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { + gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников") + gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников") + + gui("charge_androids", "Заряжать андроидов") + gui("dont_charge_androids", "Не заряжать андроидов") + + gui("charge_exopacks", "Заряжать экзопаки") + gui("dont_charge_exopacks", "Не заряжать экзопаки") + gui("multiblock.formed", "Мультиблок сформирован: %s") gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:") diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/LoaderModel.java b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/LoaderModel.java index fb6f7fe48..03d63a3e6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/LoaderModel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/LoaderModel.java @@ -78,7 +78,7 @@ public class LoaderModel { this.animate(entity.getIdleState(), LoaderAnimation.ATTACK, ageInTicks, 1.0F); } - this.animateWalk(LoaderAnimation.MOVE, limbSwing, limbSwingAmount, 1.0F, 2.5F); + this.animateWalk(LoaderAnimation.MOVE, limbSwing, limbSwingAmount, 0.8F, 2.5F); this.animate(entity.getIdleState(), LoaderAnimation.IDLE, ageInTicks, 1.0F); } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt index 4580fcefe..a0c42c6b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt @@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.NbtOps import net.minecraft.network.chat.Component import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.server.level.ServerLevel import net.minecraft.world.MenuProvider import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player @@ -83,9 +84,11 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo override fun setLevel(level: Level) { super.setLevel(level) - level.once { - if (!isRemoved && this.level == level) { - redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos) + if (level is ServerLevel) { + level.once(4) { + if (!isRemoved && this.level == level) { + redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos) + } } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt index 1fcbf265f..693ec5090 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt @@ -165,7 +165,7 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP if (!SERVER_IS_LIVE) return val level = level - level?.once { + level?.once(4) { if (!node.isValid) return@once val newState = blockState diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index 49b77cbe7..8434ce627 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.block.entity.cable import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet +import net.minecraft.core.Direction import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.SERVER_IS_LIVE import ru.dbotthepony.mc.otm.UNIVERSE_TICKS @@ -74,16 +75,20 @@ private class LinkedPriorityQueue> { } class EnergyCableGraph : GraphNodeList() { - private val livelyNodes = HashSet() - private val livelyNodesList = ArrayList() + private val livelyNodes = HashSet>() + private val livelyNodesList = ArrayList>() fun addLivelyNode(node: EnergyCableBlockEntity.Node) { when (contains(node)) { ContainsStatus.ABOUT_TO_BE_REMOVED, ContainsStatus.ABOUT_TO_BE_ADDED -> { } // do nothing ContainsStatus.DOES_NOT_BELONG -> throw IllegalArgumentException("$node does not belong to $this") ContainsStatus.CONTAINS -> { - if (livelyNodes.add(node)) { - livelyNodesList.add(node) + for (dir in RelativeSide.entries) { + val pair = node to dir + + if (livelyNodes.add(pair)) { + livelyNodesList.add(pair) + } } } } @@ -584,8 +589,12 @@ class EnergyCableGraph : GraphNodeList() @@ -608,8 +617,11 @@ class EnergyCableGraph : GraphNodeList() - for (node in itr) { - var hit = false + for (pair in itr) { + val (node, relSide) = pair + val side = node.sides[relSide]!! - for (side in node.sides.values) { - if (!side.isEnabled) - continue - else if (fromNode === node && side.side === fromSide) { - hit = true - continue - } - - val it = side.neighbour.get() ?: continue - if (it is EnergyCableBlockEntity.CableSide) continue - - val paths = getPath(fromNode, node, it.receiveEnergy(residue, true), !simulate) - hit = true - - if (paths.size == 1) { - // Single path, fast scenario - val path = paths[0] - val pathTransferred = path.transfer(residue, simulate, snapshot) - if (pathTransferred <= Decimal.ZERO) continue - val thisReceived = it.receiveEnergy(pathTransferred, simulate) - - // If cable transferred more than machine accepted, then "refund" energy - // so cables record actual value transferred through them - if (thisReceived != pathTransferred) { - path.refund(pathTransferred - thisReceived, simulate, snapshot) - - if (!simulate && thisReceived != Decimal.ZERO) { - path.triggerBlockstateUpdates() - } - } else if (!simulate) { - path.triggerBlockstateUpdates() - } - - received += thisReceived - residue -= thisReceived - if (!residue.isPositive) return received - } else if (paths.size >= 2) { - // Multiple paths, a bit more complicated - // Determine how much machine is likely to accept - val potentiallyAccepted = it.receiveEnergy(residue, true) - - // Won't accept anything - if (potentiallyAccepted <= Decimal.ZERO) continue - - // Now determine combined available throughput - // Make a copy of snapshot, so we can freely write into it - val copy = snapshot.clone() - var calcResidue = potentiallyAccepted - - // TODO: Currently, all transfers cause Braess's paradox, because of greedy selection of "fastest" cable - // Need to implement heuristics to better distribute load across different paths/segments - for (path in paths) { - val passed = path.transfer(calcResidue, true, copy) - calcResidue -= passed - if (calcResidue <= Decimal.ZERO) break - } - - if (calcResidue == potentiallyAccepted) { - // мда - continue - } - - var thisReceived = it.receiveEnergy(potentiallyAccepted - calcResidue, simulate) - received += thisReceived - residue -= thisReceived - - for (path in paths) { - val passed = path.transfer(thisReceived, simulate, snapshot) - - if (!simulate) - path.triggerBlockstateUpdates() - - thisReceived -= passed - if (thisReceived <= Decimal.ZERO) break - } - - if (!residue.isPositive) return received - //check(thisReceived <= Decimal.ZERO) { "Путом, алло, Путом, какого чёрта Путом? Путом почему ты заблокировал логику, а Путом?" } - - if (thisReceived > Decimal.ZERO) { - LOGGER.warn("Cable path from $fromNode to $node doesn't follow common sense, disabling.") - paths.forEach { it.shortCircuit = true } - } - } + if (!side.isEnabled) { + itr.remove() + check(livelyNodes.remove(pair)) { "Lively nodes Set does not contain $pair" } + continue + } else if (fromNode === node && side.side === fromSide) { + continue } - if (!hit) { + val it = side.neighbour.get() + + if (it == null || it is EnergyCableBlockEntity.CableSide) { itr.remove() - check(livelyNodes.remove(node)) { "Lively nodes Set does not contain $node" } + check(livelyNodes.remove(pair)) { "Lively nodes Set does not contain $pair" } + continue + } + + val paths = getPath(fromNode, node, it.receiveEnergy(residue, true), !simulate) + + if (paths.size == 1) { + // Single path, fast scenario + val path = paths[0] + val pathTransferred = path.transfer(residue, simulate, snapshot) + if (pathTransferred <= Decimal.ZERO) continue + val thisReceived = it.receiveEnergy(pathTransferred, simulate) + + // If cable transferred more than machine accepted, then "refund" energy + // so cables record actual value transferred through them + if (thisReceived != pathTransferred) { + path.refund(pathTransferred - thisReceived, simulate, snapshot) + + if (!simulate && thisReceived != Decimal.ZERO) { + path.triggerBlockstateUpdates() + } + } else if (!simulate) { + path.triggerBlockstateUpdates() + } + + received += thisReceived + residue -= thisReceived + if (!residue.isPositive) return received + } else if (paths.size >= 2) { + // Multiple paths, a bit more complicated + // Determine how much machine is likely to accept + val potentiallyAccepted = it.receiveEnergy(residue, true) + + // Won't accept anything + if (potentiallyAccepted <= Decimal.ZERO) continue + + // Now determine combined available throughput + // Make a copy of snapshot, so we can freely write into it + val copy = snapshot.clone() + var calcResidue = potentiallyAccepted + + // TODO: Currently, all transfers cause Braess's paradox, because of greedy selection of "fastest" cable + // Need to implement heuristics to better distribute load across different paths/segments + for (path in paths) { + val passed = path.transfer(calcResidue, true, copy) + calcResidue -= passed + if (calcResidue <= Decimal.ZERO) break + } + + if (calcResidue == potentiallyAccepted) { + // мда + continue + } + + var thisReceived = it.receiveEnergy(potentiallyAccepted - calcResidue, simulate) + received += thisReceived + residue -= thisReceived + + for (path in paths) { + val passed = path.transfer(thisReceived, simulate, snapshot) + + if (!simulate) + path.triggerBlockstateUpdates() + + thisReceived -= passed + if (thisReceived <= Decimal.ZERO) break + } + + if (!residue.isPositive) return received + //check(thisReceived <= Decimal.ZERO) { "Путом, алло, Путом, какого чёрта Путом? Путом почему ты заблокировал логику, а Путом?" } + + if (thisReceived > Decimal.ZERO) { + LOGGER.warn("Cable path from $fromNode to $node doesn't follow common sense, disabling.") + paths.forEach { it.shortCircuit = true } + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt index af0ef7c1c..e960ffe5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt @@ -103,7 +103,7 @@ class CargoCrateBlockEntity( super.loadAdditional(nbt, registry) if (nbt.contains(LOOT_TABLE_KEY, Tag.TAG_STRING.toInt())) { - lootTable = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.tryParse(nbt.getString(LOOT_TABLE_KEY))) + lootTable = ResourceLocation.tryParse(nbt.getString(LOOT_TABLE_KEY))?.let { ResourceKey.create(Registries.LOOT_TABLE, it) } lootTableSeed = if (nbt.contains(LOOT_TABLE_SEED_KEY, Tag.TAG_LONG.toInt())) nbt.getLong(LOOT_TABLE_SEED_KEY) else 0L } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index d57799340..2378e78ce 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -119,7 +119,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : var findState: PatternState? = null for (state in matterNode.graph.patterns.filter { it.item === stack.item }) { - if (state.researchPercent < 1.0) { + if (state.researchPercent < 1.0 && findState == null) { findState = state } else if (state.researchPercent >= 1.0) { return JobContainer.noItem() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt index 3c687d365..17d1f79da 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt @@ -30,14 +30,28 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ANDROID_CHARGER)) val energyConfig = ConfigurableEnergy(energy, modesTop = FlowDirection.NONE) + var chargeAndroids = true + set(value) { + field = value + markDirtyFast() + } + + var chargeExopacks = true + set(value) { + field = value + markDirtyFast() + } + init { savetables.stateful(energyConfig::energy, ENERGY_KEY) + savetablesConfig.bool(::chargeAndroids) + savetablesConfig.bool(::chargeExopacks) } override fun tick() { super.tick() - if (redstoneControl.isBlockedByRedstone) return + if (redstoneControl.isBlockedByRedstone || !chargeAndroids && !chargeExopacks) return val level = level ?: return var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true) if (!available.isPositive) return @@ -49,14 +63,14 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma for ((ent) in ents) { val ply = (ent as Player).matteryPlayer - if (ply.isAndroid) { + if (chargeAndroids && ply.isAndroid) { val received = ply.androidEnergy.receiveEnergyChecked(available, false) available -= received energyConfig.energy.extractEnergy(received, false) if (!available.isPositive) return } - if (ply.hasExopack) { + if (chargeExopacks && ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) { val received = ply.exopackEnergy.receiveEnergyChecked(available, false) available -= received energyConfig.energy.extractEnergy(received, false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt index 42b2e62a0..3ef4f37e5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt @@ -17,21 +17,26 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.shuffle +import ru.dbotthepony.mc.otm.core.util.countingLazy import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities -class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { - +class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return AndroidStationMenu(containerID, inventory, this) } + private val workerState by countingLazy(blockStateChangesCounter) { + blockState.getValue(WorkerState.SEMI_WORKER_STATE) + } + override val energy: ProfiledEnergyStorage = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { return super.extractEnergy(howMuch, simulate).also { if (!simulate && this.batteryLevel.isZero) { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { + if (workerState != WorkerState.IDLE) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) } } @@ -41,7 +46,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal { return super.receiveEnergy(howMuch, simulate).also { if (!simulate && it.isPositive) { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { + if (workerState != WorkerState.WORKING) { level?.setBlock(blockPos, blockState.setValue( WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING @@ -53,9 +58,15 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : }) val energyConfig = ConfigurableEnergy(energy) + var chargeAndroids = true + set(value) { + field = value + markDirtyFast() + } init { savetables.stateful(::energy, ENERGY_KEY) + savetablesConfig.bool(::chargeAndroids) } private var tickedOnce = false @@ -66,20 +77,20 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : if (!tickedOnce) { tickedOnce = true - if (energy.batteryLevel.isPositive && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { + if (energy.batteryLevel.isPositive && workerState != WorkerState.WORKING) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) - } else if (energy.batteryLevel.isZero && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { + } else if (!energy.batteryLevel.isPositive && workerState != WorkerState.IDLE) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) } } - if (redstoneControl.isBlockedByRedstone) return + if (redstoneControl.isBlockedByRedstone || !chargeAndroids) return val level = level ?: return val x = blockPos.x.toDouble() val y = blockPos.y.toDouble() val z = blockPos.z.toDouble() - for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0))) { + for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0)).shuffle(level.otmRandom)) { if (ent.matteryPlayer.isAndroid) moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt index d3c8ae76f..717b6d975 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt @@ -565,6 +565,7 @@ class MatteryPlayer(val ply: Player) { val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) })) val exopackChargeSlots = MatteryContainer(4) + var acceptExopackChargeFromWirelessCharger = true init { savetables.int(::ticksIExist) @@ -578,6 +579,7 @@ class MatteryPlayer(val ply: Player) { savetables.bool(::isExopackVisible, "displayExoSuit") savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded") savetables.bool(::isExopackEnderAccessInstalled, "isExopackEnderAccessUpgraded") + savetables.bool(::acceptExopackChargeFromWirelessCharger) savetables.int(::nextDischargeHurt) savetables.int(::nextHealTick) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt index 2d52e5824..06bab6193 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt @@ -43,6 +43,10 @@ object Widgets18 { val CURIOS_INVENTORY = miscGrid.next() val STATISTICS_TAB = miscGrid.next() val SETTINGS_TAB = miscGrid.next() + val WIRELESS_CHARGING_ENABLED = miscGrid.next() + val WIRELESS_CHARGING_DISABLED = miscGrid.next() + val WIRELESS_CHARGING_ANDROIDS_ENABLED = miscGrid.next() + val WIRELESS_CHARGING_ANDROIDS_DISABLED = miscGrid.next() private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RogueAndroidRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RogueAndroidRenderer.kt index ad7c1a5d4..9f7340a4d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RogueAndroidRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RogueAndroidRenderer.kt @@ -1,4 +1,5 @@ package ru.dbotthepony.mc.otm.client.render.entity +import net.minecraft.client.model.HumanoidModel import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.ResourceLocation @@ -6,17 +7,32 @@ import net.minecraft.client.model.PlayerModel import net.minecraft.client.renderer.entity.EntityRendererProvider import net.minecraft.client.renderer.entity.HumanoidMobRenderer import net.minecraft.client.model.geom.ModelLayers +import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer +import net.minecraft.client.renderer.entity.layers.ItemInHandLayer +import net.minecraft.client.resources.model.ModelManager import net.minecraft.resources.ResourceLocation import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.Mob -class RogueAndroidRenderer(context: EntityRendererProvider.Context, private val entityType: EntityType, private val androidTexture: String) : +class RogueAndroidRenderer(context: EntityRendererProvider.Context, private val entityType: EntityType, private val androidTexture: String,private val modelManager: ModelManager) : HumanoidMobRenderer>( context, PlayerModel(context.bakeLayer(ModelLayers.PLAYER), false), 0.5f ) { + init { + addLayer(ItemInHandLayer(this, context.itemInHandRenderer)) + addLayer( + HumanoidArmorLayer( + this, + HumanoidModel(context.bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)), + HumanoidModel(context.bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR)), + modelManager + ) + ) + } + override fun getTextureLocation(entity: T): ResourceLocation { return ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/entity/android/$androidTexture.png") } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt index 2eeccb3e4..dac9e5539 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.render.WidgetLocation import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.translation import ru.dbotthepony.mc.otm.client.screen.panels.* +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel @@ -172,13 +173,25 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit } protected fun makeChargePanels(frame: EditablePanel<*>) { - val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE + 6f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f + val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE * 2 + 8f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f val chargeStrip = BackgroundPanel.paddedCenter(this, frame, frame.width - chargeWidth - 6f, frame.height + 2f, chargeWidth, AbstractSlotPanel.SIZE) val chargeStrip2 = BackgroundPanel.paddedCenter(this, frame, frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f, AbstractSlotPanel.SIZE, AbstractSlotPanel.SIZE * 4f) chargeStrip.customDock { chargeStrip.setPos(frame.width - chargeWidth - 6f, frame.height + 2f) } chargeStrip2.customDock { chargeStrip2.setPos(frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f) } + BooleanButtonPanel.square18( + this, chargeStrip, + prop = menu.acceptExopackChargeFromWirelessCharger, + iconActive = Widgets18.WIRELESS_CHARGING_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.exopack.accept_wireless_charge"), + tooltipInactive = TranslatableComponent("otm.gui.exopack.dont_accept_wireless_charge"), + ).also { + it.dock = Dock.LEFT + it.dockRight = 2f + } + BatterySlotPanel(this, chargeStrip, menu.exopackChargeSlots[0]).also { it.dock = Dock.LEFT } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt index 27b80cb22..a7e6b9fb4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.tech import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel @@ -10,8 +11,10 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { @@ -40,7 +43,33 @@ class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title it.dockRight = 2f } - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + + if (menu.chargeExopacks != null) { + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeExopacks!!, + iconActive = Widgets18.WIRELESS_CHARGING_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_exopacks"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_exopacks"), + ) + ) + } + + if (menu.chargeAndroids != null) { + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeAndroids!!, + iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_androids"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"), + ) + ) + } return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt index 16acceee3..08190ec3c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt @@ -34,6 +34,7 @@ import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.core.RandomSource2Generator import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket @@ -717,7 +718,18 @@ class AndroidStationScreen(p_97741_: AndroidStationMenu, p_97742_: Inventory, p_ this.playerStrip = playerStrip - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeAndroids, + iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_androids"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"), + ) + ) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 6cb4504db..50130a208 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -188,17 +188,20 @@ fun > T.prev(values: Array): T { return values[next] } -fun IntArray.shuffle(random: RandomSource) { +fun IntArray.shuffle(random: RandomSource): IntArray { for (i in lastIndex downTo 1) { val j = random.nextInt(i + 1) val copy = this[i] this[i] = this[j] this[j] = copy } + + return this } -fun MutableList.shuffle(random: RandomSource) { - return Util.shuffle(this, random) +fun > L.shuffle(random: RandomSource): L { + Util.shuffle(this, random) + return this } fun List.random(random: RandomGenerator): T { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 99438ed72..5095ac2fe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -6,7 +6,6 @@ import net.minecraft.util.RandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.RandomSupport -import java.lang.StringBuilder import java.util.random.RandomGenerator /** @@ -22,12 +21,12 @@ class Xoshiro256SSRandom private constructor( private val gaussian = MarsagliaPolarGaussian(this) init { - require( - s0 != 0L || - s1 != 0L || - s2 != 0L || - s3 != 0L - ) { "Xoshiro can't operate with seed being entirely zero" } + if (s0 or s1 or s2 or s3 == 0L) { + s0 = 0x73CF3D83FFF44FF3L + s1 = 0x6412312B70F3CD37L + s2 = -0X6BB4C4E1327BFDCFL + s3 = -0X4BE0F5BB5F3F5240L + } } constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) { @@ -129,4 +128,11 @@ class Xoshiro256SSRandom private constructor( throw UnsupportedOperationException() } } + + companion object { + @JvmStatic + fun raw(s0: Long, s1: Long, s2: Long, s3: Long): Xoshiro256SSRandom { + return Xoshiro256SSRandom(s0, s1, s2, s3, null) + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/AndroidMelee.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/AndroidMelee.kt index 0df65bc77..4a827f31a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/AndroidMelee.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/AndroidMelee.kt @@ -6,7 +6,7 @@ import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.attributes.AttributeSupplier import net.minecraft.world.entity.ai.attributes.Attributes -import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal +import net.minecraft.world.entity.ai.goal.AvoidEntityGoal import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal import net.minecraft.world.entity.ai.goal.MeleeAttackGoal import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal @@ -15,7 +15,9 @@ import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal import net.minecraft.world.entity.ai.navigation.GroundPathNavigation import net.minecraft.world.entity.ai.navigation.PathNavigation -import net.minecraft.world.entity.monster.Monster +import net.minecraft.world.entity.animal.frog.Frog +import net.minecraft.world.entity.monster.* +import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level @@ -24,14 +26,19 @@ class AndroidMelee(type: EntityType, level: Level) : Monster(type, override fun registerGoals() { goalSelector.addGoal(8, RandomLookAroundGoal(this)) - goalSelector.addGoal(7, WaterAvoidingRandomStrollGoal(this, 0.8)) + goalSelector.addGoal(7, WaterAvoidingRandomStrollGoal(this, 0.6)) goalSelector.addGoal(8, LookAtPlayerGoal(this, Player::class.java, 8f)) - goalSelector.addGoal(3, NearestAttackableTargetGoal(this, LivingEntity::class.java , true, true)) - goalSelector.addGoal(3, NearestAttackableTargetGoal(this, Player::class.java , true, true)) + goalSelector.addGoal(3, NearestAttackableTargetGoal(this, LivingEntity::class.java, 10, true, true) { entity -> + entity is Player || + entity is Villager || + entity is AbstractIllager || + entity is Zombie || + entity is AbstractSkeleton + }) - goalSelector.addGoal(1, LeapAtTargetGoal(this, 0.4f)) - goalSelector.addGoal(2, MeleeAttackGoal(this, 1.3, true)) + goalSelector.addGoal(1, AvoidEntityGoal(this, Frog::class.java, 8.0F, 1.2, 1.5)) + goalSelector.addGoal(2, MeleeAttackGoal(this, 1.0, true)) targetSelector.addGoal(1, HurtByTargetGoal(this)) } @@ -40,7 +47,11 @@ class AndroidMelee(type: EntityType, level: Level) : Monster(type, } override fun getHurtSound(damageSource: net.minecraft.world.damagesource.DamageSource): SoundEvent { - return SoundEvents.IRON_GOLEM_HURT + return SoundEvents.HEAVY_CORE_BREAK + } + + override fun getDeathSound(): SoundEvent { + return SoundEvents.VAULT_BREAK } override fun createNavigation(level: Level): PathNavigation = GroundPathNavigation(this, level) @@ -48,9 +59,11 @@ class AndroidMelee(type: EntityType, level: Level) : Monster(type, companion object { fun createAttributes() : AttributeSupplier.Builder { return createMonsterAttributes() - .add(Attributes.MAX_HEALTH, 16.0) + .add(Attributes.MAX_HEALTH, 30.0) + .add(Attributes.ARMOR, 4.0) + .add(Attributes.SCALE, 1.1) .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.ATTACK_DAMAGE, 3.0) + .add(Attributes.ATTACK_DAMAGE, 4.0) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt index f13fd15dc..512563d84 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt @@ -14,7 +14,11 @@ import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal import net.minecraft.world.entity.ai.navigation.GroundPathNavigation import net.minecraft.world.entity.ai.navigation.PathNavigation +import net.minecraft.world.entity.monster.AbstractIllager +import net.minecraft.world.entity.monster.AbstractSkeleton import net.minecraft.world.entity.monster.Monster +import net.minecraft.world.entity.monster.Zombie +import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.level.Level @@ -29,8 +33,10 @@ class BreadMonster(type: EntityType, level: Level) : Monster(type, goalSelector.addGoal(8, RandomLookAroundGoal(this)) goalSelector.addGoal(7, WaterAvoidingRandomStrollGoal(this, 0.8)) goalSelector.addGoal(8, LookAtPlayerGoal(this, Player::class.java, 8f)) - goalSelector.addGoal(3, NearestAttackableTargetGoal(this, LivingEntity::class.java , true, true)) goalSelector.addGoal(3, NearestAttackableTargetGoal(this, Player::class.java , true, true)) + goalSelector.addGoal(3, NearestAttackableTargetGoal(this, LivingEntity::class.java, 10, true, true) { entity -> + entity !is BreadMonster + }) goalSelector.addGoal(1, LeapAtTargetGoal(this, 0.4f)) goalSelector.addGoal(2, MeleeAttackGoal(this, 1.3, true)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Loader.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Loader.kt index 38ecf9013..d0d3a5e50 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Loader.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Loader.kt @@ -12,6 +12,7 @@ import net.minecraft.sounds.SoundEvents import net.minecraft.world.entity.AnimationState import net.minecraft.world.entity.Entity import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.attributes.AttributeSupplier import net.minecraft.world.entity.ai.attributes.Attributes import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal @@ -22,7 +23,11 @@ import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal import net.minecraft.world.entity.ai.navigation.GroundPathNavigation import net.minecraft.world.entity.ai.navigation.PathNavigation +import net.minecraft.world.entity.monster.AbstractIllager +import net.minecraft.world.entity.monster.AbstractSkeleton import net.minecraft.world.entity.monster.Monster +import net.minecraft.world.entity.monster.Zombie +import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.level.Level import ru.dbotthepony.mc.otm.OverdriveThatMatters @@ -68,7 +73,13 @@ class Loader(type: EntityType, level: Level) : Monster(type, level) { goalSelector.addGoal(8, RandomLookAroundGoal(this)) goalSelector.addGoal(7, WaterAvoidingRandomStrollGoal(this, 0.8)) goalSelector.addGoal(8, LookAtPlayerGoal(this, Player::class.java, 8f)) - goalSelector.addGoal(3, NearestAttackableTargetGoal(this, Player::class.java , true, true)) + goalSelector.addGoal(3, NearestAttackableTargetGoal(this, LivingEntity::class.java, 10, true, true) { entity -> + entity is Player || + entity is Villager || + entity is AbstractIllager || + entity is Zombie || + entity is AbstractSkeleton + }) goalSelector.addGoal(2, MeleeAttackGoal(this, 1.0, true)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index 6d27c6177..0d8e58e48 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -7,7 +7,14 @@ import net.minecraft.server.level.ServerPlayer import net.minecraft.world.Container import net.minecraft.world.entity.ExperienceOrb import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.* +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.inventory.ContainerSynchronizer +import net.minecraft.world.inventory.CraftingContainer +import net.minecraft.world.inventory.CraftingMenu +import net.minecraft.world.inventory.ResultContainer +import net.minecraft.world.inventory.ResultSlot +import net.minecraft.world.inventory.Slot +import net.minecraft.world.inventory.TransientCraftingContainer import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.network.PacketDistributor import ru.dbotthepony.mc.otm.capability.MatteryPlayer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt index 674e64ea6..4a65058ae 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.container.sortWithIndices import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.collect.ConditionalSet import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.network.MatteryStreamCodec import ru.dbotthepony.mc.otm.network.MenuDataPacket @@ -207,7 +208,8 @@ abstract class MatteryMenu( var sortInventoryInput: SortInput? = null private set - val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings) + val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer.sortingSettings) + val acceptExopackChargeFromWirelessCharger = BooleanInputWithFeedback(this, true, player.matteryPlayer::acceptExopackChargeFromWirelessCharger) var offhandSlot: InventorySlot? = null protected set diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index bf6ee95a6..a39b17f62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -63,10 +63,6 @@ open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) return super.mayPickup(player) && (!ignoreSpectators || !player.isSpectator) } - override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (!ignoreSpectators || runOnClient(true) { minecraft.player?.isSpectator != true }) - } - open fun canTakeItemForPickAll(): Boolean { return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt index 196526d4d..be2b8c24e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt @@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerMiddleBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerTopBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -13,6 +14,9 @@ class AndroidChargerMenu : MatteryPoweredMenu { val energyConfig: EnergyConfigPlayerInput val profiledEnergy: ProfiledLevelGaugeWidget<*> + val chargeAndroids: BooleanInputWithFeedback? + val chargeExopacks: BooleanInputWithFeedback? + constructor( p_38852_: Int, inventory: Inventory, @@ -20,6 +24,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget) + chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids }) + chargeExopacks = BooleanInputWithFeedback(this, tile?.let { it::chargeExopacks }) } constructor( @@ -29,6 +35,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) + chargeAndroids = null + chargeExopacks = null } constructor( @@ -38,6 +46,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) + chargeAndroids = null + chargeExopacks = null } init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt index 9b3f0da7e..974fa4823 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt @@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -25,7 +26,7 @@ class AndroidStationMenu @JvmOverloads constructor( ) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) { private fun container(target: (MatteryPlayer) -> KMutableProperty0): Container { if (player is ServerPlayer) - return PartContainer(target.invoke(player.matteryPlayer ?: throw NullPointerException("OTM player capability is missing"))) + return PartContainer(target.invoke(player.matteryPlayer)) else return SimpleContainer(1) } @@ -115,6 +116,7 @@ class AndroidStationMenu @JvmOverloads constructor( val equipment = makeEquipmentSlots() val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) + val chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids }) init { addInventorySlots() @@ -122,6 +124,6 @@ class AndroidStationMenu @JvmOverloads constructor( } override fun stillValid(player: Player): Boolean { - return super.stillValid(player) && player.matteryPlayer?.isAndroid == true + return super.stillValid(player) && player.matteryPlayer.isAndroid } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt index af4a6b109..ebfa596c4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt @@ -77,7 +77,7 @@ object MEntityTypes { private fun registerAttributes(event: EntityAttributeCreationEvent) { event.put(BREAD_MONSTER, BreadMonster.createAttributes().build()) event.put(LOADER, Loader.createAttributes().build()) - event.put(ANDROID_MELEE, Loader.createAttributes().build()) + event.put(ANDROID_MELEE, AndroidMelee.createAttributes().build()) } @Suppress("unchecked_cast") @@ -94,7 +94,7 @@ object MEntityTypes { EntityRenderers.register(LOADER, ::LoaderRenderer) EntityRenderers.register(ANDROID_MELEE) { context -> - RogueAndroidRenderer(context, ANDROID_MELEE, "melee") + RogueAndroidRenderer(context, ANDROID_MELEE, "melee",context.modelManager) } } } diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png index b5dc14305..0c33af3f2 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf index 65faca40d..894ea7b4b 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png index 4ecb97677..f311ac0c6 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf index ceec2f67e..ad1bff632 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_a.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_a.nbt index 478c171a7..cd5ad5874 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_a.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_a.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_b.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_b.nbt index 98e586f0d..1715e99ba 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_b.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_b.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_c.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_c.nbt index a0cd64d4b..2ca375811 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_c.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_c.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_d.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_d.nbt index eea9ee537..5955b2742 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_d.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_d.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_e.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_e.nbt index 516fa0596..1cf97bee8 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_e.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_e.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_f.nbt b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_f.nbt index bab3d0454..3dd138768 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_f.nbt and b/src/main/resources/data/overdrive_that_matters/structure/frigate/rooms/frigate_room_f.nbt differ