Revise and streamline pattern and replication tasks API

This commit is contained in:
DBotThePony 2022-09-03 14:59:35 +07:00
parent cc3e5f5550
commit 6e824db2f5
Signed by: DBot
GPG Key ID: DCC23B5715498507
21 changed files with 660 additions and 558 deletions

View File

@ -5,7 +5,7 @@ import net.minecraftforge.common.capabilities.*;
import org.jetbrains.annotations.NotNull;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode;
@ -36,7 +36,7 @@ public class MatteryCapability {
@Nonnull
@NotNull
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IReplicationTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull
@NotNull
@ -56,7 +56,7 @@ public class MatteryCapability {
event.register(MatteryPlayerCapability.class);
event.register(IMatterHandler.class);
event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class);
event.register(IReplicationTaskProvider.class);
event.register(IMatteryDrive.class);
event.register(IStorageGraphNode.class);
event.register(IMatterGraphNode.class);

View File

@ -1,146 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import ru.dbotthepony.mc.otm.core.UnOverengineeringKt;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Objects;
import java.util.UUID;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public record MatterTask(UUID id, @Nullable UUID pattern, Item item, int in_progress, int finished, int required) {
public MatterTask(UUID id, @Nullable UUID pattern, Item item, int in_progress, int finished, int required) {
this.id = id;
this.pattern = pattern;
this.item = item;
this.in_progress = Math.max(0, in_progress);
this.finished = Math.max(0, finished);
this.required = Math.max(0, required);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MatterTask obj1)
return obj1.id.equals(id);
return false;
}
public ItemStack stack() {
return new ItemStack(item, 1);
}
public ItemStack stack(int amount) {
return new ItemStack(item, amount);
}
public int total() {
return in_progress + finished + required;
}
public MatterTask shrinkRequired(int amount) {
return new MatterTask(id, pattern, item, in_progress + amount, finished, required - amount);
}
public MatterTask shrinkInProgress(int amount) {
return new MatterTask(id, pattern, item, in_progress - amount, finished + amount, required);
}
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
tag.putLong("id_l", id.getLeastSignificantBits());
tag.putLong("id_u", id.getMostSignificantBits());
if (pattern != null) {
tag.putLong("pattern_l", pattern.getLeastSignificantBits());
tag.putLong("pattern_u", pattern.getMostSignificantBits());
}
tag.putString("item", Objects.requireNonNull(UnOverengineeringKt.getRegistryName(item)).toString());
tag.putInt("in_progress", in_progress);
tag.putInt("finished", finished);
tag.putInt("required", required);
return tag;
}
@Nullable
public static MatterTask deserializeNBT(@Nullable Tag nbt) {
if (nbt == null)
return null;
if (nbt instanceof CompoundTag tag) {
Item get_item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("item")));
if (get_item != null && get_item != Items.AIR) {
long a = tag.getLong("pattern_u");
long b = tag.getLong("pattern_l");
UUID pattern = a != 0 && b != 0 ? new UUID(a, b) : null;
return new MatterTask(
new UUID(tag.getLong("id_u"), tag.getLong("id_l")),
pattern,
get_item,
tag.getInt("in_progress"),
tag.getInt("finished"),
tag.getInt("required")
);
}
}
return null;
}
public void write(FriendlyByteBuf buffer) {
buffer.writeLong(id.getMostSignificantBits());
buffer.writeLong(id.getLeastSignificantBits());
if (pattern != null) {
buffer.writeBoolean(true);
buffer.writeLong(pattern.getMostSignificantBits());
buffer.writeLong(pattern.getLeastSignificantBits());
} else {
buffer.writeBoolean(false);
}
buffer.writeInt(((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getID(item));
buffer.writeInt(in_progress);
buffer.writeInt(finished);
buffer.writeInt(required);
}
@Nullable
public static MatterTask read(FriendlyByteBuf buffer) {
var id = new UUID(buffer.readLong(), buffer.readLong());
var pattern = buffer.readBoolean() ? new UUID(buffer.readLong(), buffer.readLong()) : null;
var item = ((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getValue(buffer.readInt());
if (item == null)
return null;
var in_progress = buffer.readInt();
var finished = buffer.readInt();
var required = buffer.readInt();
return new MatterTask(id, pattern, item, in_progress, finished, required);
}
}

View File

@ -1,94 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import ru.dbotthepony.mc.otm.core.UnOverengineeringKt;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.UUID;
public record PatternState(@Nonnull UUID id, @Nonnull Item item, double research) {
public PatternState(@Nonnull UUID id, @Nonnull Item item, double research) {
this.id = id;
this.item = item;
this.research = Math.max(0, Math.min(1, research));
}
@Override
public boolean equals(Object state) {
if (state instanceof PatternState state1)
return state1.id.equals(id);
return false;
}
public ItemStack stack() {
return new ItemStack(item, 1);
}
@Override
public int hashCode() {
return id.hashCode();
}
public CompoundTag serializeNBT() {
var tag = new CompoundTag();
tag.putLong("id_m", id.getMostSignificantBits());
tag.putLong("id_l", id.getLeastSignificantBits());
tag.putString("item", Objects.requireNonNull(UnOverengineeringKt.getRegistryName(item)).toString());
tag.putDouble("research_percent", research);
return tag;
}
@Nullable
public static PatternState deserializeNBT(Tag nbt) {
if (nbt instanceof CompoundTag tag) {
var item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("item")));
if (item == null)
return null;
var id = new UUID(tag.getLong("id_m"), tag.getLong("id_l"));
var research_percent = tag.getDouble("research_percent");
return new PatternState(id, item, research_percent);
}
return null;
}
public void write(FriendlyByteBuf buffer) {
buffer.writeLong(id.getMostSignificantBits());
buffer.writeLong(id.getLeastSignificantBits());
buffer.writeInt(((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getID(item));
buffer.writeDouble(research);
}
@Nullable
public static PatternState read(FriendlyByteBuf buffer) {
long ida = buffer.readLong();
long idb = buffer.readLong();
int item = buffer.readInt();
double percent = buffer.readDouble();
Item get_item = ((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getValue(item);
if (get_item == null)
return null;
return new PatternState(new UUID(ida, idb), get_item, percent);
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.Streams
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
@ -32,6 +33,7 @@ import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.core.set
import java.util.ArrayList
import java.util.stream.Stream
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
@ -50,13 +52,13 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (grid != null && !ItemStack.isSameItemSameTags(new, old)) {
if (!old.isEmpty) {
old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) }
cap.storedPatterns.forEach { grid.onPatternRemoved(it) }
}
}
if (!new.isEmpty) {
new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternAdded(state!!) }
cap.storedPatterns.forEach { grid.onPatternAdded(it) }
}
}
@ -147,10 +149,14 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return PatternStorageMenu(containerID, inventory, this)
}
override val storedPatterns: Collection<PatternState> get() {
val list = ArrayList<PatternState>()
patterns.forEachCapability(MatteryCapability.PATTERN) { capability: IPatternStorage -> list.addAll(capability.storedPatterns) }
return list
override val storedPatterns: Stream<out IPatternState> get() {
val streams = ArrayList<Stream<out IPatternState>>()
for (provider in patterns.iterator(MatteryCapability.PATTERN)) {
streams.add(provider.second.storedPatterns)
}
return Streams.concat(*streams.toTypedArray())
}
override val capacity: Int get() {
@ -176,9 +182,9 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph)
}
override fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus {
for ((_, storage) in patterns.iterator(MatteryCapability.PATTERN)) {
val status = storage.insertPattern(pattern, only_update, simulate)
override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (pair in patterns.iterator(MatteryCapability.PATTERN)) {
val status = pair.second.insertPattern(pattern, onlyUpdate, simulate)
if (!status.isFailed) {
if (!simulate) {

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
@ -12,10 +11,6 @@ import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.HashMap
import java.util.UUID
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import java.util.stream.Collectors
import ru.dbotthepony.mc.otm.capability.matter.MatterTaskAllocation
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
@ -25,15 +20,16 @@ import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.ArrayList
import java.util.List
import java.util.stream.Stream
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IMatterTaskProvider {
MatteryBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IReplicationTaskProvider {
private val listeners = ArrayList<MatterPanelMenu>()
override val matterNode = Graph6Node<IMatterGraphNode>(this)
@ -88,61 +84,59 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph)
}
override fun getTaskHandler(): IMatterTaskProvider? {
override fun getTaskHandler(): IReplicationTaskProvider {
return this
}
private val _tasks = HashMap<UUID, MatterTask>()
private val _tasks = HashMap<UUID, ReplicationTask>()
override val tasks: Collection<MatterTask> get() {
return _tasks.values.stream().filter { task: MatterTask? -> task!!.required() > 0 }.collect(Collectors.toList()) as Collection<MatterTask>
override val replicationTasks: Stream<ReplicationTask> get() {
return _tasks.values.stream().filter { it.required > 0 }
}
override val allTasks: Collection<MatterTask> get() {
return List.copyOf(_tasks.values) as Collection<MatterTask>
override val allReplicationTasks: Stream<ReplicationTask> get() {
return _tasks.values.stream()
}
override fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
val graph = matterNode.graph as MatterNetworkGraph? ?: return null
for ((key, task) in _tasks) {
if (task.required > 0) {
val getPattern = graph.getPattern(task.pattern!!)
val pattern = task.patternId?.let(graph::getPattern) ?: continue
if (getPattern != null) {
if (!simulate) {
val new = task.shrinkRequired(1)
val new = task.allocate()
_tasks[key] = new
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(new) }
listeners.forEach { it.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task)
setChanged()
}
return MatterTaskAllocation(task, getPattern)
}
return ReplicationTaskAllocation(task, pattern)
}
}
return null
}
override fun notifyTaskCompletion(task: MatterTask): Boolean {
var localTask = _tasks[task.id] ?: return false
override fun notifyTaskCompletion(taskId: UUID): Boolean {
var localTask = _tasks[taskId] ?: return false
val oldTask = localTask
localTask = localTask.shrinkInProgress(1)
localTask = localTask.finish()
val graph = matterNode.graph as MatterNetworkGraph?
// Задача полностью выполнена
if (localTask.required <= 0 && localTask.in_progress <= 0) {
_tasks.remove(task.id)
graph?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(localTask) }
if (localTask.required <= 0 && localTask.inProgress <= 0) {
_tasks.remove(taskId)
graph?.onMatterTaskFinished(localTask)
listeners.forEach { it.taskRemoved(localTask) }
} else {
// Задача обновлена
_tasks[task.id()] = localTask
_tasks[taskId] = localTask
graph?.onMatterTaskUpdated(localTask, oldTask)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(localTask) }
listeners.forEach { it.taskUpdated(localTask) }
}
setChanged()
@ -155,7 +149,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val list = ListTag()
for (task in _tasks.values) {
list.add(task!!.serializeNBT())
list.add(task.serializeNBT())
}
nbt.put("tasks", list)
@ -167,16 +161,16 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val list = nbt.getList("tasks", Tag.TAG_COMPOUND.toInt())
for (tag in list) {
val task = MatterTask.deserializeNBT(tag)
val task = ReplicationTask.deserializeNBT(tag)
if (task != null) {
_tasks[task.id()] = task
_tasks[task.id] = task
}
}
}
override fun getTask(id: UUID): MatterTask? {
return _tasks[id]
override fun getTask(id: UUID): ReplicationTask? {
return _tasks[id]?.asImmutable()
}
fun removeTask(id: UUID) {
@ -185,19 +179,17 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(task) }
listeners.forEach { it.taskRemoved(task) }
setChanged()
}
fun removeTask(state: PatternState) = removeTask(state.id)
fun addTask(state: PatternState, how_much: Int): MatterTask {
val task = MatterTask(UUID.randomUUID(), state.id, state.item, 0, 0, how_much)
_tasks[task.id()] = task
fun addTask(state: IPatternState, count: Int): IReplicationTask<*> {
val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count)
_tasks[task.id] = task
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task) }
listeners.forEach { it.taskUpdated(task) }
setChanged()
return task

View File

@ -35,7 +35,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
class ReplicatorJob : ItemJob {
val matterPerTick: ImpreciseFraction
val task: MatterTask
val task: ReplicationTask
var matterValue: ImpreciseFraction
val pattern: PatternState?
val asDust: Boolean
@ -45,13 +45,13 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterValue = tag.getImpreciseFraction("value")
pattern = tag.map("pattern", PatternState::deserializeNBT)
asDust = tag.getBoolean("as_dust")
task = tag.map("task", MatterTask::deserializeNBT) ?: throw NullPointerException("Unable to deserialize matter task")
task = tag.map("task", ReplicationTask::deserializeNBT) ?: throw NullPointerException("Unable to deserialize matter task")
}
constructor(
itemStack: ItemStack,
matterPerTick: ImpreciseFraction,
task: MatterTask,
task: ReplicationTask,
matterValue: ImpreciseFraction,
pattern: PatternState?,
asDust: Boolean,
@ -93,7 +93,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return Status.FAILURE_WAIT
}
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task)
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS
}
@ -101,23 +101,23 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return Status.FAILURE_ITEM
}
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task)
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS
}
override fun onMatterTaskCreated(task: MatterTask) {
override fun onMatterTaskCreated(task: IReplicationTask<*>) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {
override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternAdded(state: PatternState) {
override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
@ -149,10 +149,10 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return ReplicatorJob(
itemStack = stack,
matterPerTick = matter.value / ticks,
task = allocation.task,
task = allocation.task.asImmutable(),
matterValue = matter.value,
pattern = allocation.pattern,
asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.research ?: 2.0),
pattern = allocation.pattern?.asImmutable(),
asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.researchPercent ?: 2.0),
ticks = ticks,
) to null
}

View File

@ -18,6 +18,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
@ -47,19 +48,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
})
// IMatterGraphNode
override fun onPatternAdded(state: PatternState) {
override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternRemoved(state: PatternState) {
override fun onPatternRemoved(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
@ -122,22 +123,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val stack = job.itemStack
if (stack.isEmpty || !hasMatterValue(stack)) return Status.SUCCESS
val getState = grid.findPatterns(stack.item)
var findState: PatternState? = null
var findState: IPatternState? = null
for (state in getState) {
if (state.item() === stack.item) {
if (findState == null && state.research() < 1.0) {
for (state in grid.patterns.filter { it.item === stack.item }) {
if (findState == null && state.researchPercent < 1.0) {
findState = state
} else if (findState != null && findState.research() < state.research()) {
} else if (findState != null && findState.researchPercent < state.researchPercent) {
findState = state
}
}
}
val new =
if (findState != null) {
PatternState(findState.id(), stack.item, findState.research() + 0.2)
PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}
@ -159,20 +157,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val stack = container.getItem(0)
if (stack.isEmpty || !canDecompose(stack)) return null to IdleReason.ITEM
val getState = grid.findPatterns(stack.item)
var findState: PatternState? = null
var findState: IPatternState? = null
for (state in getState) {
if (state.item === stack.item && state.research < 1.0) {
for (state in grid.patterns.filter { it.item === stack.item }) {
if (state.researchPercent < 1.0) {
findState = state
} else if (state.item === stack.item && state.research >= 1.0) {
return null to IdleReason.OBSERVING
} else if (state.researchPercent >= 1.0) {
return null to IdleReason.ITEM
}
}
val new: PatternState =
val new: IPatternState =
if (findState != null) {
PatternState(findState.id, stack.item, findState.research + 0.2)
PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}

View File

@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import java.util.*
import java.util.function.Predicate
import java.util.stream.Collectors
import java.util.stream.Stream
interface IMatterHandler {
val storedMatter: ImpreciseFraction
@ -14,6 +15,7 @@ interface IMatterHandler {
fun receiveMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
val direction: MatterDirection
val missingMatter: ImpreciseFraction
get() = maxStoredMatter.minus(storedMatter).moreThanZero()
@ -27,42 +29,44 @@ interface IMatterHandler {
enum class MatterDirection { RECEIVE, EXTRACT, BIDIRECTIONAL }
interface IMatterTaskProvider {
interface IReplicationTaskProvider {
/**
* @return immutable collection of tasks that can be allocated by a worker
* It must return new stream each time
*/
val tasks: Collection<MatterTask>
val replicationTasks: Stream<out IReplicationTask<*>>
/**
* @return immutable collection of all stored tasks, even fully allocated by workers
* It must return new stream each time
*/
val allTasks: Collection<MatterTask>
val allReplicationTasks: Stream<out IReplicationTask<*>>
/**
* Allocates (marks as work-in-progress) a task
* by incrementing it's in_progress by 1
* and shrinking required by 1
* by incrementing it's [IReplicationTask.inProgress] by 1
* and shrinking [IReplicationTask.required] by 1
*
* If required == 0, it should not be returned by this method
* If [IReplicationTask.required] == 0, it should not be returned by this method
* @param simulate whenever to change internal state
* @return MatterTaskAllocation(task, pattern) that should be performed, or null if no work is available
*/
fun allocateTask(simulate: Boolean): MatterTaskAllocation?
fun allocateTask(simulate: Boolean): ReplicationTaskAllocation?
/**
* Notify about task completion. If this provider indeed contain this task, it should
* shrink in_progress by 1
* If in_progress == 0 and required == 0, it should discard the task
* @param task task being completed. this method should ignore tasks that are not owned by it.
* @param taskId task being completed. this method should ignore tasks that are not owned by it.
* @return whenever task indeed belong to this provider and internal state was updated
*/
fun notifyTaskCompletion(task: MatterTask): Boolean
fun notifyTaskCompletion(taskId: UUID): Boolean
/**
* @param id uuid of task
* @return MatterTask that this capability holds with this id, or null
*/
fun getTask(id: UUID): MatterTask?
fun getTask(id: UUID): IReplicationTask<*>? {
return allReplicationTasks.filter { it.id == id }.findAny().orElse(null)
}
/**
* Destroys all tasks this capability contains
@ -72,50 +76,36 @@ interface IMatterTaskProvider {
interface IPatternStorage {
/**
* @return unmodifiable collection of stored patterns
* It must return new stream each time
*/
val storedPatterns: Collection<PatternState>
val storedPatterns: Stream<out IPatternState>
fun findPatterns(item: Item): Collection<PatternState> {
return findPatterns { item2: PatternState -> item == item2.item() }
fun findPatterns(item: Item): Collection<IPatternState> {
return findPatterns { item == it.item }
}
fun findPatterns(predicate: Predicate<PatternState>?): Collection<PatternState> {
return storedPatterns.stream().filter(predicate).collect(Collectors.toList())
fun findPatterns(predicate: Predicate<IPatternState>): Collection<IPatternState> {
return storedPatterns.filter(predicate).collect(Collectors.toList())
}
fun findPattern(item: Item): PatternState? {
return findPattern { item2: PatternState -> item == item2.item() }
fun findPattern(item: Item): IPatternState? {
return storedPatterns.filter { it.item == item }.findAny().orElse(null)
}
fun findPattern(predicate: Predicate<PatternState>): PatternState? {
for (pattern in storedPatterns) {
if (predicate.test(pattern)) {
return pattern
}
fun getPattern(id: UUID?): IPatternState? {
return storedPatterns.filter { it.id == id }.findAny().orElse(null)
}
return null
fun hasPattern(item: Item): Boolean {
return storedPatterns.filter { it.item == item }.findAny().isPresent
}
fun getPattern(id: UUID?): PatternState? {
id ?: return null
for (pattern in storedPatterns) {
if (pattern.id == id) {
return pattern
}
}
return null
}
fun hasPattern(state: PatternState): Boolean {
return getPattern(state.id) != null
fun hasPattern(state: IPatternState): Boolean {
return hasPattern(state.id)
}
fun hasPattern(id: UUID?): Boolean {
return getPattern(id) != null
return storedPatterns.filter { it.id == id }.findAny().isPresent
}
val capacity: Int
@ -126,17 +116,17 @@ interface IPatternStorage {
* and if it fail, try only_update = false
*
* @param pattern pattern to be inserted or update value from
* @param only_update do not insert new pattern if this pattern's UUID is not matched
* @param onlyUpdate do not insert new pattern if this pattern's UUID is not matched
* @param simulate whenever to affect state
* @return record of status of the operation (at status() FAIL, UPDATED, INSERTED) as well as new_state and old_state
*/
fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus
fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus
fun insertPattern(pattern: PatternState, simulate: Boolean): PatternInsertStatus {
fun insertPattern(pattern: IPatternState, simulate: Boolean): PatternInsertStatus {
return insertPattern(pattern, false, simulate)
}
fun updatePattern(pattern: PatternState, simulate: Boolean): PatternInsertStatus {
fun updatePattern(pattern: IPatternState, simulate: Boolean): PatternInsertStatus {
return insertPattern(pattern, true, simulate)
}
}

View File

@ -8,17 +8,17 @@ private enum class PatternInsertResult {
sealed class PatternInsertStatus(
private val status: PatternInsertResult,
val newState: PatternState?,
val oldState: PatternState?
val newState: IPatternState?,
val oldState: IPatternState?
) {
val isFailed get() = status === PatternInsertResult.FAIL
val isUpdated get() = status === PatternInsertResult.UPDATED
val isInserted get() = status === PatternInsertResult.INSERTED
val isFailed get() = status == PatternInsertResult.FAIL
val isUpdated get() = status == PatternInsertResult.UPDATED
val isInserted get() = status == PatternInsertResult.INSERTED
}
object PatternInsertFailure : PatternInsertStatus(PatternInsertResult.FAIL, null, null)
class PatternInsertUpdated(new: PatternState, old: PatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old)
class PatternInsertInserted(new: PatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null)
class PatternInsertUpdated(new: IPatternState, old: IPatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old)
class PatternInsertInserted(new: IPatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null)
@JvmRecord
data class MatterTaskAllocation(val task: MatterTask, val pattern: PatternState?)
data class ReplicationTaskAllocation(val task: IReplicationTask<*>, val pattern: IPatternState?)

View File

@ -0,0 +1,146 @@
package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.core.*
import java.util.*
sealed interface IPatternState {
val id: UUID
val item: Item
val researchPercent: Double
fun asMutable(): MutablePatternState
fun asImmutable() : PatternState
fun matchId(other: IPatternState): Boolean {
return other.id == id
}
fun copyAsMutable(
id: UUID = this.id,
item: Item = this.item,
researchPercent: Double = this.researchPercent,
): MutablePatternState {
return MutablePatternState(id, item, researchPercent)
}
fun copyAsImmutable(
id: UUID = this.id,
item: Item = this.item,
researchPercent: Double = this.researchPercent,
) : PatternState {
return PatternState(id, item, researchPercent)
}
fun stack(count: Int = 1): ItemStack {
return ItemStack(item, count)
}
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["id"] = id
it["item"] = item.registryName!!.toString()
it["researchPercent"] = researchPercent
}
}
fun write(buff: FriendlyByteBuf) {
buff.writeUUID(id)
buff.writeItemType(item)
buff.writeDouble(researchPercent)
}
}
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IPatternState? {
if (nbt !is CompoundTag)
return null
if (!nbt.contains("id", "researchPercent", "item"))
return null
val id = nbt.getUUID("id")
val researchPercent = nbt.getDouble("researchPercent")
val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(nbt.getString("item"))) ?: return null
if (item == Items.AIR)
return null
if (mutable) {
return MutablePatternState(id, item, researchPercent)
} else {
return PatternState(id, item, researchPercent)
}
}
private fun read(buff: FriendlyByteBuf, mutable: Boolean): IPatternState? {
val id = buff.readUUID()
val item = buff.readItemType()
val researchPercent = buff.readDouble()
item ?: return null
if (mutable) {
return MutablePatternState(id, item, researchPercent)
} else {
return PatternState(id, item, researchPercent)
}
}
data class PatternState(
override val id: UUID,
override val item: Item,
override val researchPercent: Double,
) : IPatternState {
override fun asMutable(): MutablePatternState {
return MutablePatternState(id, item, researchPercent)
}
override fun asImmutable(): PatternState {
return this
}
companion object {
fun deserializeNBT(tag: Tag?): PatternState? {
return deserializeNBT(tag, false) as PatternState?
}
fun read(buff: FriendlyByteBuf): PatternState? {
return read(buff, false) as PatternState?
}
}
}
data class MutablePatternState(
override val id: UUID,
override val item: Item,
override var researchPercent: Double,
) : IPatternState {
override fun asMutable(): MutablePatternState {
return this
}
override fun asImmutable(): PatternState {
return PatternState(id, item, researchPercent)
}
companion object {
fun deserializeNBT(tag: Tag?): MutablePatternState? {
return deserializeNBT(tag, true) as MutablePatternState?
}
fun read(buff: FriendlyByteBuf): MutablePatternState? {
return read(buff, true) as MutablePatternState?
}
}
}
fun FriendlyByteBuf.writePatternState(state: IPatternState) = state.write(this)
fun FriendlyByteBuf.readPatternState() = PatternState.read(this)
fun FriendlyByteBuf.readMutablePatternState() = MutablePatternState.read(this)

View File

@ -0,0 +1,210 @@
package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
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.set
import ru.dbotthepony.mc.otm.core.writeItemType
import java.util.UUID
sealed interface IReplicationTask<S : IReplicationTask<S>> {
val id: UUID
val patternId: UUID?
val item: Item
val inProgress: Int
val finished: Int
val required: Int
fun asMutable(): MutableReplicationTask
fun asImmutable(): ReplicationTask
val total get() = inProgress + finished + required
fun copyAsMutable(
id: UUID = this.id,
patternId: UUID? = this.patternId,
item: Item = this.item,
inProgress: Int = this.inProgress,
finished: Int = this.finished,
required: Int = this.required,
): MutableReplicationTask {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
}
fun copyAsImmutable(
id: UUID = this.id,
patternId: UUID? = this.patternId,
item: Item = this.item,
inProgress: Int = this.inProgress,
finished: Int = this.finished,
required: Int = this.required,
): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
fun matchId(other: IReplicationTask<*>): Boolean {
return other.id == id
}
fun stack(count: Int = 1): ItemStack {
return ItemStack(item, count)
}
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 write(buff: FriendlyByteBuf) {
buff.writeUUID(id)
buff.writeBoolean(patternId != null)
patternId?.let(buff::writeUUID)
buff.writeItemType(item)
buff.writeInt(inProgress)
buff.writeInt(finished)
buff.writeInt(required)
}
}
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IReplicationTask<*>? {
if (nbt !is CompoundTag)
return null
if (!nbt.contains("id") || !nbt.contains("inProgress") || !nbt.contains("finished") || !nbt.contains("required") || !nbt.contains("item"))
return null
val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(nbt.getString("item"))) ?: return null
if (item == Items.AIR)
return null
val id = nbt.getUUID("id")
val patternId = if (nbt.contains("patternId")) nbt.getUUID("patternId") else null
val inProgress = nbt.getInt("inProgress")
val finished = nbt.getInt("finished")
val required = nbt.getInt("required")
if (mutable) {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
} else {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
}
private fun read(buff: FriendlyByteBuf, mutable: Boolean): IReplicationTask<*>? {
val id = buff.readUUID()
val patternId: UUID? = if (buff.readBoolean()) buff.readUUID() else null
val item = buff.readItemType()
val inProgress = buff.readInt()
val finished = buff.readInt()
val required = buff.readInt()
item ?: return null
if (mutable) {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
} else {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
}
data class ReplicationTask(
override val id: UUID,
override val patternId: UUID?,
override val item: Item,
override val inProgress: Int,
override val finished: Int,
override val required: Int
) : IReplicationTask<ReplicationTask> {
override fun asMutable(): MutableReplicationTask {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
}
override fun asImmutable(): ReplicationTask {
return this
}
override fun allocate(amount: Int): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress + amount, finished, required - amount)
}
override fun finish(amount: Int): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress - amount, finished + amount, required)
}
companion object {
fun deserializeNBT(nbt: Tag?): ReplicationTask? {
return deserializeNBT(nbt, false) as ReplicationTask?
}
fun read(buff: FriendlyByteBuf): ReplicationTask? {
return read(buff, false) as ReplicationTask?
}
}
}
data class MutableReplicationTask(
override val id: UUID,
override val patternId: UUID?,
override val item: Item,
override var inProgress: Int,
override var finished: Int,
override var required: Int
) : IReplicationTask<MutableReplicationTask> {
override fun asMutable(): MutableReplicationTask {
return this
}
override fun asImmutable(): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
override fun allocate(amount: Int): MutableReplicationTask {
inProgress += amount
finished -= amount
return this
}
override fun finish(amount: Int): MutableReplicationTask {
finished += amount
inProgress -= amount
return this
}
companion object {
fun deserializeNBT(nbt: Tag?): MutableReplicationTask? {
return deserializeNBT(nbt, true) as MutableReplicationTask?
}
fun read(buff: FriendlyByteBuf): MutableReplicationTask? {
return read(buff, true) as MutableReplicationTask?
}
}
}
fun FriendlyByteBuf.writeReplicationTask(task: IReplicationTask<*>) = task.write(this)
fun FriendlyByteBuf.readReplicationTask() = ReplicationTask.read(this)
fun FriendlyByteBuf.readMutableReplicationTask() = MutableReplicationTask.read(this)

View File

@ -5,7 +5,8 @@ import net.minecraft.client.gui.components.EditBox
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTask
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.core.TranslatableComponent
@ -70,7 +71,7 @@ class MatterPanelScreen(
if (isPatternView) {
return menu.patterns.getOrNull(index)?.stack() ?: ItemStack.EMPTY
} else {
return menu.tasks.getOrNull(index)?.stack() ?: ItemStack.EMPTY
return menu.tasks.getOrNull(index)?.let { it.stack(it.required + it.inProgress) } ?: ItemStack.EMPTY
}
}
@ -81,14 +82,14 @@ class MatterPanelScreen(
menu.patterns.getOrNull(index)?.let {
list.add(TranslatableComponent(
"otm.item.pattern.research",
String.format("%.2f", it.research() * 100.0)
String.format("%.2f", it.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)) }
} else {
menu.tasks.getOrNull(index)?.let {
list.add(TranslatableComponent("otm.gui.matter_task.total", it.total()).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.required", it.required()).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.in_progress", it.in_progress()).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.finished", it.finished()).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.total", it.total).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.required", it.required).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.in_progress", it.inProgress).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.finished", it.finished).withStyle(ChatFormatting.GRAY))
}
}
@ -115,7 +116,7 @@ class MatterPanelScreen(
return frame
}
private fun openTask(task: MatterTask) {
private fun openTask(task: IReplicationTask<*>) {
val frame = FramePanel.padded(this, null, 170f, 20f, TranslatableComponent("otm.container.matter_panel.task"))
object : AbstractSlotPanel(this@MatterPanelScreen, frame) {
@ -155,7 +156,7 @@ class MatterPanelScreen(
frame.toScreenCenter()
}
private fun openPattern(pattern: PatternState) {
private fun openPattern(pattern: IPatternState) {
val frame = FramePanel.padded(this, null, 213f, (ButtonPanel.HEIGHT + 3f) * 4f, TranslatableComponent("otm.container.matter_panel.task"))
val rowTop = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
@ -186,7 +187,7 @@ class MatterPanelScreen(
return super.getItemStackTooltip(stack).toMutableList().also {
it.add(TranslatableComponent(
"otm.item.pattern.research",
String.format("%.2f", pattern.research() * 100.0)
String.format("%.2f", pattern.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA))
}
}
@ -236,7 +237,7 @@ class MatterPanelScreen(
} catch (_: NumberFormatException) {
}
MenuNetworkChannel.sendToServer(ReplicationRequestPacket(pattern, value))
MenuNetworkChannel.sendToServer(ReplicationRequestPacket(pattern.id, value))
frame.remove()
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.core
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import java.util.UUID
operator fun CompoundTag.set(index: String, value: Tag) = put(index, value)
operator fun CompoundTag.set(index: String, value: Int) = putInt(index, value)
@ -16,6 +17,18 @@ operator fun CompoundTag.set(index: String, value: ByteArray) = putByteArray(i
operator fun CompoundTag.set(index: String, value: IntArray) = putIntArray(index, value)
operator fun CompoundTag.set(index: String, value: LongArray) = putLongArray(index, value)
operator fun CompoundTag.set(index: String, value: UUID) = putUUID(index, value)
fun CompoundTag.contains(vararg keys: String): Boolean {
for (key in keys) {
if (!contains(key)) {
return false
}
}
return true
}
inline fun <R, reified T : Tag> CompoundTag.map(s: String, consumer: (T) -> R): R? {
val tag = get(s)

View File

@ -10,11 +10,17 @@ import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.ForgeRegistry
import net.minecraftforge.registries.IForgeRegistry
import net.minecraftforge.registries.RegistryManager
import java.math.BigInteger
/**
@ -299,3 +305,23 @@ inline fun <T> ImmutableList(size: Int, initializer: (index: Int) -> T): Immutab
}
}
}
fun <T> IForgeRegistry<T>.getID(value: T): Int {
return (this as ForgeRegistry<T>).getID(value)
}
fun <T> IForgeRegistry<T>.getValue(index: Int): T? {
return (this as ForgeRegistry<T>).getValue(index)
}
fun IForgeRegistry<*>.getID(value: ResourceLocation): Int {
return (this as ForgeRegistry<*>).getID(value)
}
fun FriendlyByteBuf.writeItemType(value: Item) {
writeInt(ForgeRegistries.ITEMS.getID(value))
}
fun FriendlyByteBuf.readItemType(): Item? {
return ForgeRegistries.ITEMS.getValue(readInt())
}

View File

@ -4,20 +4,20 @@ import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
interface IMatterGraphListener {
fun onPatternAdded(state: PatternState) {}
fun onPatternRemoved(state: PatternState) {}
fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {}
fun onPatternAdded(state: IPatternState) {}
fun onPatternRemoved(state: IPatternState) {}
fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {}
fun onMatterTaskCreated(task: MatterTask) {}
fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {}
fun onMatterTaskFinished(state: MatterTask) {}
fun onMatterTaskRemoved(state: MatterTask) {}
fun onMatterTaskCreated(task: IReplicationTask<*>) {}
fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {}
fun onMatterTaskFinished(state: IReplicationTask<*>) {}
fun onMatterTaskRemoved(state: IReplicationTask<*>) {}
}
interface IMatterGraphNode : IMatterGraphListener {
fun getMatterHandler(): IMatterHandler? = null
fun getPatternHandler(): IPatternStorage? = null
fun getTaskHandler(): IMatterTaskProvider? = null
fun getTaskHandler(): IReplicationTaskProvider? = null
val matterNode: Graph6Node<IMatterGraphNode>
val matterGraph: MatterNetworkGraph? get() = matterNode.graph as MatterNetworkGraph?

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.graph.matter
import com.google.common.collect.Streams
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.entity.BlockEntity
@ -9,7 +10,8 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node
import java.util.*
import kotlin.collections.ArrayList
import java.util.function.Predicate
import java.util.stream.Stream
import kotlin.collections.HashSet
@Suppress("unused")
@ -31,26 +33,26 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
val tasks = node.value.getTaskHandler()
if (tasks != null) {
for (task in tasks.tasks) {
for (task in tasks.replicationTasks) {
onMatterTaskRemoved(task)
}
}
for (pattern in getStoredPatterns()) {
for (pattern in this.patterns) {
node.value.onPatternRemoved(pattern)
}
for (task in getTasks()) {
for (task in this.tasks) {
node.value.onMatterTaskRemoved(task)
}
}
override fun onNodeAdded(node: Graph6Node<IMatterGraphNode>) {
for (pattern in getStoredPatterns()) {
for (pattern in this.patterns) {
node.value.onPatternAdded(pattern)
}
for (task in getTasks()) {
for (task in this.tasks) {
node.value.onMatterTaskCreated(task)
}
@ -65,7 +67,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
val tasks = node.value.getTaskHandler()
if (tasks != null) {
for (task in tasks.tasks) {
for (task in tasks.replicationTasks) {
onMatterTaskCreated(task)
}
}
@ -103,6 +105,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch
var extracted = ImpreciseFraction.ZERO
@ -126,6 +129,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch
var received = ImpreciseFraction.ZERO
@ -149,6 +153,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch
var received = ImpreciseFraction.ZERO
@ -168,7 +173,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return received
}
private fun _insertPattern(state: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
private fun doInsertPattern(state: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (node in nodes) {
val storage = node.value.getPatternHandler()
@ -184,42 +189,26 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return PatternInsertFailure
}
fun insertPattern(state: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
if (onlyUpdate) return _insertPattern(state, true, simulate)
val status = _insertPattern(state, true, simulate)
fun insertPattern(state: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
if (onlyUpdate) return doInsertPattern(state, true, simulate)
val status = doInsertPattern(state, true, simulate)
if (!status.isFailed) return status
return _insertPattern(state, false, simulate)
return doInsertPattern(state, false, simulate)
}
fun getTasks(): Collection<MatterTask> {
val list = ArrayList<MatterTask>()
for (node in nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null) {
list.addAll(tasks.tasks)
}
val tasks: Stream<out IReplicationTask<*>> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.replicationTasks }.toTypedArray())
}
return list
val allTasks: Stream<out IReplicationTask<*>> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.allReplicationTasks }.toTypedArray())
}
fun getStoredPatterns(): Collection<PatternState> {
val list = ArrayList<PatternState>()
for (node in nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
list.addAll(storage.storedPatterns)
}
val patterns: Stream<out IPatternState> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getPatternHandler()?.storedPatterns }.toTypedArray())
}
return list
}
fun getPatternCount(): Long {
val patternCount: Long get() {
var value = 0L
for (node in nodes) {
@ -233,7 +222,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return value
}
fun getPatternCapacity(): Long {
val patternCapacity: Long get() {
var value = 0L
for (node in nodes) {
@ -247,7 +236,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return value
}
fun getPattern(id: UUID): PatternState? {
fun getPattern(id: UUID): IPatternState? {
for (node in nodes) {
val storage = node.value.getPatternHandler()
@ -267,15 +256,15 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun hasPattern(state: PatternState) = getPattern(state.id) != null
fun hasPattern(id: UUID) = getPattern(id) != null
fun findPattern(predicate: (PatternState) -> Boolean): PatternState? {
fun findPattern(predicate: Predicate<IPatternState>): IPatternState? {
for (node in nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
for (state in storage.storedPatterns) {
if (predicate(state)) {
return state
}
val find = storage.storedPatterns.filter(predicate).findAny()
if (find.isPresent) {
return find.get()
}
}
}
@ -285,27 +274,13 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun findPattern(predicate: Item) = findPattern { it.item == predicate }
fun findPatterns(predicate: (PatternState) -> Boolean): Collection<PatternState> {
val list = ArrayList<PatternState>()
for (node in nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
for (state in storage.storedPatterns) {
if (predicate(state)) {
list.add(state)
}
}
}
}
return list
fun findPatterns(predicate: Predicate<IPatternState>): List<IPatternState> {
return patterns.filter(predicate).toList()
}
fun findPatterns(predicate: Item) = findPatterns { it.item == predicate }
fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
for (node in nodes) {
val tasks = node.value.getTaskHandler()
@ -321,49 +296,41 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return null
}
fun notifyTaskCompletion(task: MatterTask): Boolean {
for (node in nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null && tasks.notifyTaskCompletion(task)) {
return true
}
fun notifyTaskCompletion(taskId: UUID): Boolean {
return nodes.any { it.value.getTaskHandler()?.notifyTaskCompletion(taskId) == true }
}
return false
}
override fun onPatternAdded(state: PatternState) {
override fun onPatternAdded(state: IPatternState) {
for (node in nodes) node.value.onPatternAdded(state)
for (node in listeners) node.onPatternAdded(state)
}
override fun onPatternRemoved(state: PatternState) {
override fun onPatternRemoved(state: IPatternState) {
for (node in nodes) node.value.onPatternRemoved(state)
for (node in listeners) node.onPatternRemoved(state)
}
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
for (node in nodes) node.value.onPatternUpdated(new_state, old_state)
for (node in listeners) node.onPatternUpdated(new_state, old_state)
override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
for (node in nodes) node.value.onPatternUpdated(newState, oldState)
for (node in listeners) node.onPatternUpdated(newState, oldState)
}
override fun onMatterTaskCreated(task: MatterTask) {
override fun onMatterTaskCreated(task: IReplicationTask<*>) {
for (node in nodes) node.value.onMatterTaskCreated(task)
for (node in listeners) node.onMatterTaskCreated(task)
}
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {
for (node in nodes) node.value.onMatterTaskUpdated(new_state, old_state)
for (node in listeners) node.onMatterTaskUpdated(new_state, old_state)
override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {
for (node in nodes) node.value.onMatterTaskUpdated(newState, oldState)
for (node in listeners) node.onMatterTaskUpdated(newState, oldState)
}
override fun onMatterTaskFinished(state: MatterTask) {
override fun onMatterTaskFinished(state: IReplicationTask<*>) {
for (node in nodes) node.value.onMatterTaskFinished(state)
for (node in listeners) node.onMatterTaskFinished(state)
}
override fun onMatterTaskRemoved(state: MatterTask) {
override fun onMatterTaskRemoved(state: IReplicationTask<*>) {
for (node in nodes) node.value.onMatterTaskRemoved(state)
for (node in listeners) node.onMatterTaskRemoved(state)
}

View File

@ -18,6 +18,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.ifHas
import java.util.*
import java.util.stream.Stream
class PatternStorageItem : Item {
val capacity: Int
@ -53,8 +54,8 @@ class PatternStorageItem : Item {
list.add(
TranslatableComponent(
"otm.item.pattern.line",
state.item().getName(ItemStack(state.item(), 1)),
String.format("%.2f", state.research() * 100.0)
state.item.getName(ItemStack(state.item, 1)),
String.format("%.2f", state.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)
)
}
@ -71,47 +72,40 @@ class PatternStorageItem : Item {
}
override val stored: Int get() {
return storedPatterns.size
stack.tag?.ifHas("otm_patterns", ListTag::class.java) {
return it.size
}
return 0
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (cap === MatteryCapability.PATTERN) resolver.cast() else LazyOptional.empty()
return if (cap == MatteryCapability.PATTERN) resolver.cast() else LazyOptional.empty()
}
override val storedPatterns: Collection<PatternState> get() {
override val storedPatterns: Stream<out IPatternState> get() {
stack.tag?.ifHas("otm_patterns", ListTag::class.java) {
val list = ArrayList<PatternState>()
for (tag in it) {
if (tag is CompoundTag) {
val state = PatternState.deserializeNBT(tag)
if (state != null)
list.add(state)
}
return it.stream().map { PatternState.deserializeNBT(it) }.filter { it != null } as Stream<out IPatternState>
}
return list
}
return emptyList()
return Stream.empty()
}
override fun insertPattern(
pattern: PatternState,
only_update: Boolean,
pattern: IPatternState,
onlyUpdate: Boolean,
simulate: Boolean
): PatternInsertStatus {
val tag = stack.orCreateTag
var list = tag["otm_patterns"]
if (list !is ListTag) {
if (only_update)
if (onlyUpdate)
return PatternInsertFailure
if (simulate) {
if (capacity > 0)
return PatternInsertInserted(pattern)
return PatternInsertInserted(pattern.asImmutable())
else
return PatternInsertFailure
}
@ -126,24 +120,24 @@ class PatternStorageItem : Item {
val state = PatternState.deserializeNBT(list.getCompound(i))
if (state != null) {
if (state == pattern) {
if (state.id == pattern.id) {
if (!simulate) {
list[i] = pattern.serializeNBT()
}
return PatternInsertUpdated(pattern, state)
return PatternInsertUpdated(pattern.asImmutable(), state)
}
} else {
invalidCounter++
}
}
if (only_update || capacity <= list.size - invalidCounter)
if (onlyUpdate || capacity <= list.size - invalidCounter)
return PatternInsertFailure
if (invalidCounter > 0) {
if (simulate)
return PatternInsertInserted(pattern)
return PatternInsertInserted(pattern.asImmutable())
for (i in list.indices) {
val state = PatternState.deserializeNBT(list.getCompound(i))

View File

@ -9,8 +9,7 @@ import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.entity.matter.MatterPanelBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
@ -40,7 +39,7 @@ class CancelTaskPacket(val id: UUID) : MatteryPacket {
}
}
class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<PatternState>) : MatteryPacket {
class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<IPatternState>) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeBoolean(isUpdate)
buff.writeInt(patterns.size)
@ -74,7 +73,7 @@ class PatternsChangePacket(val isUpdate: Boolean, val patterns: Collection<Patte
}
}
class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<MatterTask>) : MatteryPacket {
class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<IReplicationTask<*>>) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeBoolean(isUpdate)
buff.writeInt(tasks.size)
@ -102,17 +101,17 @@ class TasksChangePacket(val isUpdate: Boolean, val tasks: Collection<MatterTask>
val isUpdate = buff.readBoolean()
val size = buff.readInt()
return TasksChangePacket(isUpdate, ArrayList<MatterTask>(size).also {
for (i in 0 until size) it.add(MatterTask.read(buff) ?: throw NullPointerException("Unable to read PatternState from network at $i")) })
return TasksChangePacket(isUpdate, ArrayList<IReplicationTask<*>>(size).also {
for (i in 0 until size) it.add(buff.readReplicationTask() ?: throw NullPointerException("Unable to read Replication Task from network at $i")) })
}
}
}
class ReplicationRequestPacket(val state: PatternState, amount: Int) : MatteryPacket {
class ReplicationRequestPacket(val id: UUID, amount: Int) : MatteryPacket {
val amount = amount.coerceAtLeast(1).coerceAtMost(99999)
override fun write(buff: FriendlyByteBuf) {
state.write(buff)
buff.writeUUID(id)
buff.writeInt(amount)
}
@ -122,13 +121,13 @@ class ReplicationRequestPacket(val state: PatternState, amount: Int) : MatteryPa
val sender = context.sender ?: return@enqueueWork
val menu = sender.containerMenu as? MatterPanelMenu ?: return@enqueueWork
menu.requestReplication(sender, state, amount)
menu.requestReplication(sender, id, amount)
}
}
companion object {
fun read(buff: FriendlyByteBuf): ReplicationRequestPacket {
return ReplicationRequestPacket(PatternState.read(buff)!!, buff.readInt())
return ReplicationRequestPacket(buff.readUUID(), buff.readInt())
}
}
}
@ -138,24 +137,24 @@ class MatterPanelMenu @JvmOverloads constructor(
inventory: Inventory,
tile: MatterPanelBlockEntity? = null
) : MatteryMenu(MMenus.MATTER_PANEL, p_38852_, inventory, tile), IMatterGraphListener {
fun taskUpdated(task: MatterTask) {
fun taskUpdated(task: IReplicationTask<*>) {
sendNetwork(TasksChangePacket(true, listOf(task)))
}
fun taskRemoved(task: MatterTask) {
fun taskRemoved(task: IReplicationTask<*>) {
sendNetwork(TasksChangePacket(false, listOf(task)))
}
// client code
val patterns = ArrayList<PatternState>()
val tasks = ArrayList<MatterTask>()
val patterns = ArrayList<IPatternState>()
val tasks = ArrayList<IReplicationTask<*>>()
var changeset = 0
fun networkPatternsUpdated(patterns: Collection<PatternState>) {
fun networkPatternsUpdated(patterns: Collection<IPatternState>) {
changeset++
for (pattern in patterns) {
val index = this.patterns.indexOf(pattern)
val index = this.patterns.indexOfFirst(pattern::matchId)
if (index != -1) {
this.patterns[index] = pattern
@ -165,7 +164,7 @@ class MatterPanelMenu @JvmOverloads constructor(
}
}
fun networkPatternsRemoved(patterns: Collection<PatternState>) {
fun networkPatternsRemoved(patterns: Collection<IPatternState>) {
changeset++
for (pattern in patterns) {
@ -173,11 +172,11 @@ class MatterPanelMenu @JvmOverloads constructor(
}
}
fun networkTasksUpdated(tasks: Collection<MatterTask>) {
fun networkTasksUpdated(tasks: Collection<IReplicationTask<*>>) {
changeset++
for (task in tasks) {
val index = this.tasks.indexOf(task)
val index = this.tasks.indexOfFirst(task::matchId)
if (index != -1) {
this.tasks[index] = task
@ -185,39 +184,40 @@ class MatterPanelMenu @JvmOverloads constructor(
this.tasks.add(task)
}
watcher_update?.accept(task)
updateWatcher?.accept(task)
}
}
fun networkTasksRemoved(tasks: Collection<MatterTask>) {
fun networkTasksRemoved(tasks: Collection<IReplicationTask<*>>) {
changeset++
for (task in tasks) {
this.tasks.remove(task)
watcher_delete?.accept(task)
deleteWatcher?.accept(task)
}
}
private var watcher_delete: Consumer<MatterTask>? = null
private var watcher_update: Consumer<MatterTask>? = null
private var deleteWatcher: Consumer<IReplicationTask<*>>? = null
private var updateWatcher: Consumer<IReplicationTask<*>>? = null
fun networkTaskWatcher(watcher_update: Consumer<MatterTask>, watcher_delete: Consumer<MatterTask>) {
this.watcher_delete = watcher_delete
this.watcher_update = watcher_update
fun networkTaskWatcher(updateWatcher: Consumer<IReplicationTask<*>>, deleteWatcher: Consumer<IReplicationTask<*>>) {
this.deleteWatcher = deleteWatcher
this.updateWatcher = updateWatcher
}
// server code
fun requestReplication(ply: ServerPlayer, state: PatternState, how_much: Int) {
fun requestReplication(ply: ServerPlayer, id: UUID, count: Int) {
val tile = tile as MatterPanelBlockEntity? ?: return
val graph = tile.matterGraph ?: return
val state = graph.getPattern(id)
if (graph.getPattern(state) == null) {
OverdriveThatMatters.LOGGER.error("Received replication request from {} of {}, but it is no longer in grid", ply, state)
if (state == null) {
OverdriveThatMatters.LOGGER.error("Received replication request from {} of {}, but it is not found in grid", ply, id)
return
}
tile.addTask(state, how_much)
tile.addTask(state, count)
}
fun receiveTaskCancel(ply: ServerPlayer, id: UUID) {
@ -228,19 +228,19 @@ class MatterPanelMenu @JvmOverloads constructor(
MenuNetworkChannel.sendToServer(CancelTaskPacket(id))
}
override fun onPatternAdded(state: PatternState) {
override fun onPatternAdded(state: IPatternState) {
sendNetwork(PatternsChangePacket(true, listOf(state)))
}
override fun onPatternRemoved(state: PatternState) {
override fun onPatternRemoved(state: IPatternState) {
sendNetwork(PatternsChangePacket(false, listOf(state)))
}
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
sendNetwork(PatternsChangePacket(true, listOf(new_state)))
override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
sendNetwork(PatternsChangePacket(true, listOf(newState)))
}
private var initial_send = false
private var initialSend = false
private var listeningGrid: MatterNetworkGraph? = null
@ -260,7 +260,7 @@ class MatterPanelMenu @JvmOverloads constructor(
override fun broadcastChanges() {
super.broadcastChanges()
if (!initial_send) fullPatternBroadcast()
if (!initialSend) fullPatternBroadcast()
}
private fun sendNetwork(packet: Any) {
@ -269,7 +269,7 @@ class MatterPanelMenu @JvmOverloads constructor(
fun fullPatternBroadcast() {
if (inventory.player.level.isClientSide) {
initial_send = true
initialSend = true
return
}
@ -279,11 +279,11 @@ class MatterPanelMenu @JvmOverloads constructor(
val grid = tile.matterGraph
if (grid != null) {
initial_send = true
sendNetwork(PatternsChangePacket(true, grid.getStoredPatterns()))
initialSend = true
sendNetwork(PatternsChangePacket(true, grid.patterns.toList()))
}
sendNetwork(TasksChangePacket(true, tile.allTasks))
sendNetwork(TasksChangePacket(true, tile.allReplicationTasks.toList()))
}
}

View File

@ -36,10 +36,10 @@ class MatterScannerMenu @JvmOverloads constructor(
addSlot(input)
if (tile != null) {
progress = ProgressGaugeWidget(this, { tile.workProgress.toFloat() }, tile::isUnableToProcess)
progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess)
patterns = LevelGaugeWidget(this,
{ ImpreciseFraction(tile.matterGraph?.getPatternCount()?.toBigInteger() ?: BigInteger.ZERO) },
{ ImpreciseFraction(tile.matterGraph?.getPatternCapacity()?.toBigInteger() ?: BigInteger.ZERO) })
{ ImpreciseFraction(tile.matterGraph?.patternCount ?: 0L) },
{ ImpreciseFraction(tile.matterGraph?.patternCapacity ?: 0L) })
} else {
progress = ProgressGaugeWidget(this)
patterns = LevelGaugeWidget(this)

View File

@ -28,9 +28,9 @@ class PatternStorageMenu @JvmOverloads constructor(
} else {
storedThis = LevelGaugeWidget(this, tile)
storedGrid = LevelGaugeWidget(this, {
ImpreciseFraction(tile.matterGraph?.getPatternCount() ?: 0)
ImpreciseFraction(tile.matterGraph?.patternCount ?: 0)
}, {
ImpreciseFraction(tile.matterGraph?.getPatternCapacity() ?: 0)
ImpreciseFraction(tile.matterGraph?.patternCapacity ?: 0)
})
}