Merge branch '1.21' into worldgen-placement-providers
This commit is contained in:
commit
0ef34a00cc
@ -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:")
|
||||
|
@ -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", "Текущая потеря энергии в тик:")
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<T : Comparable<T>> {
|
||||
}
|
||||
|
||||
class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableGraph>() {
|
||||
private val livelyNodes = HashSet<EnergyCableBlockEntity.Node>()
|
||||
private val livelyNodesList = ArrayList<EnergyCableBlockEntity.Node>()
|
||||
private val livelyNodes = HashSet<Pair<EnergyCableBlockEntity.Node, RelativeSide>>()
|
||||
private val livelyNodesList = ArrayList<Pair<EnergyCableBlockEntity.Node, RelativeSide>>()
|
||||
|
||||
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<EnergyCableBlockEntity.Node, EnergyCableG
|
||||
}
|
||||
|
||||
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
||||
if (livelyNodes.remove(node)) {
|
||||
check(livelyNodesList.remove(node))
|
||||
for (dir in RelativeSide.entries) {
|
||||
val pair = node to dir
|
||||
|
||||
if (livelyNodes.remove(pair)) {
|
||||
check(livelyNodesList.remove(pair))
|
||||
}
|
||||
}
|
||||
|
||||
val touchedSegments = HashSet<Segment>()
|
||||
@ -608,8 +617,11 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
||||
}
|
||||
|
||||
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
||||
check(livelyNodes.add(node))
|
||||
livelyNodesList.add(node)
|
||||
for (dir in RelativeSide.entries) {
|
||||
val pair = node to dir
|
||||
check(livelyNodes.add(pair))
|
||||
livelyNodesList.add(pair)
|
||||
}
|
||||
|
||||
notifyThroughputsChanged()
|
||||
}
|
||||
@ -622,98 +634,97 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
||||
var residue = howMuch.coerceAtMost(fromNode.energyThroughput)
|
||||
val snapshot = Reference2ObjectOpenHashMap<Segment, Decimal>()
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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<WorkerEnergyStorage> = 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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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<T : Mob>(context: EntityRendererProvider.Context, private val entityType: EntityType<T>, private val androidTexture: String) :
|
||||
class RogueAndroidRenderer<T : Mob>(context: EntityRendererProvider.Context, private val entityType: EntityType<T>, private val androidTexture: String,private val modelManager: ModelManager) :
|
||||
HumanoidMobRenderer<T, PlayerModel<T>>(
|
||||
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")
|
||||
}
|
||||
|
@ -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<T : MatteryMenu>(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
|
||||
}
|
||||
|
@ -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<AndroidChargerMenu>(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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -188,17 +188,20 @@ fun <T : Enum<T>> T.prev(values: Array<out T>): 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 <T> MutableList<T>.shuffle(random: RandomSource) {
|
||||
return Util.shuffle(this, random)
|
||||
fun <T, L : MutableList<T>> L.shuffle(random: RandomSource): L {
|
||||
Util.shuffle(this, random)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T> List<T>.random(random: RandomGenerator): T {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<AndroidMelee>, 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<AndroidMelee>, 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<AndroidMelee>, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<BreadMonster>, 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))
|
||||
|
@ -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<Loader>, 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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<ItemStack>): 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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user