Revamp job event loops, move jobs to codecs
Add PatternState codecs Add ReplicationTask codecs Instead of returning job status on job tick, now downstream code directly update status of provided job status object Make Matter Replicator and Matter Recycler not do full stop when there is not enough matter/nowhere to put matter
This commit is contained in:
parent
d4fb6d0b24
commit
8a78b299c5
@ -1,114 +1,229 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import com.mojang.datafixers.Products
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.core.math.weakEqualDoubles
|
||||
import ru.dbotthepony.mc.otm.core.math.weakGreaterThan
|
||||
import ru.dbotthepony.mc.otm.core.math.weakLessThan
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.minRange
|
||||
|
||||
private fun isReason(status: Any?, reason: Any) = status == null || status == reason
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
interface IMachineJob {
|
||||
interface IJob {
|
||||
val ticks: Double
|
||||
val powerUsage: Decimal
|
||||
val experience: Float get() = 0f
|
||||
|
||||
fun serializeNBT(): CompoundTag
|
||||
}
|
||||
|
||||
open class MachineJob : IMachineJob {
|
||||
final override val ticks: Double
|
||||
final override val powerUsage: Decimal
|
||||
final override val experience: Float
|
||||
|
||||
constructor(
|
||||
ticks: Double,
|
||||
powerUsage: Decimal = Decimal.ZERO,
|
||||
experience: Float = 0f,
|
||||
) {
|
||||
this.ticks = ticks
|
||||
this.powerUsage = powerUsage
|
||||
this.experience = experience
|
||||
open class Job(
|
||||
final override val ticks: Double,
|
||||
final override val powerUsage: Decimal = Decimal.ZERO,
|
||||
final override val experience: Float = 0f
|
||||
) : IJob {
|
||||
companion object {
|
||||
fun <T : Job> basicCodec(builder: RecordCodecBuilder.Instance<T>): Products.P3<RecordCodecBuilder.Mu<T>, Double, Decimal, Float> {
|
||||
return builder.group(
|
||||
Codec.doubleRange(0.0, Double.MAX_VALUE).fieldOf("ticks").forGetter(Job::ticks),
|
||||
DecimalCodec.fieldOf("powerUsage").forGetter(Job::powerUsage), // не надо указывать минимальную энергию как 0,
|
||||
// ибо мы можем таким образом использовать это для создания работ генератора
|
||||
Codec.floatRange(0f, Float.MAX_VALUE).optionalFieldOf("experience", 0f).forGetter(Job::experience),
|
||||
)
|
||||
}
|
||||
|
||||
constructor(
|
||||
tag: CompoundTag
|
||||
) : this(tag.getDouble("Ticks"), tag.getDecimal("EnergyUsage"), tag.getFloat("Experience"))
|
||||
fun <T : Job> plainCodec(builder: RecordCodecBuilder.Instance<T>): Products.P2<RecordCodecBuilder.Mu<T>, Double, Decimal> {
|
||||
return builder.group(
|
||||
Codec.doubleRange(0.0, Double.MAX_VALUE).fieldOf("ticks").forGetter(Job::ticks),
|
||||
DecimalCodec.fieldOf("powerUsage").forGetter(Job::powerUsage), // не надо указывать минимальную энергию как 0,
|
||||
// ибо мы можем таким образом использовать это для создания работ генератора
|
||||
)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["Ticks"] = ticks
|
||||
it["EnergyUsage"] = powerUsage
|
||||
it["Experience"] = experience
|
||||
val CODEC: Codec<Job> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
basicCodec(it).apply(it, ::Job)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class MachineItemJob : MachineJob {
|
||||
val itemStack: ItemStack
|
||||
|
||||
constructor(
|
||||
itemStack: ItemStack,
|
||||
open class ItemJob(
|
||||
val itemStack: ItemStack,
|
||||
ticks: Double,
|
||||
power: Decimal = Decimal.ZERO,
|
||||
experience: Float = 0f,
|
||||
) : super(ticks, power, experience) {
|
||||
this.itemStack = itemStack
|
||||
experience: Float = 0f
|
||||
) : Job(ticks, power, experience) {
|
||||
companion object {
|
||||
fun <T : ItemJob> itemCodec(builder: RecordCodecBuilder.Instance<T>): Products.P4<RecordCodecBuilder.Mu<T>, ItemStack, Double, Decimal, Float> {
|
||||
return builder.group(ItemStack.CODEC.fieldOf("itemStack").forGetter(ItemJob::itemStack)).and(basicCodec(builder))
|
||||
}
|
||||
|
||||
constructor(
|
||||
tag: CompoundTag
|
||||
) : super(tag) {
|
||||
this.itemStack = (tag["Item"] as? CompoundTag)?.let { ItemStack.of(it) } ?: ItemStack.EMPTY
|
||||
val CODEC: Codec<ItemJob> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
itemCodec(it).apply(it, ::ItemJob)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return super.serializeNBT().also {
|
||||
it["Item"] = itemStack.serializeNBT()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class JobStatus(
|
||||
val success: Boolean,
|
||||
val throttleTicks: Int = 0,
|
||||
val idleReason: MachineJobEventLoop.IdleReason? = null,
|
||||
val newDrainedPower: Decimal? = null
|
||||
) {
|
||||
init {
|
||||
require(throttleTicks >= 0) { "Negative amount of ticks to throttle: $throttleTicks" }
|
||||
class JobStatus<T : IJob>(
|
||||
var requiredPower: Decimal,
|
||||
val extractedPower: Decimal,
|
||||
ticksAdvanced: Double,
|
||||
val job: T,
|
||||
val workTicks: Double,
|
||||
) : IJob by job {
|
||||
constructor(job: T, workTicks: Double) : this(Decimal.ZERO, Decimal.ZERO, 0.0, job, workTicks)
|
||||
|
||||
val workProgress: Float
|
||||
get() {
|
||||
return ((workTicks + workTicks) / job.ticks).coerceAtMost(1.0).toFloat()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SUCCESS = JobStatus(true)
|
||||
val FAILURE = JobStatus(false)
|
||||
val FAILURE_ITEM = JobStatus(false, 20, MachineJobEventLoop.IdleReason.ITEM)
|
||||
val FAILURE_MATTER = JobStatus(false, 20, MachineJobEventLoop.IdleReason.MATTER)
|
||||
val FAILURE_WAIT = JobStatus(false, 100)
|
||||
val FAILURE_WAIT_FAST = JobStatus(false, 20)
|
||||
var success = true
|
||||
|
||||
var ticksAdvanced = ticksAdvanced
|
||||
set(value) {
|
||||
require(value >= 0.0) { "Invalid amount of ticks to advance: $value" }
|
||||
field = value
|
||||
}
|
||||
|
||||
var throttleTicks = 0
|
||||
set(value) {
|
||||
require(value >= 0) { "Invalid amount of ticks to throttle: $value" }
|
||||
if (value != 0) success = false
|
||||
field = value
|
||||
}
|
||||
|
||||
var idleReason: Any? = null
|
||||
set(value) {
|
||||
if (value != null) success = false
|
||||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* You don't have to actually call this, JobStatus is in this state by default
|
||||
*
|
||||
* But this is handy to call this when doing early returns, to clearly state that "we are in success"
|
||||
*/
|
||||
fun success() {
|
||||
this.success = true
|
||||
this.throttleTicks = 0
|
||||
this.idleReason = null
|
||||
}
|
||||
|
||||
fun throttle() {
|
||||
this.success = false
|
||||
this.throttleTicks = 100
|
||||
}
|
||||
|
||||
fun throttleFast() {
|
||||
this.success = false
|
||||
this.throttleTicks = 20
|
||||
}
|
||||
|
||||
fun noItem(throttleTicks: Int = 20) {
|
||||
this.success = false
|
||||
idleReason = MachineJobEventLoop.IdleReason.ITEM
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun noPower(throttleTicks: Int = 20) {
|
||||
this.success = false
|
||||
idleReason = MachineJobEventLoop.IdleReason.POWER
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun noMatter(throttleTicks: Int = 20) {
|
||||
this.success = false
|
||||
idleReason = MachineJobEventLoop.IdleReason.MATTER
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun noPattern(throttleTicks: Int = 20) {
|
||||
this.success = false
|
||||
idleReason = MachineJobEventLoop.IdleReason.PATTERN
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun observe(throttleTicks: Int = 20) {
|
||||
this.success = false
|
||||
idleReason = MachineJobEventLoop.IdleReason.OBSERVING
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun failure(reason: Any) {
|
||||
this.success = false
|
||||
idleReason = reason
|
||||
}
|
||||
|
||||
fun failure(throttleTicks: Int = 0) {
|
||||
this.success = false
|
||||
this.throttleTicks = throttleTicks
|
||||
}
|
||||
|
||||
fun scale(value: Decimal) {
|
||||
require(value >= Decimal.ZERO) { "Attempted to scale by negative value: $value" }
|
||||
if (value == Decimal.ONE)
|
||||
return
|
||||
|
||||
if (value.isZero) {
|
||||
ticksAdvanced = 0.0
|
||||
requiredPower = Decimal.ZERO
|
||||
success = false
|
||||
} else {
|
||||
requiredPower *= value
|
||||
ticksAdvanced *= value.toDouble()
|
||||
}
|
||||
}
|
||||
|
||||
fun scale(value: Double) {
|
||||
require(value >= 0.0) { "Attempted to scale by negative value: $value" }
|
||||
if (value == 1.0)
|
||||
return
|
||||
|
||||
if (value == 0.0) {
|
||||
ticksAdvanced = 0.0
|
||||
requiredPower = Decimal.ZERO
|
||||
success = false
|
||||
} else {
|
||||
requiredPower *= value
|
||||
ticksAdvanced *= value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class JobContainer<JobType : IMachineJob>(val job: JobType? = null, val idleReason: Any? = null, val throttleTicks: Int = 0) {
|
||||
data class JobContainer<JobType : IJob>(val job: JobType? = null, val idleReason: Any? = null, val throttleTicks: Int = 0) {
|
||||
init {
|
||||
require(throttleTicks >= 0) { "Negative amount of ticks to throttle: $throttleTicks" }
|
||||
|
||||
if (job != null && idleReason != null) {
|
||||
throw IllegalArgumentException("Can't have both job and idle reason specified")
|
||||
}
|
||||
|
||||
if (job != null && throttleTicks != 0) {
|
||||
throw IllegalArgumentException("Can't have both job and throttle ticks specified")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <JobType : IMachineJob> success(job: JobType): JobContainer<JobType> {
|
||||
fun <JobType : IJob> success(job: JobType): JobContainer<JobType> {
|
||||
return JobContainer(job, null)
|
||||
}
|
||||
|
||||
fun <JobType : IMachineJob> failure(reason: Any?): JobContainer<JobType> {
|
||||
fun <JobType : IJob> failure(reason: Any?): JobContainer<JobType> {
|
||||
return JobContainer(null, reason)
|
||||
}
|
||||
|
||||
@ -120,41 +235,40 @@ data class JobContainer<JobType : IMachineJob>(val job: JobType? = null, val idl
|
||||
private val observe = JobContainer(null, MachineJobEventLoop.IdleReason.OBSERVING)
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> failure(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> failure(): JobContainer<JobType> {
|
||||
return empty as JobContainer<JobType>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> noItem(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> noItem(): JobContainer<JobType> {
|
||||
return noItem as JobContainer<JobType>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> noEnergy(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> noEnergy(): JobContainer<JobType> {
|
||||
return noEnergy as JobContainer<JobType>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> noMatter(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> noMatter(): JobContainer<JobType> {
|
||||
return noMatter as JobContainer<JobType>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> noPattern(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> noPattern(): JobContainer<JobType> {
|
||||
return noPattern as JobContainer<JobType>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
fun <JobType : IMachineJob> observe(): JobContainer<JobType> {
|
||||
fun <JobType : IJob> observe(): JobContainer<JobType> {
|
||||
return observe as JobContainer<JobType>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<CompoundTag?> {
|
||||
abstract class MachineJobEventLoop<JobType : IJob>(val codec: Codec<JobType>) : INBTSerializable<CompoundTag?> {
|
||||
protected abstract val energy: IMatteryEnergyStorage?
|
||||
protected abstract val isBlockedByRedstone: Boolean
|
||||
protected abstract fun deserializeJob(nbt: CompoundTag): JobType?
|
||||
protected abstract val upgrades: IMatteryUpgrade?
|
||||
|
||||
var currentJob: JobType? = null
|
||||
@ -212,7 +326,17 @@ abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<Com
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also { nbt ->
|
||||
nbt["WorkTicks"] = workTicks
|
||||
currentJob?.let { nbt["Job"] = it.serializeNBT() }
|
||||
|
||||
currentJob?.let {
|
||||
codec.encode(it, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map(
|
||||
{
|
||||
nbt["Job"] = it
|
||||
},
|
||||
{
|
||||
LOGGER.error("Failed to serialize job data, it will not persist", RuntimeException(it.message()))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,27 +344,36 @@ abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<Com
|
||||
nbt ?: return
|
||||
|
||||
workTicks = nbt.getDouble("WorkTicks")
|
||||
currentJob = nbt.map("Job", ::deserializeJob)
|
||||
currentJob = null
|
||||
|
||||
if ("Job" in nbt) {
|
||||
codec.decode(NbtOps.INSTANCE, nbt["Job"]!!).get().map(
|
||||
{
|
||||
currentJob = it.first
|
||||
},
|
||||
{
|
||||
LOGGER.error("Failed to deserialize job data from storage", RuntimeException(it.message()))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (currentJob == null)
|
||||
workTicks = 0.0
|
||||
}
|
||||
|
||||
protected abstract fun jobUpdated(new: JobType?, old: JobType?)
|
||||
protected open fun jobUpdated(new: JobType?, old: JobType?) {}
|
||||
|
||||
/**
|
||||
* Called whenever reaching desired amount of ticks at job
|
||||
*/
|
||||
protected abstract fun onJobFinish(job: JobType): JobStatus
|
||||
protected abstract fun onJobFinish(status: JobStatus<JobType>)
|
||||
|
||||
/**
|
||||
* Called when there is nothing to do and we are not idling
|
||||
*/
|
||||
protected abstract fun computeNextJob(): JobContainer<JobType>
|
||||
|
||||
protected open fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: JobType): JobStatus {
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
protected open fun onJobTick(status: JobStatus<JobType>) {}
|
||||
|
||||
/**
|
||||
* Advances job loop by specified [ticks]. If machine is speed up by upgrades,
|
||||
@ -317,8 +450,11 @@ abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<Com
|
||||
if (requiredPower.isPositive) {
|
||||
extractedPower = energy!!.extractEnergy(requiredPower, true)
|
||||
ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceIn(0.0, 1.0) * ticksLeft
|
||||
} else {
|
||||
} else if (requiredPower.isZero) {
|
||||
ticksAdvanced = ticksLeft
|
||||
} else {
|
||||
extractedPower = -energy!!.receiveEnergy(-requiredPower, true)
|
||||
ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceIn(0.0, 1.0) * ticksLeft
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,7 +462,8 @@ abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<Com
|
||||
break
|
||||
}
|
||||
|
||||
val status = onWorkTick(requiredPower ?: Decimal.ZERO, extractedPower ?: Decimal.ZERO, ticksAdvanced, currentJob)
|
||||
val status = JobStatus(requiredPower ?: Decimal.ZERO, extractedPower ?: Decimal.ZERO, ticksAdvanced, currentJob, workTicks)
|
||||
onJobTick(status)
|
||||
|
||||
if (!status.success) {
|
||||
throttleTicks += status.throttleTicks
|
||||
@ -336,25 +473,31 @@ abstract class MachineJobEventLoop<JobType : IMachineJob> : INBTSerializable<Com
|
||||
isIdling = true
|
||||
}
|
||||
|
||||
break
|
||||
} else if (status.requiredPower.isPositive && energy == null) {
|
||||
idleReason = IdleReason.POWER
|
||||
isIdling = true
|
||||
idleTicksAnim++
|
||||
break
|
||||
}
|
||||
|
||||
workingTicksAnim++
|
||||
errorTicksAnim = 0
|
||||
|
||||
workTicks += ticksAdvanced
|
||||
availableTicks -= ticksAdvanced
|
||||
workTicks += status.ticksAdvanced
|
||||
availableTicks -= status.ticksAdvanced
|
||||
|
||||
extractedPower = status.newDrainedPower ?: extractedPower
|
||||
|
||||
if (extractedPower != null) {
|
||||
energy!!.extractEnergy(extractedPower, false)
|
||||
if (energy != null && status.requiredPower.isPositive) {
|
||||
energy.extractEnergy(status.requiredPower, false)
|
||||
} else if (energy != null && status.requiredPower.isNegative) {
|
||||
energy.receiveEnergy(-status.requiredPower, false)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
val status = onJobFinish(currentJob)
|
||||
val status = JobStatus(currentJob, workTicks)
|
||||
onJobFinish(status)
|
||||
|
||||
if (status.success) {
|
||||
this.currentJob = null
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
@ -11,12 +12,12 @@ import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matteryEnergy
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
|
||||
@ -25,15 +26,15 @@ import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
*
|
||||
* From technical point, this is a specialized use case of [MachineJobEventLoop].
|
||||
*/
|
||||
abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
||||
abstract class MatteryWorkerBlockEntity<JobType : IJob>(
|
||||
type: BlockEntityType<*>,
|
||||
blockPos: BlockPos,
|
||||
blockState: BlockState,
|
||||
val jobDeserializer: (tag: CompoundTag) -> JobType?,
|
||||
jobCodec: Codec<JobType>,
|
||||
maxJobs: Int = 1,
|
||||
) : MatteryPoweredBlockEntity(type, blockPos, blockState) {
|
||||
val jobEventLoops: ImmutableList<MachineJobEventLoop<JobType>> = immutableList(maxJobs) { id ->
|
||||
object : MachineJobEventLoop<JobType>() {
|
||||
object : MachineJobEventLoop<JobType>(jobCodec) {
|
||||
override val energy: IMatteryEnergyStorage?
|
||||
get() = matteryEnergy
|
||||
override val isBlockedByRedstone: Boolean
|
||||
@ -41,12 +42,8 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
||||
override val upgrades: IMatteryUpgrade?
|
||||
get() = this@MatteryWorkerBlockEntity.upgrades
|
||||
|
||||
override fun deserializeJob(nbt: CompoundTag): JobType? {
|
||||
return jobDeserializer.invoke(nbt)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: JobType): JobStatus {
|
||||
return this@MatteryWorkerBlockEntity.onJobFinish(job, id)
|
||||
override fun onJobFinish(status: JobStatus<JobType>) {
|
||||
return this@MatteryWorkerBlockEntity.onJobFinish(status, id)
|
||||
}
|
||||
|
||||
override fun computeNextJob(): JobContainer<JobType> {
|
||||
@ -57,8 +54,8 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
||||
this@MatteryWorkerBlockEntity.jobUpdated(new, old, id)
|
||||
}
|
||||
|
||||
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: JobType): JobStatus {
|
||||
return this@MatteryWorkerBlockEntity.onWorkTick(requiredPower, extractedPower, ticksAdvanced, job, id)
|
||||
override fun onJobTick(status: JobStatus<JobType>) {
|
||||
return this@MatteryWorkerBlockEntity.onJobTick(status, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,12 +69,10 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
||||
}
|
||||
|
||||
protected open fun jobUpdated(new: JobType?, old: JobType?, id: Int) {}
|
||||
protected abstract fun onJobFinish(job: JobType, id: Int): JobStatus
|
||||
protected abstract fun onJobFinish(status: JobStatus<JobType>, id: Int)
|
||||
protected abstract fun computeNextJob(id: Int): JobContainer<JobType>
|
||||
|
||||
protected open fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: JobType, id: Int): JobStatus {
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
protected open fun onJobTick(status: JobStatus<JobType>, id: Int) {}
|
||||
|
||||
override fun saveShared(nbt: CompoundTag) {
|
||||
super.saveShared(nbt)
|
||||
@ -148,6 +143,8 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
fun appendHoverText(itemStack: ItemStack, blockGetter: BlockGetter?, tooltips: MutableList<Component>, flag: TooltipFlag) {
|
||||
itemStack.tag ?: return
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
@ -11,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeConfigSpec
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.Job
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
@ -30,6 +32,8 @@ import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.minRange
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
|
||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||
import ru.dbotthepony.mc.otm.item.matter.MatterDustItem
|
||||
@ -93,32 +97,23 @@ fun moveMatterAsDustIntoContainer(_matterValue: Decimal, container: MatteryConta
|
||||
}
|
||||
|
||||
class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
|
||||
: MatteryWorkerBlockEntity<MatterDecomposerBlockEntity.DecomposerJob>(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob) {
|
||||
|
||||
class DecomposerJob : MachineJob {
|
||||
val toDust: Boolean
|
||||
var matterValue: Decimal
|
||||
|
||||
constructor(tag: CompoundTag) : super(tag) {
|
||||
toDust = tag.getBoolean(TO_DUST_KEY)
|
||||
matterValue = tag.getDecimal(MATTER_VALUE_KEY)
|
||||
}
|
||||
|
||||
constructor(toDust: Boolean, matterValue: Decimal, ticks: Double) : super(ticks, BASE_CONSUMPTION) {
|
||||
this.toDust = toDust
|
||||
this.matterValue = matterValue
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return super.serializeNBT().also {
|
||||
it[TO_DUST_KEY] = toDust
|
||||
it[MATTER_VALUE_KEY] = matterValue
|
||||
}
|
||||
}
|
||||
: MatteryWorkerBlockEntity<MatterDecomposerBlockEntity.DecomposerJob>(MBlockEntities.MATTER_DECOMPOSER, pos, state, DecomposerJob.CODEC) {
|
||||
|
||||
class DecomposerJob(
|
||||
val toDust: Boolean,
|
||||
var matterValue: Decimal,
|
||||
ticks: Double,
|
||||
) : Job(ticks, BASE_CONSUMPTION) {
|
||||
companion object {
|
||||
const val TO_DUST_KEY = "toDust"
|
||||
const val MATTER_VALUE_KEY = "matterValue"
|
||||
val CODEC: Codec<DecomposerJob> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
Codec.BOOL.fieldOf("toDust").forGetter(DecomposerJob::toDust),
|
||||
DecimalCodec.minRange(Decimal.ZERO).fieldOf("matterValue").forGetter(DecomposerJob::matterValue),
|
||||
Codec.DOUBLE.minRange(0.0).fieldOf("ticks").forGetter(DecomposerJob::ticks)
|
||||
).apply(it, ::DecomposerJob)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,22 +160,18 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
|
||||
return MatterDecomposerMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: DecomposerJob, id: Int): JobStatus {
|
||||
if (job.toDust) {
|
||||
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, outputContainer, 0, 1)
|
||||
override fun onJobFinish(status: JobStatus<DecomposerJob>, id: Int) {
|
||||
if (status.job.toDust) {
|
||||
status.job.matterValue = moveMatterAsDustIntoContainer(status.job.matterValue, outputContainer, 0, 1)
|
||||
|
||||
if (!job.matterValue.isZero)
|
||||
return JobStatus.FAILURE_WAIT_FAST
|
||||
if (!status.job.matterValue.isZero)
|
||||
status.throttleFast()
|
||||
} else {
|
||||
status.job.matterValue -= matter.receiveMatter(status.job.matterValue, false)
|
||||
|
||||
return JobStatus.SUCCESS
|
||||
if (status.job.matterValue.isPositive)
|
||||
status.noMatter()
|
||||
}
|
||||
|
||||
job.matterValue -= matter.receiveMatter(job.matterValue, false)
|
||||
|
||||
if (job.matterValue.isPositive)
|
||||
return JobStatus.FAILURE_MATTER
|
||||
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<DecomposerJob> {
|
||||
|
@ -9,8 +9,6 @@ import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import java.util.HashMap
|
||||
import java.util.UUID
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@ -29,7 +27,7 @@ import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
import java.util.stream.Stream
|
||||
|
||||
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
@ -100,7 +98,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
|
||||
for ((key, task) in _tasks) {
|
||||
if (task.required > 0) {
|
||||
val pattern = task.patternId?.let(graph::getPattern) ?: continue
|
||||
val pattern = task.patternId.map(graph::getPattern).orElse(null) ?: continue
|
||||
|
||||
if (!simulate) {
|
||||
val new = task.allocate()
|
||||
@ -198,7 +196,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
}
|
||||
|
||||
fun addTask(state: IPatternState, count: Int): IReplicationTask<*> {
|
||||
val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count)
|
||||
val task = ReplicationTask(UUID.randomUUID(), Optional.of(state.id), state.item, 0, 0, count)
|
||||
_tasks[task.id] = task
|
||||
|
||||
matterNode.graph.onMatterTaskCreated(task)
|
||||
|
@ -1,22 +1,19 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeConfigSpec
|
||||
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineJob
|
||||
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
|
||||
import ru.dbotthepony.mc.otm.block.entity.Job
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
@ -30,40 +27,20 @@ import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
|
||||
import ru.dbotthepony.mc.otm.item.matter.MatterDustItem
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
|
||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.minRange
|
||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||
|
||||
class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
: MatteryWorkerBlockEntity<MatterRecyclerBlockEntity.RecyclerJob>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::RecyclerJob) {
|
||||
|
||||
class RecyclerJob : MachineJob {
|
||||
var totalMatter: Decimal
|
||||
|
||||
constructor(
|
||||
ticks: Double,
|
||||
powerUsage: Decimal,
|
||||
totalMatter: Decimal
|
||||
) : super(ticks, powerUsage) {
|
||||
this.totalMatter = totalMatter
|
||||
}
|
||||
|
||||
constructor(tag: CompoundTag) : super(tag) {
|
||||
this.totalMatter = tag.getDecimal(KEY)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return super.serializeNBT().also {
|
||||
it[KEY] = totalMatter
|
||||
}
|
||||
}
|
||||
: MatteryWorkerBlockEntity<MatterRecyclerBlockEntity.RecyclerJob>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, RecyclerJob.CODEC) {
|
||||
|
||||
class RecyclerJob(ticks: Double, powerUsage: Decimal, var totalMatter: Decimal) : Job(ticks, powerUsage) {
|
||||
companion object {
|
||||
const val KEY = "totalMatter"
|
||||
val CODEC: Codec<RecyclerJob> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
plainCodec(it).and(DecimalCodec.minRange(Decimal.ZERO).fieldOf("totalMatter").forGetter(RecyclerJob::totalMatter)).apply(it, ::RecyclerJob)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,18 +85,18 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
return MatterRecyclerMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: RecyclerJob, id: Int): JobStatus {
|
||||
override fun onJobFinish(status: JobStatus<RecyclerJob>, id: Int) {
|
||||
val job = status.job
|
||||
|
||||
if (job.totalMatter.isPositive) {
|
||||
val received = matter.receiveMatter(job.totalMatter, true)
|
||||
|
||||
if (job.totalMatter != received)
|
||||
return JobStatus.FAILURE_MATTER
|
||||
return status.noMatter()
|
||||
|
||||
matter.receiveMatter(job.totalMatter, false)
|
||||
job.totalMatter -= received
|
||||
}
|
||||
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<RecyclerJob> {
|
||||
@ -147,20 +124,16 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: RecyclerJob, id: Int): JobStatus {
|
||||
val receive = job.totalMatter.coerceAtMost(MachinesConfig.MATTER_RECYCLER_MATTER_PER_TICK.get() * ticksAdvanced)
|
||||
override fun onJobTick(status: JobStatus<RecyclerJob>, id: Int) {
|
||||
val job = status.job
|
||||
val toReceive = job.totalMatter.coerceAtMost(MachinesConfig.MATTER_RECYCLER_MATTER_PER_TICK.get() * status.ticksAdvanced)
|
||||
|
||||
if (receive.isZero)
|
||||
return JobStatus.SUCCESS
|
||||
if (toReceive.isZero)
|
||||
return status.success()
|
||||
|
||||
val received = matter.receiveMatter(receive, true)
|
||||
|
||||
if (receive != received)
|
||||
return JobStatus.FAILURE_MATTER
|
||||
|
||||
matter.receiveMatter(receive, false)
|
||||
val received = matter.receiveMatter(toReceive, false)
|
||||
status.scale(received / toReceive)
|
||||
job.totalMatter -= received
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
@ -11,7 +12,7 @@ import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeConfigSpec
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineJobEventLoop
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
@ -28,76 +29,43 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
|
||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.UUIDCodec
|
||||
import ru.dbotthepony.mc.otm.data.minRange
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
||||
import ru.dbotthepony.mc.otm.matter.MatterManager
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterReplicatorMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import java.util.*
|
||||
|
||||
class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
MatteryWorkerBlockEntity<MatterReplicatorBlockEntity.ReplicatorJob>(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, {
|
||||
try {
|
||||
ReplicatorJob(it)
|
||||
} catch(err: NoSuchElementException) {
|
||||
null
|
||||
}
|
||||
}) {
|
||||
MatteryWorkerBlockEntity<MatterReplicatorBlockEntity.ReplicatorJob>(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, ReplicatorJob.CODEC) {
|
||||
|
||||
class ReplicatorJob : MachineItemJob {
|
||||
val matterPerTick: Decimal
|
||||
val task: ReplicationTask
|
||||
var matterValue: Decimal
|
||||
val pattern: PatternState?
|
||||
val asDust: Boolean
|
||||
|
||||
constructor(tag: CompoundTag) : super(tag) {
|
||||
matterPerTick = tag.getDecimal(MATTER_PER_TICK_KEY)
|
||||
matterValue = tag.getDecimal(MATTER_VALUE_KEY)
|
||||
pattern = tag.map(PATTERN_KEY, PatternState::deserializeNBT)
|
||||
asDust = tag.getBoolean(AS_DUST_KEY)
|
||||
task = tag.map(TASK_KEY, ReplicationTask::deserializeNBT) ?: throw NoSuchElementException("Unable to deserialize matter task")
|
||||
}
|
||||
|
||||
constructor(
|
||||
class ReplicatorJob(
|
||||
itemStack: ItemStack,
|
||||
matterPerTick: Decimal,
|
||||
task: ReplicationTask,
|
||||
matterValue: Decimal,
|
||||
pattern: PatternState?,
|
||||
asDust: Boolean,
|
||||
val matterPerTick: Decimal,
|
||||
val task: UUID,
|
||||
var matterValue: Decimal,
|
||||
val pattern: Optional<PatternState>,
|
||||
val asDust: Boolean,
|
||||
ticks: Double,
|
||||
) : super(itemStack, ticks, BASE_CONSUMPTION) {
|
||||
this.matterPerTick = matterPerTick
|
||||
this.task = task
|
||||
this.matterValue = matterValue
|
||||
this.pattern = pattern
|
||||
this.asDust = asDust
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return super.serializeNBT().also {
|
||||
it[MATTER_PER_TICK_KEY] = this.matterPerTick
|
||||
it[TASK_KEY] = this.task.serializeNBT()
|
||||
it[MATTER_VALUE_KEY] = this.matterValue
|
||||
|
||||
if (this.pattern != null)
|
||||
it[PATTERN_KEY] = this.pattern.serializeNBT()
|
||||
|
||||
it[AS_DUST_KEY] = this.asDust
|
||||
}
|
||||
}
|
||||
|
||||
) : ItemJob(itemStack, ticks, BASE_CONSUMPTION) {
|
||||
companion object {
|
||||
const val MATTER_PER_TICK_KEY = "matterPerTick"
|
||||
const val MATTER_VALUE_KEY = "matterValue"
|
||||
const val PATTERN_KEY = "pattern"
|
||||
const val AS_DUST_KEY = "asDust"
|
||||
const val TASK_KEY = "task"
|
||||
val CODEC: Codec<ReplicatorJob> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
ItemStack.CODEC.fieldOf("itemStack").forGetter(ReplicatorJob::itemStack),
|
||||
DecimalCodec.minRange(Decimal.ZERO).fieldOf("matterPerTick").forGetter(ReplicatorJob::matterPerTick),
|
||||
UUIDCodec.fieldOf("task").forGetter(ReplicatorJob::task),
|
||||
DecimalCodec.minRange(Decimal.ZERO).fieldOf("matterValue").forGetter(ReplicatorJob::matterValue),
|
||||
PatternState.CODEC.optionalFieldOf("pattern").forGetter(ReplicatorJob::pattern),
|
||||
Codec.BOOL.fieldOf("asDust").forGetter(ReplicatorJob::asDust),
|
||||
Codec.doubleRange(0.0, Double.MAX_VALUE).fieldOf("ticks").forGetter(ReplicatorJob::ticks),
|
||||
).apply(it, ::ReplicatorJob)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,24 +109,24 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return MatterReplicatorMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: ReplicatorJob, id: Int): JobStatus {
|
||||
override fun onJobFinish(status: JobStatus<ReplicatorJob>, id: Int) {
|
||||
val job = status.job
|
||||
|
||||
if (job.asDust) {
|
||||
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
|
||||
|
||||
if (!job.matterValue.isZero) {
|
||||
return JobStatus.FAILURE_WAIT
|
||||
}
|
||||
|
||||
matterNode.graph.notifyTaskCompletion(job.task.id)
|
||||
return JobStatus.SUCCESS
|
||||
return status.throttle()
|
||||
}
|
||||
|
||||
matterNode.graph.notifyTaskCompletion(job.task)
|
||||
} else {
|
||||
if (!container.fullyAddItem(job.itemStack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) {
|
||||
return JobStatus.FAILURE_ITEM
|
||||
return status.noItem()
|
||||
}
|
||||
|
||||
matterNode.graph.notifyTaskCompletion(job.task.id)
|
||||
return JobStatus.SUCCESS
|
||||
matterNode.graph.notifyTaskCompletion(job.task)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
@ -211,64 +179,29 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return JobContainer.success(ReplicatorJob(
|
||||
itemStack = stack,
|
||||
matterPerTick = matter.matter / ticks,
|
||||
task = allocation.task.asImmutable(),
|
||||
task = allocation.task.id,
|
||||
matterValue = matter.matter,
|
||||
pattern = allocation.pattern?.asImmutable(),
|
||||
pattern = Optional.ofNullable(allocation.pattern?.asImmutable()),
|
||||
asDust = (level?.random?.nextDouble() ?: 1.0) * upgrades.failureMultiplier > (allocation.pattern?.researchPercent ?: 2.0),
|
||||
ticks = ticks,
|
||||
))
|
||||
}
|
||||
|
||||
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: ReplicatorJob, id: Int): JobStatus {
|
||||
val drainPerTick = job.matterPerTick * ticksAdvanced
|
||||
override fun onJobTick(status: JobStatus<ReplicatorJob>, id: Int) {
|
||||
val job = status.job
|
||||
val drainPerTick = job.matterPerTick * status.ticksAdvanced
|
||||
|
||||
if (matter.extractMatter(drainPerTick, true) < drainPerTick) {
|
||||
// в машине недостаточно материи
|
||||
|
||||
if (drainPerTick > matter.maxStoredMatter) {
|
||||
// в тик требуется больше материи, чем её может хранить репликатор
|
||||
val toExtract = drainPerTick - matter.extractMatter(drainPerTick, true)
|
||||
val drain = matterNode.graph.extractMatter(toExtract, true)
|
||||
|
||||
if (drain != toExtract) {
|
||||
// недостаточно материи в сети
|
||||
return JobStatus.FAILURE_MATTER
|
||||
}
|
||||
|
||||
// достаточно материи в сети + внутри машины
|
||||
matter.extractMatter(drainPerTick, false)
|
||||
matterNode.graph.extractMatter(drain, false)
|
||||
return JobStatus.SUCCESS
|
||||
} else {
|
||||
// в тик требуется меньше материи, чем её может хранить репликатор
|
||||
// примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше
|
||||
val drain = matterNode.graph.extractMatter((drainPerTick * DRAIN_MULT)
|
||||
.coerceAtMost(job.matterPerTick * (job.ticks - jobEventLoops[0].workTicks - ticksAdvanced))
|
||||
val toDrain = (drainPerTick * DRAIN_MULT)
|
||||
.coerceAtMost(job.matterPerTick * (status.ticks - status.workTicks + status.ticksAdvanced))
|
||||
.coerceAtLeast(Decimal.ONE)
|
||||
.coerceAtMost(matter.missingMatter), false)
|
||||
.coerceAtMost(matter.missingMatter)
|
||||
|
||||
if (drain.isZero) {
|
||||
// в сети нет материи
|
||||
return JobStatus.FAILURE_MATTER
|
||||
matter.receiveMatter(matterNode.graph.extractMatter(toDrain, false), false)
|
||||
}
|
||||
|
||||
matter.receiveMatter(drain, false)
|
||||
|
||||
// получили материю, проверяем возможность работы
|
||||
if (matter.extractMatter(drainPerTick, true) >= drainPerTick) {
|
||||
matter.extractMatter(drainPerTick, false)
|
||||
return JobStatus.SUCCESS
|
||||
} else {
|
||||
// :(
|
||||
return JobStatus.FAILURE_WAIT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// в машине достаточно материи
|
||||
matter.extractMatter(drainPerTick, false)
|
||||
visualProgress = jobEventLoops[0].workProgress
|
||||
return JobStatus.SUCCESS
|
||||
status.scale(matter.extractMatter(drainPerTick, false) / drainPerTick)
|
||||
visualProgress = status.workProgress
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -10,7 +10,7 @@ import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeConfigSpec
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineJobEventLoop
|
||||
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
@ -35,7 +35,7 @@ import java.util.*
|
||||
import kotlin.math.pow
|
||||
|
||||
class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
MatteryWorkerBlockEntity<MachineItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::MachineItemJob) {
|
||||
MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) {
|
||||
|
||||
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
|
||||
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, ENERGY_VALUES))
|
||||
@ -87,9 +87,9 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return MatterScannerMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: MachineItemJob, id: Int): JobStatus {
|
||||
val stack = job.itemStack
|
||||
if (stack.isEmpty || !MatterManager.hasMatterValue(stack)) return JobStatus.SUCCESS
|
||||
override fun onJobFinish(status: JobStatus<ItemJob>, id: Int) {
|
||||
val stack = status.job.itemStack
|
||||
if (stack.isEmpty || !MatterManager.hasMatterValue(stack)) return status.success()
|
||||
|
||||
var findState: IPatternState? = null
|
||||
|
||||
@ -110,14 +110,12 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
PatternState(UUID.randomUUID(), stack.item, researchAdvance)
|
||||
}
|
||||
|
||||
if (!matterNode.graph.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) {
|
||||
return JobStatus.SUCCESS
|
||||
} else {
|
||||
return JobStatus.FAILURE_WAIT
|
||||
if (matterNode.graph.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) {
|
||||
status.throttle()
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<MachineItemJob> {
|
||||
override fun computeNextJob(id: Int): JobContainer<ItemJob> {
|
||||
if (energy.batteryLevel.isZero) {
|
||||
return JobContainer.noEnergy()
|
||||
}
|
||||
@ -151,7 +149,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
stack.shrink(1)
|
||||
container.setChanged()
|
||||
val complexity = MatterManager.get(copy).complexity
|
||||
return JobContainer.success(MachineItemJob(copy, (if (complexity > 1.0) complexity.pow(1.25) else complexity.pow(0.5)), BASE_CONSUMPTION))
|
||||
return JobContainer.success(ItemJob(copy, (if (complexity > 1.0) complexity.pow(1.25) else complexity.pow(0.5)), BASE_CONSUMPTION))
|
||||
}
|
||||
|
||||
return JobContainer.noItem()
|
||||
@ -163,7 +161,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
}
|
||||
|
||||
|
||||
override fun jobUpdated(new: MachineItemJob?, old: MachineItemJob?, id: Int) {
|
||||
override fun jobUpdated(new: ItemJob?, old: ItemJob?, id: Int) {
|
||||
visualItemStack = new?.itemStack ?: ItemStack.EMPTY
|
||||
visualProgress = 0f
|
||||
}
|
||||
@ -174,14 +172,11 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
var visualProgress by synchronizer.float().property
|
||||
private set
|
||||
|
||||
override fun onWorkTick(
|
||||
requiredPower: Decimal,
|
||||
extractedPower: Decimal,
|
||||
ticksAdvanced: Double,
|
||||
job: MachineItemJob,
|
||||
override fun onJobTick(
|
||||
status: JobStatus<ItemJob>,
|
||||
id: Int
|
||||
): JobStatus {
|
||||
val result = super.onWorkTick(requiredPower, extractedPower, ticksAdvanced, job, id)
|
||||
) {
|
||||
val result = super.onJobTick(status, id)
|
||||
|
||||
visualProgress = jobEventLoops[0].workProgress
|
||||
|
||||
|
@ -7,7 +7,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
|
||||
class CobblerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
: MatteryWorkerBlockEntity<MachineItemJob>(MBlockEntities.COBBLESTONE_GENERATOR, blockPos, blockState, ::MachineItemJob) {
|
||||
: MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.COBBLESTONE_GENERATOR, blockPos, blockState, ItemJob.CODEC) {
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
return CobblerMenu(containerID, inventory, this)
|
||||
}
|
||||
@ -36,16 +36,14 @@ class CobblerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: MachineItemJob, id: Int): JobStatus {
|
||||
if (!container.fullyAddItem(job.itemStack)) {
|
||||
return JobStatus.FAILURE_ITEM
|
||||
override fun onJobFinish(status: JobStatus<ItemJob>, id: Int) {
|
||||
if (!container.fullyAddItem(status.job.itemStack)) {
|
||||
status.noItem()
|
||||
}
|
||||
}
|
||||
|
||||
return JobStatus.SUCCESS
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<MachineItemJob> {
|
||||
return JobContainer.success(MachineItemJob(ItemStack(Items.COBBLESTONE), 40.0))
|
||||
override fun computeNextJob(id: Int): JobContainer<ItemJob> {
|
||||
return JobContainer.success(ItemJob(ItemStack(Items.COBBLESTONE), 40.0))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -10,7 +10,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.UpgradeType
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.container.balance
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
@ -30,7 +29,7 @@ class PlatePressBlockEntity(
|
||||
p_155229_: BlockPos,
|
||||
p_155230_: BlockState,
|
||||
val isTwin: Boolean = false,
|
||||
) : MatteryWorkerBlockEntity<MachineItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ::MachineItemJob, if (isTwin) 2 else 1) {
|
||||
) : MatteryWorkerBlockEntity<ItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ItemJob.CODEC, if (isTwin) 2 else 1) {
|
||||
override val upgrades = UpgradeContainer(this::setChangedLight, if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING)
|
||||
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS)))
|
||||
val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer)
|
||||
@ -69,18 +68,17 @@ class PlatePressBlockEntity(
|
||||
return PlatePressMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: MachineItemJob, id: Int): JobStatus {
|
||||
if (job.itemStack.isEmpty)
|
||||
return JobStatus.SUCCESS
|
||||
override fun onJobFinish(status: JobStatus<ItemJob>, id: Int) {
|
||||
if (status.job.itemStack.isEmpty)
|
||||
return status.success()
|
||||
|
||||
if (!outputContainer.fullyAddItem(job.itemStack, start = id, end = id) && !outputContainer.fullyAddItem(job.itemStack))
|
||||
return JobStatus.FAILURE_ITEM
|
||||
if (!outputContainer.fullyAddItem(status.job.itemStack, start = id, end = id) && !outputContainer.fullyAddItem(status.job.itemStack))
|
||||
return status.noItem()
|
||||
|
||||
experience = (experience + job.experience).coerceAtMost(100.0)
|
||||
return JobStatus.SUCCESS
|
||||
experience = (experience + status.experience).coerceAtMost(100.0)
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<MachineItemJob> {
|
||||
override fun computeNextJob(id: Int): JobContainer<ItemJob> {
|
||||
if (energy.batteryLevel.isZero) {
|
||||
return JobContainer.noEnergy()
|
||||
}
|
||||
@ -101,7 +99,7 @@ class PlatePressBlockEntity(
|
||||
inputContainer.setChanged(id)
|
||||
|
||||
return JobContainer.success(
|
||||
MachineItemJob(
|
||||
ItemJob(
|
||||
recipe.getResultItem(level.registryAccess()).copyWithCount(toProcess),
|
||||
recipe.workTime * MachinesConfig.PLATE_PRESS.workTimeMultiplier,
|
||||
MachinesConfig.PLATE_PRESS.powerConsumption * toProcess,
|
||||
|
@ -3,19 +3,17 @@ package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.ExperienceOrb
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.crafting.AbstractCookingRecipe
|
||||
import net.minecraft.world.item.crafting.Recipe
|
||||
import net.minecraft.world.item.crafting.RecipeType
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.CombinedItemHandler
|
||||
import ru.dbotthepony.mc.otm.capability.UpgradeType
|
||||
@ -36,7 +34,7 @@ class PoweredFurnaceBlockEntity(
|
||||
blockState: BlockState,
|
||||
val recipeType: RecipeType<out AbstractCookingRecipe>,
|
||||
val config: WorkerBalanceValues
|
||||
) : MatteryWorkerBlockEntity<MachineItemJob>(type, blockPos, blockState, ::MachineItemJob, 2) {
|
||||
) : MatteryWorkerBlockEntity<ItemJob>(type, blockPos, blockState, ItemJob.CODEC, 2) {
|
||||
override val upgrades = UpgradeContainer(this::setChangedLight, 2, UpgradeType.BASIC_PROCESSING)
|
||||
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config)))
|
||||
|
||||
@ -86,16 +84,15 @@ class PoweredFurnaceBlockEntity(
|
||||
return PoweredFurnaceMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: MachineItemJob, id: Int): JobStatus {
|
||||
if (outputs[id].fullyAddItem(job.itemStack)) {
|
||||
experience += job.experience
|
||||
return JobStatus.SUCCESS
|
||||
override fun onJobFinish(status: JobStatus<ItemJob>, id: Int) {
|
||||
if (outputs[id].fullyAddItem(status.job.itemStack)) {
|
||||
experience += status.experience
|
||||
} else {
|
||||
status.noItem()
|
||||
}
|
||||
}
|
||||
|
||||
return JobStatus.FAILURE_ITEM
|
||||
}
|
||||
|
||||
override fun computeNextJob(id: Int): JobContainer<MachineItemJob> {
|
||||
override fun computeNextJob(id: Int): JobContainer<ItemJob> {
|
||||
if (!energy.batteryLevel.isPositive)
|
||||
return JobContainer.noEnergy()
|
||||
|
||||
@ -109,7 +106,7 @@ class PoweredFurnaceBlockEntity(
|
||||
val toProcess = inputs[id][0].count.coerceAtMost(upgrades.processingItems + 1)
|
||||
inputs[id][0].shrink(toProcess)
|
||||
|
||||
JobContainer.success(MachineItemJob(
|
||||
JobContainer.success(ItemJob(
|
||||
output.copyWithCount(toProcess), it.cookingTime * config.workTimeMultiplier, config.powerConsumption * toProcess, it.experience * toProcess
|
||||
))
|
||||
}.orElse(JobContainer.noItem())
|
||||
|
@ -63,7 +63,7 @@ import ru.dbotthepony.mc.otm.android.AndroidResearchManager
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineJobEventLoop
|
||||
import ru.dbotthepony.mc.otm.capability.energy.BatteryBackedEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
@ -411,33 +411,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
}).property
|
||||
|
||||
inner class SmelterBelt(index: Int) : MachineJobEventLoop<MachineItemJob>() {
|
||||
inner class SmelterBelt(index: Int) : MachineJobEventLoop<ItemJob>(ItemJob.CODEC) {
|
||||
override val energy: IMatteryEnergyStorage
|
||||
get() = exoPackEnergy
|
||||
override val isBlockedByRedstone: Boolean
|
||||
get() = false
|
||||
|
||||
override fun deserializeJob(nbt: CompoundTag): MachineItemJob {
|
||||
return MachineItemJob(nbt)
|
||||
}
|
||||
|
||||
override val upgrades: IMatteryUpgrade?
|
||||
get() = null
|
||||
|
||||
override fun jobUpdated(new: MachineItemJob?, old: MachineItemJob?) {}
|
||||
|
||||
override fun onJobFinish(job: MachineItemJob): JobStatus {
|
||||
if (output.fullyAddItem(job.itemStack)) {
|
||||
exoPackSmelterExperience += job.experience
|
||||
return JobStatus.SUCCESS
|
||||
override fun onJobFinish(status: JobStatus<ItemJob>) {
|
||||
if (output.fullyAddItem(status.job.itemStack)) {
|
||||
exoPackSmelterExperience += status.job.experience
|
||||
} else {
|
||||
return JobStatus.FAILURE_ITEM
|
||||
status.noItem()
|
||||
}
|
||||
}
|
||||
|
||||
private val cache = RecipeManager.createCheck(RecipeType.SMELTING)
|
||||
|
||||
override fun computeNextJob(): JobContainer<MachineItemJob> {
|
||||
override fun computeNextJob(): JobContainer<ItemJob> {
|
||||
if (!exoPackEnergy.batteryLevel.isPositive) return JobContainer.noEnergy()
|
||||
val level = ply.level() as? ServerLevel ?: return JobContainer.failure()
|
||||
val recipe = cache.getRecipeFor(input, level)
|
||||
@ -449,7 +442,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
val item = actual.assemble(input, level.registryAccess())
|
||||
input[0].shrink(1)
|
||||
input.setChanged(0)
|
||||
return JobContainer.success(MachineItemJob(item, actual.cookingTime.toDouble(), ExopackConfig.FURNACE_POWER_CONSUMPTION, actual.experience))
|
||||
return JobContainer.success(ItemJob(item, actual.cookingTime.toDouble(), ExopackConfig.FURNACE_POWER_CONSUMPTION, actual.experience))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.capability.matter
|
||||
|
||||
import com.mojang.datafixers.Products
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@ -11,6 +15,7 @@ import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.nbt.contains
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.data.UUIDCodec
|
||||
import java.util.*
|
||||
|
||||
sealed interface IPatternState {
|
||||
@ -45,13 +50,7 @@ sealed interface IPatternState {
|
||||
return ItemStack(item, count)
|
||||
}
|
||||
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["id"] = id
|
||||
it["item"] = item.registryName!!.toString()
|
||||
it["researchPercent"] = researchPercent
|
||||
}
|
||||
}
|
||||
fun serializeNBT(): CompoundTag
|
||||
|
||||
fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeUUID(id)
|
||||
@ -60,6 +59,14 @@ sealed interface IPatternState {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : IPatternState> codec(builder: RecordCodecBuilder.Instance<T>): Products.P3<RecordCodecBuilder.Mu<T>, UUID, Item, Double> {
|
||||
return builder.group(
|
||||
UUIDCodec.fieldOf("id").forGetter(IPatternState::id),
|
||||
ForgeRegistries.ITEMS.codec.fieldOf("item").forGetter(IPatternState::item),
|
||||
Codec.doubleRange(0.0, 1.0).fieldOf("researchPercent").forGetter(IPatternState::researchPercent)
|
||||
)
|
||||
}
|
||||
|
||||
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IPatternState? {
|
||||
if (nbt !is CompoundTag)
|
||||
return null
|
||||
@ -108,6 +115,10 @@ data class PatternState(
|
||||
return this
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CODEC.encode(this, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map({ it as CompoundTag }, { throw RuntimeException("Failed to serialize PatternState: ${it.message()}") })
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(tag: Tag?): PatternState? {
|
||||
return deserializeNBT(tag, false) as PatternState?
|
||||
@ -116,6 +127,12 @@ data class PatternState(
|
||||
fun read(buff: FriendlyByteBuf): PatternState? {
|
||||
return read(buff, false) as PatternState?
|
||||
}
|
||||
|
||||
val CODEC: Codec<PatternState> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
codec(it).apply(it, ::PatternState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +149,10 @@ data class MutablePatternState(
|
||||
return PatternState(id, item, researchPercent)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CODEC.encode(this, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map({ it as CompoundTag }, { throw RuntimeException("Failed to serialize MutablePatternState: ${it.message()}") })
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(tag: Tag?): MutablePatternState? {
|
||||
return deserializeNBT(tag, true) as MutablePatternState?
|
||||
@ -140,6 +161,12 @@ data class MutablePatternState(
|
||||
fun read(buff: FriendlyByteBuf): MutablePatternState? {
|
||||
return read(buff, true) as MutablePatternState?
|
||||
}
|
||||
|
||||
val CODEC: Codec<MutablePatternState> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
codec(it).apply(it, ::MutablePatternState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.capability.matter
|
||||
|
||||
import com.mojang.datafixers.Products
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@ -9,14 +13,14 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.core.readItemType
|
||||
import ru.dbotthepony.mc.otm.core.registryName
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.writeItemType
|
||||
import ru.dbotthepony.mc.otm.data.UUIDCodec
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
|
||||
sealed interface IReplicationTask<S : IReplicationTask<S>> {
|
||||
val id: UUID
|
||||
val patternId: UUID?
|
||||
val patternId: Optional<UUID>
|
||||
val item: Item
|
||||
val inProgress: Int
|
||||
val finished: Int
|
||||
@ -29,7 +33,7 @@ sealed interface IReplicationTask<S : IReplicationTask<S>> {
|
||||
|
||||
fun copyAsMutable(
|
||||
id: UUID = this.id,
|
||||
patternId: UUID? = this.patternId,
|
||||
patternId: Optional<UUID> = this.patternId,
|
||||
item: Item = this.item,
|
||||
inProgress: Int = this.inProgress,
|
||||
finished: Int = this.finished,
|
||||
@ -40,7 +44,7 @@ sealed interface IReplicationTask<S : IReplicationTask<S>> {
|
||||
|
||||
fun copyAsImmutable(
|
||||
id: UUID = this.id,
|
||||
patternId: UUID? = this.patternId,
|
||||
patternId: Optional<UUID> = this.patternId,
|
||||
item: Item = this.item,
|
||||
inProgress: Int = this.inProgress,
|
||||
finished: Int = this.finished,
|
||||
@ -60,25 +64,13 @@ sealed interface IReplicationTask<S : IReplicationTask<S>> {
|
||||
fun allocate(amount: Int = 1): S
|
||||
fun finish(amount: Int = 1): S
|
||||
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["id"] = id
|
||||
|
||||
if (patternId != null)
|
||||
it["patternId"] = patternId!!
|
||||
|
||||
it["item"] = item.registryName!!.toString()
|
||||
it["inProgress"] = inProgress
|
||||
it["finished"] = finished
|
||||
it["required"] = required
|
||||
}
|
||||
}
|
||||
fun serializeNBT(): CompoundTag
|
||||
|
||||
fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeUUID(id)
|
||||
|
||||
buff.writeBoolean(patternId != null)
|
||||
patternId?.let(buff::writeUUID)
|
||||
buff.writeBoolean(patternId.isPresent)
|
||||
patternId.ifPresent(buff::writeUUID)
|
||||
|
||||
buff.writeItemType(item)
|
||||
|
||||
@ -88,6 +80,17 @@ sealed interface IReplicationTask<S : IReplicationTask<S>> {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : IReplicationTask<T>> codec(builder: RecordCodecBuilder.Instance<T>): Products.P6<RecordCodecBuilder.Mu<T>, UUID, Optional<UUID>, Item, Int, Int, Int> {
|
||||
return builder.group(
|
||||
UUIDCodec.fieldOf("id").forGetter(IReplicationTask<*>::id),
|
||||
UUIDCodec.optionalFieldOf("patternId").forGetter(IReplicationTask<*>::patternId),
|
||||
ForgeRegistries.ITEMS.codec.fieldOf("item").forGetter(IReplicationTask<*>::item),
|
||||
Codec.intRange(0, Int.MAX_VALUE).fieldOf("inProgress").forGetter(IReplicationTask<*>::inProgress),
|
||||
Codec.intRange(0, Int.MAX_VALUE).fieldOf("finished").forGetter(IReplicationTask<*>::finished),
|
||||
Codec.intRange(0, Int.MAX_VALUE).fieldOf("required").forGetter(IReplicationTask<*>::required),
|
||||
)
|
||||
}
|
||||
|
||||
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IReplicationTask<*>? {
|
||||
if (nbt !is CompoundTag)
|
||||
return null
|
||||
@ -108,9 +111,9 @@ private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IReplicationTask<*>? {
|
||||
val required = nbt.getInt("required")
|
||||
|
||||
if (mutable) {
|
||||
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
|
||||
return MutableReplicationTask(id, Optional.ofNullable(patternId), item, inProgress, finished, required)
|
||||
} else {
|
||||
return ReplicationTask(id, patternId, item, inProgress, finished, required)
|
||||
return ReplicationTask(id, Optional.ofNullable(patternId), item, inProgress, finished, required)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,15 +128,15 @@ private fun read(buff: FriendlyByteBuf, mutable: Boolean): IReplicationTask<*>?
|
||||
item ?: return null
|
||||
|
||||
if (mutable) {
|
||||
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
|
||||
return MutableReplicationTask(id, Optional.ofNullable(patternId), item, inProgress, finished, required)
|
||||
} else {
|
||||
return ReplicationTask(id, patternId, item, inProgress, finished, required)
|
||||
return ReplicationTask(id, Optional.ofNullable(patternId), item, inProgress, finished, required)
|
||||
}
|
||||
}
|
||||
|
||||
data class ReplicationTask(
|
||||
override val id: UUID,
|
||||
override val patternId: UUID?,
|
||||
override val patternId: Optional<UUID>,
|
||||
override val item: Item,
|
||||
override val inProgress: Int,
|
||||
override val finished: Int,
|
||||
@ -155,6 +158,10 @@ data class ReplicationTask(
|
||||
return ReplicationTask(id, patternId, item, inProgress - amount, finished + amount, required)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CODEC.encode(this, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map({ it as CompoundTag }, { throw RuntimeException("Failed to serialize ReplicationTask: ${it.message()}") })
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(nbt: Tag?): ReplicationTask? {
|
||||
return deserializeNBT(nbt, false) as ReplicationTask?
|
||||
@ -163,12 +170,18 @@ data class ReplicationTask(
|
||||
fun read(buff: FriendlyByteBuf): ReplicationTask? {
|
||||
return read(buff, false) as ReplicationTask?
|
||||
}
|
||||
|
||||
val CODEC: Codec<ReplicationTask> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
codec(it).apply(it, ::ReplicationTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class MutableReplicationTask(
|
||||
override val id: UUID,
|
||||
override val patternId: UUID?,
|
||||
override val patternId: Optional<UUID>,
|
||||
override val item: Item,
|
||||
override var inProgress: Int,
|
||||
override var finished: Int,
|
||||
@ -194,6 +207,10 @@ data class MutableReplicationTask(
|
||||
return this
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CODEC.encode(this, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map({ it as CompoundTag }, { throw RuntimeException("Failed to serialize MutableReplicationTask: ${it.message()}") })
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(nbt: Tag?): MutableReplicationTask? {
|
||||
return deserializeNBT(nbt, true) as MutableReplicationTask?
|
||||
@ -202,6 +219,12 @@ data class MutableReplicationTask(
|
||||
fun read(buff: FriendlyByteBuf): MutableReplicationTask? {
|
||||
return read(buff, true) as MutableReplicationTask?
|
||||
}
|
||||
|
||||
val CODEC: Codec<MutableReplicationTask> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
codec(it).apply(it, ::MutableReplicationTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package ru.dbotthepony.mc.otm.compat.jade.providers
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import ru.dbotthepony.mc.otm.block.entity.MachineItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.compat.jade.JadeTagKeys
|
||||
import ru.dbotthepony.mc.otm.compat.jade.JadeUids
|
||||
@ -34,8 +34,8 @@ object MatteryWorkerProvider : IBlockComponentProvider, IServerDataProvider<Bloc
|
||||
jobData.putBoolean("isIdling", job.isIdling)
|
||||
jobData.putBoolean("isUnableToProcess", job.isUnableToProcess)
|
||||
|
||||
if (job.currentJob is MachineItemJob) {
|
||||
val currentJob = job.currentJob as MachineItemJob
|
||||
if (job.currentJob is ItemJob) {
|
||||
val currentJob = job.currentJob as ItemJob
|
||||
jobData.put("itemStack", currentJob.itemStack.serializeNBT())
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,51 @@
|
||||
package ru.dbotthepony.mc.otm.data
|
||||
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
|
||||
class ComparableCodec<S : Comparable<S>>(val parent: Codec<S>, val min: S? = null, val max: S? = null, val minExclusive: Boolean = false, val maxExclusive: Boolean = false) : Codec<S> {
|
||||
private fun <T : Any> check(input: S): DataResult<T>? {
|
||||
if (min != null) {
|
||||
if (minExclusive) {
|
||||
if (input <= min) {
|
||||
return DataResult.error { "Value $input is smaller or equal to minimal $min" }
|
||||
}
|
||||
} else {
|
||||
if (input < min) {
|
||||
return DataResult.error { "Value $input is smaller than minimal $min" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max != null) {
|
||||
if (maxExclusive) {
|
||||
if (input >= max) {
|
||||
return DataResult.error { "Value $input is bigger or equal to maximal $max" }
|
||||
}
|
||||
} else {
|
||||
if (input > max) {
|
||||
return DataResult.error { "Value $input is bigger than maximal $max" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun <T : Any> encode(input: S, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
check<T>(input)?.let { return it }
|
||||
return parent.encode(input, ops, prefix)
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<S, T>> {
|
||||
return parent.decode(ops, input).flatMap {
|
||||
check<Pair<S, T>>(it.first) ?: DataResult.success(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <S : Comparable<S>> Codec<S>.minRange(min: S, exclusive: Boolean = false) = ComparableCodec(this, min = min, minExclusive = exclusive)
|
||||
fun <S : Comparable<S>> Codec<S>.maxRange(max: S, exclusive: Boolean = false) = ComparableCodec(this, max = max, maxExclusive = exclusive)
|
||||
fun <S : Comparable<S>> Codec<S>.inRange(min: S, minExclusive: Boolean = false, max: S, maxExclusive: Boolean = false) = ComparableCodec(this, min, max, minExclusive, maxExclusive)
|
@ -4,28 +4,63 @@ import com.mojang.datafixers.util.Pair
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.stream.Collector
|
||||
import java.util.stream.Stream
|
||||
|
||||
object DecimalCodec : Codec<Decimal> {
|
||||
override fun <T : Any> encode(input: Decimal, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
if (ops === NbtOps.INSTANCE) {
|
||||
return DataResult.success((ops as DynamicOps<T>).createByteList(ByteBuffer.wrap(input.toByteArray())))
|
||||
}
|
||||
|
||||
return DataResult.success(ops.createString(input.toString()))
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Decimal, T>> {
|
||||
val result = ops.getStringValue(input).flatMap {
|
||||
return ops.getStringValue(input).flatMap {
|
||||
try {
|
||||
DataResult.success(Pair(Decimal(it), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Not a valid number for converting into Decimal: $it" }
|
||||
}
|
||||
}.get().map(
|
||||
{
|
||||
DataResult.success(it)
|
||||
},
|
||||
{ e0 ->
|
||||
ops.getIntStream(input).flatMap {
|
||||
try {
|
||||
DataResult.success(Pair(Decimal.fromByteArray(
|
||||
it.mapToObj { val v = it.toLong(); Stream.of(v and 0xFFL, (v and 0xFF00L) ushr 8, (v and 0xFF0000L) ushr 16, (v and 0xFF000000L) ushr 24) }
|
||||
.flatMap { it }
|
||||
.collect(::ByteArrayList, { v, a -> v.add(a.toByte()) }, ByteArrayList::addAll)
|
||||
.toByteArray()
|
||||
), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Failed to convert array of bytes into Decimal: $it" }
|
||||
}
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
}
|
||||
|
||||
return ops.getNumberValue(input).flatMap {
|
||||
}.get().map(
|
||||
{
|
||||
DataResult.success(it)
|
||||
},
|
||||
{ e1 ->
|
||||
ops.getNumberValue(input).flatMap {
|
||||
DataResult.success(Pair(Decimal(it.toString()), ops.empty()))
|
||||
}.get().map(
|
||||
{
|
||||
DataResult.success(it)
|
||||
},
|
||||
{ e2 ->
|
||||
DataResult.error { "None of attempts at decoding Decimal were successful: ${e0.message()}; ${e1.message()}; ${e2.message()}" }
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,17 @@ package ru.dbotthepony.mc.otm.data
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.datafixers.kinds.App
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.storage.loot.LootContext
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParam
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
|
||||
import java.util.Optional
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
fun JsonArray.getRidOfNulls(): JsonArray {
|
||||
val toRemove = IntAVLTreeSet()
|
||||
|
26
src/main/kotlin/ru/dbotthepony/mc/otm/data/UUIDCodec.kt
Normal file
26
src/main/kotlin/ru/dbotthepony/mc/otm/data/UUIDCodec.kt
Normal file
@ -0,0 +1,26 @@
|
||||
package ru.dbotthepony.mc.otm.data
|
||||
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import java.util.UUID
|
||||
import java.util.stream.LongStream
|
||||
|
||||
object UUIDCodec : Codec<UUID> {
|
||||
override fun <T : Any> encode(input: UUID, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
return DataResult.success(ops.createLongList(LongStream.of(input.mostSignificantBits, input.leastSignificantBits)))
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<UUID, T>> {
|
||||
return ops.getLongStream(input).flatMap {
|
||||
val l = it.limit(2).toArray()
|
||||
|
||||
if (l.size != 2) {
|
||||
DataResult.error { "Can't construct UUID from ${l.size} elements" }
|
||||
} else {
|
||||
DataResult.success(Pair(UUID(l[0], l[1]), ops.empty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user