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 org.jetbrains.annotations.NotNull;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive; import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler; 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.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode; import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode;
@ -36,7 +36,7 @@ public class MatteryCapability {
@Nonnull @Nonnull
@NotNull @NotNull
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IReplicationTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull @Nonnull
@NotNull @NotNull
@ -56,7 +56,7 @@ public class MatteryCapability {
event.register(MatteryPlayerCapability.class); event.register(MatteryPlayerCapability.class);
event.register(IMatterHandler.class); event.register(IMatterHandler.class);
event.register(IPatternStorage.class); event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class); event.register(IReplicationTaskProvider.class);
event.register(IMatteryDrive.class); event.register(IMatteryDrive.class);
event.register(IStorageGraphNode.class); event.register(IStorageGraphNode.class);
event.register(IMatterGraphNode.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 package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.Streams
import javax.annotation.ParametersAreNonnullByDefault import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState 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.registry.MBlockEntities
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import java.util.ArrayList import java.util.ArrayList
import java.util.stream.Stream
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
@ -50,13 +52,13 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (grid != null && !ItemStack.isSameItemSameTags(new, old)) { if (grid != null && !ItemStack.isSameItemSameTags(new, old)) {
if (!old.isEmpty) { if (!old.isEmpty) {
old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) } cap.storedPatterns.forEach { grid.onPatternRemoved(it) }
} }
} }
if (!new.isEmpty) { if (!new.isEmpty) {
new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> 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) return PatternStorageMenu(containerID, inventory, this)
} }
override val storedPatterns: Collection<PatternState> get() { override val storedPatterns: Stream<out IPatternState> get() {
val list = ArrayList<PatternState>() val streams = ArrayList<Stream<out IPatternState>>()
patterns.forEachCapability(MatteryCapability.PATTERN) { capability: IPatternStorage -> list.addAll(capability.storedPatterns) }
return list for (provider in patterns.iterator(MatteryCapability.PATTERN)) {
streams.add(provider.second.storedPatterns)
}
return Streams.concat(*streams.toTypedArray())
} }
override val capacity: Int get() { override val capacity: Int get() {
@ -176,9 +182,9 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus { override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for ((_, storage) in patterns.iterator(MatteryCapability.PATTERN)) { for (pair in patterns.iterator(MatteryCapability.PATTERN)) {
val status = storage.insertPattern(pattern, only_update, simulate) val status = pair.second.insertPattern(pattern, onlyUpdate, simulate)
if (!status.isFailed) { if (!status.isFailed) {
if (!simulate) { 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.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player 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 ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.HashMap import java.util.HashMap
import java.util.UUID 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.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
@ -25,15 +20,16 @@ import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity 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.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.ArrayList import java.util.ArrayList
import java.util.List import java.util.stream.Stream
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : 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>() private val listeners = ArrayList<MatterPanelMenu>()
override val matterNode = Graph6Node<IMatterGraphNode>(this) override val matterNode = Graph6Node<IMatterGraphNode>(this)
@ -88,61 +84,59 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun getTaskHandler(): IMatterTaskProvider? { override fun getTaskHandler(): IReplicationTaskProvider {
return this return this
} }
private val _tasks = HashMap<UUID, MatterTask>() private val _tasks = HashMap<UUID, ReplicationTask>()
override val tasks: Collection<MatterTask> get() { override val replicationTasks: Stream<ReplicationTask> get() {
return _tasks.values.stream().filter { task: MatterTask? -> task!!.required() > 0 }.collect(Collectors.toList()) as Collection<MatterTask> return _tasks.values.stream().filter { it.required > 0 }
} }
override val allTasks: Collection<MatterTask> get() { override val allReplicationTasks: Stream<ReplicationTask> get() {
return List.copyOf(_tasks.values) as Collection<MatterTask> return _tasks.values.stream()
} }
override fun allocateTask(simulate: Boolean): MatterTaskAllocation? { override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
val graph = matterNode.graph as MatterNetworkGraph? ?: return null val graph = matterNode.graph as MatterNetworkGraph? ?: return null
for ((key, task) in _tasks) { for ((key, task) in _tasks) {
if (task.required > 0) { if (task.required > 0) {
val getPattern = graph.getPattern(task.pattern!!) val pattern = task.patternId?.let(graph::getPattern) ?: continue
if (getPattern != null) {
if (!simulate) { if (!simulate) {
val new = task.shrinkRequired(1) val new = task.allocate()
_tasks[key] = new _tasks[key] = new
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(new) } listeners.forEach { it.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task) graph.onMatterTaskUpdated(new, task)
setChanged() setChanged()
} }
return MatterTaskAllocation(task, getPattern) return ReplicationTaskAllocation(task, pattern)
}
} }
} }
return null return null
} }
override fun notifyTaskCompletion(task: MatterTask): Boolean { override fun notifyTaskCompletion(taskId: UUID): Boolean {
var localTask = _tasks[task.id] ?: return false var localTask = _tasks[taskId] ?: return false
val oldTask = localTask val oldTask = localTask
localTask = localTask.shrinkInProgress(1) localTask = localTask.finish()
val graph = matterNode.graph as MatterNetworkGraph? val graph = matterNode.graph as MatterNetworkGraph?
// Задача полностью выполнена // Задача полностью выполнена
if (localTask.required <= 0 && localTask.in_progress <= 0) { if (localTask.required <= 0 && localTask.inProgress <= 0) {
_tasks.remove(task.id) _tasks.remove(taskId)
graph?.onMatterTaskCreated(task) graph?.onMatterTaskFinished(localTask)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(localTask) } listeners.forEach { it.taskRemoved(localTask) }
} else { } else {
// Задача обновлена // Задача обновлена
_tasks[task.id()] = localTask _tasks[taskId] = localTask
graph?.onMatterTaskUpdated(localTask, oldTask) graph?.onMatterTaskUpdated(localTask, oldTask)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(localTask) } listeners.forEach { it.taskUpdated(localTask) }
} }
setChanged() setChanged()
@ -155,7 +149,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val list = ListTag() val list = ListTag()
for (task in _tasks.values) { for (task in _tasks.values) {
list.add(task!!.serializeNBT()) list.add(task.serializeNBT())
} }
nbt.put("tasks", list) 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()) val list = nbt.getList("tasks", Tag.TAG_COMPOUND.toInt())
for (tag in list) { for (tag in list) {
val task = MatterTask.deserializeNBT(tag) val task = ReplicationTask.deserializeNBT(tag)
if (task != null) { if (task != null) {
_tasks[task.id()] = task _tasks[task.id] = task
} }
} }
} }
override fun getTask(id: UUID): MatterTask? { override fun getTask(id: UUID): ReplicationTask? {
return _tasks[id] return _tasks[id]?.asImmutable()
} }
fun removeTask(id: UUID) { fun removeTask(id: UUID) {
@ -185,19 +179,17 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task) (matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(task) } listeners.forEach { it.taskRemoved(task) }
setChanged() setChanged()
} }
fun removeTask(state: PatternState) = removeTask(state.id) fun addTask(state: IPatternState, count: Int): IReplicationTask<*> {
val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count)
fun addTask(state: PatternState, how_much: Int): MatterTask { _tasks[task.id] = task
val task = MatterTask(UUID.randomUUID(), state.id, state.item, 0, 0, how_much)
_tasks[task.id()] = task
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task) (matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task) } listeners.forEach { it.taskUpdated(task) }
setChanged() setChanged()
return task return task

View File

@ -35,7 +35,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
class ReplicatorJob : ItemJob { class ReplicatorJob : ItemJob {
val matterPerTick: ImpreciseFraction val matterPerTick: ImpreciseFraction
val task: MatterTask val task: ReplicationTask
var matterValue: ImpreciseFraction var matterValue: ImpreciseFraction
val pattern: PatternState? val pattern: PatternState?
val asDust: Boolean val asDust: Boolean
@ -45,13 +45,13 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterValue = tag.getImpreciseFraction("value") matterValue = tag.getImpreciseFraction("value")
pattern = tag.map("pattern", PatternState::deserializeNBT) pattern = tag.map("pattern", PatternState::deserializeNBT)
asDust = tag.getBoolean("as_dust") 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( constructor(
itemStack: ItemStack, itemStack: ItemStack,
matterPerTick: ImpreciseFraction, matterPerTick: ImpreciseFraction,
task: MatterTask, task: ReplicationTask,
matterValue: ImpreciseFraction, matterValue: ImpreciseFraction,
pattern: PatternState?, pattern: PatternState?,
asDust: Boolean, asDust: Boolean,
@ -93,7 +93,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return Status.FAILURE_WAIT return Status.FAILURE_WAIT
} }
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task) (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS return Status.SUCCESS
} }
@ -101,23 +101,23 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return Status.FAILURE_ITEM return Status.FAILURE_ITEM
} }
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task) (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS return Status.SUCCESS
} }
override fun onMatterTaskCreated(task: MatterTask) { override fun onMatterTaskCreated(task: IReplicationTask<*>) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
} }
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) { override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
} }
override fun onPatternAdded(state: PatternState) { override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
@ -149,10 +149,10 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return ReplicatorJob( return ReplicatorJob(
itemStack = stack, itemStack = stack,
matterPerTick = matter.value / ticks, matterPerTick = matter.value / ticks,
task = allocation.task, task = allocation.task.asImmutable(),
matterValue = matter.value, matterValue = matter.value,
pattern = allocation.pattern, pattern = allocation.pattern?.asImmutable(),
asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.research ?: 2.0), asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.researchPercent ?: 2.0),
ticks = ticks, ticks = ticks,
) to null ) 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.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage 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.capability.matter.PatternState
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
@ -47,19 +48,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}) })
// IMatterGraphNode // IMatterGraphNode
override fun onPatternAdded(state: PatternState) { override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
} }
override fun onPatternRemoved(state: PatternState) { override fun onPatternRemoved(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
} }
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) { override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
} }
@ -122,22 +123,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val stack = job.itemStack val stack = job.itemStack
if (stack.isEmpty || !hasMatterValue(stack)) return Status.SUCCESS if (stack.isEmpty || !hasMatterValue(stack)) return Status.SUCCESS
val getState = grid.findPatterns(stack.item) var findState: IPatternState? = null
var findState: PatternState? = null
for (state in getState) { for (state in grid.patterns.filter { it.item === stack.item }) {
if (state.item() === stack.item) { if (findState == null && state.researchPercent < 1.0) {
if (findState == null && state.research() < 1.0) {
findState = state findState = state
} else if (findState != null && findState.research() < state.research()) { } else if (findState != null && findState.researchPercent < state.researchPercent) {
findState = state findState = state
} }
} }
}
val new = val new =
if (findState != null) { if (findState != null) {
PatternState(findState.id(), stack.item, findState.research() + 0.2) PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else { } else {
PatternState(UUID.randomUUID(), stack.item, 0.2) PatternState(UUID.randomUUID(), stack.item, 0.2)
} }
@ -159,20 +157,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val stack = container.getItem(0) val stack = container.getItem(0)
if (stack.isEmpty || !canDecompose(stack)) return null to IdleReason.ITEM if (stack.isEmpty || !canDecompose(stack)) return null to IdleReason.ITEM
val getState = grid.findPatterns(stack.item) var findState: IPatternState? = null
var findState: PatternState? = null
for (state in getState) { for (state in grid.patterns.filter { it.item === stack.item }) {
if (state.item === stack.item && state.research < 1.0) { if (state.researchPercent < 1.0) {
findState = state findState = state
} else if (state.item === stack.item && state.research >= 1.0) { } else if (state.researchPercent >= 1.0) {
return null to IdleReason.OBSERVING return null to IdleReason.ITEM
} }
} }
val new: PatternState = val new: IPatternState =
if (findState != null) { if (findState != null) {
PatternState(findState.id, stack.item, findState.research + 0.2) PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else { } else {
PatternState(UUID.randomUUID(), stack.item, 0.2) 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.*
import java.util.function.Predicate import java.util.function.Predicate
import java.util.stream.Collectors import java.util.stream.Collectors
import java.util.stream.Stream
interface IMatterHandler { interface IMatterHandler {
val storedMatter: ImpreciseFraction val storedMatter: ImpreciseFraction
@ -14,6 +15,7 @@ interface IMatterHandler {
fun receiveMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction fun receiveMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction fun extractMatterOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction fun extractMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
val direction: MatterDirection val direction: MatterDirection
val missingMatter: ImpreciseFraction val missingMatter: ImpreciseFraction
get() = maxStoredMatter.minus(storedMatter).moreThanZero() get() = maxStoredMatter.minus(storedMatter).moreThanZero()
@ -27,42 +29,44 @@ interface IMatterHandler {
enum class MatterDirection { RECEIVE, EXTRACT, BIDIRECTIONAL } 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 * Allocates (marks as work-in-progress) a task
* by incrementing it's in_progress by 1 * by incrementing it's [IReplicationTask.inProgress] by 1
* and shrinking required 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 * @param simulate whenever to change internal state
* @return MatterTaskAllocation(task, pattern) that should be performed, or null if no work is available * @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 * Notify about task completion. If this provider indeed contain this task, it should
* shrink in_progress by 1 * shrink in_progress by 1
* If in_progress == 0 and required == 0, it should discard the task * 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 * @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 * @param id uuid of task
* @return MatterTask that this capability holds with this id, or null * @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 * Destroys all tasks this capability contains
@ -72,50 +76,36 @@ interface IMatterTaskProvider {
interface IPatternStorage { 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> { fun findPatterns(item: Item): Collection<IPatternState> {
return findPatterns { item2: PatternState -> item == item2.item() } return findPatterns { item == it.item }
} }
fun findPatterns(predicate: Predicate<PatternState>?): Collection<PatternState> { fun findPatterns(predicate: Predicate<IPatternState>): Collection<IPatternState> {
return storedPatterns.stream().filter(predicate).collect(Collectors.toList()) return storedPatterns.filter(predicate).collect(Collectors.toList())
} }
fun findPattern(item: Item): PatternState? { fun findPattern(item: Item): IPatternState? {
return findPattern { item2: PatternState -> item == item2.item() } return storedPatterns.filter { it.item == item }.findAny().orElse(null)
} }
fun findPattern(predicate: Predicate<PatternState>): PatternState? { fun getPattern(id: UUID?): IPatternState? {
for (pattern in storedPatterns) { return storedPatterns.filter { it.id == id }.findAny().orElse(null)
if (predicate.test(pattern)) {
return pattern
}
} }
return null fun hasPattern(item: Item): Boolean {
return storedPatterns.filter { it.item == item }.findAny().isPresent
} }
fun getPattern(id: UUID?): PatternState? { fun hasPattern(state: IPatternState): Boolean {
id ?: return null return hasPattern(state.id)
for (pattern in storedPatterns) {
if (pattern.id == id) {
return pattern
}
}
return null
}
fun hasPattern(state: PatternState): Boolean {
return getPattern(state.id) != null
} }
fun hasPattern(id: UUID?): Boolean { fun hasPattern(id: UUID?): Boolean {
return getPattern(id) != null return storedPatterns.filter { it.id == id }.findAny().isPresent
} }
val capacity: Int val capacity: Int
@ -126,17 +116,17 @@ interface IPatternStorage {
* and if it fail, try only_update = false * and if it fail, try only_update = false
* *
* @param pattern pattern to be inserted or update value from * @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 * @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 * @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) return insertPattern(pattern, false, simulate)
} }
fun updatePattern(pattern: PatternState, simulate: Boolean): PatternInsertStatus { fun updatePattern(pattern: IPatternState, simulate: Boolean): PatternInsertStatus {
return insertPattern(pattern, true, simulate) return insertPattern(pattern, true, simulate)
} }
} }

View File

@ -8,17 +8,17 @@ private enum class PatternInsertResult {
sealed class PatternInsertStatus( sealed class PatternInsertStatus(
private val status: PatternInsertResult, private val status: PatternInsertResult,
val newState: PatternState?, val newState: IPatternState?,
val oldState: PatternState? val oldState: IPatternState?
) { ) {
val isFailed get() = status === PatternInsertResult.FAIL val isFailed get() = status == PatternInsertResult.FAIL
val isUpdated get() = status === PatternInsertResult.UPDATED val isUpdated get() = status == PatternInsertResult.UPDATED
val isInserted get() = status === PatternInsertResult.INSERTED val isInserted get() = status == PatternInsertResult.INSERTED
} }
object PatternInsertFailure : PatternInsertStatus(PatternInsertResult.FAIL, null, null) object PatternInsertFailure : PatternInsertStatus(PatternInsertResult.FAIL, null, null)
class PatternInsertUpdated(new: PatternState, old: PatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old) class PatternInsertUpdated(new: IPatternState, old: IPatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old)
class PatternInsertInserted(new: PatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null) class PatternInsertInserted(new: IPatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null)
@JvmRecord @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.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack 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.capability.matter.PatternState
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
@ -70,7 +71,7 @@ class MatterPanelScreen(
if (isPatternView) { if (isPatternView) {
return menu.patterns.getOrNull(index)?.stack() ?: ItemStack.EMPTY return menu.patterns.getOrNull(index)?.stack() ?: ItemStack.EMPTY
} else { } 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 { menu.patterns.getOrNull(index)?.let {
list.add(TranslatableComponent( list.add(TranslatableComponent(
"otm.item.pattern.research", "otm.item.pattern.research",
String.format("%.2f", it.research() * 100.0) String.format("%.2f", it.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)) } ).withStyle(ChatFormatting.AQUA)) }
} else { } else {
menu.tasks.getOrNull(index)?.let { 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.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.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.in_progress", it.inProgress).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.finished", it.finished()).withStyle(ChatFormatting.GRAY)) list.add(TranslatableComponent("otm.gui.matter_task.finished", it.finished).withStyle(ChatFormatting.GRAY))
} }
} }
@ -115,7 +116,7 @@ class MatterPanelScreen(
return frame 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")) val frame = FramePanel.padded(this, null, 170f, 20f, TranslatableComponent("otm.container.matter_panel.task"))
object : AbstractSlotPanel(this@MatterPanelScreen, frame) { object : AbstractSlotPanel(this@MatterPanelScreen, frame) {
@ -155,7 +156,7 @@ class MatterPanelScreen(
frame.toScreenCenter() 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 frame = FramePanel.padded(this, null, 213f, (ButtonPanel.HEIGHT + 3f) * 4f, TranslatableComponent("otm.container.matter_panel.task"))
val rowTop = EditablePanel(this, frame, height = ButtonPanel.HEIGHT) val rowTop = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
@ -186,7 +187,7 @@ class MatterPanelScreen(
return super.getItemStackTooltip(stack).toMutableList().also { return super.getItemStackTooltip(stack).toMutableList().also {
it.add(TranslatableComponent( it.add(TranslatableComponent(
"otm.item.pattern.research", "otm.item.pattern.research",
String.format("%.2f", pattern.research() * 100.0) String.format("%.2f", pattern.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)) ).withStyle(ChatFormatting.AQUA))
} }
} }
@ -236,7 +237,7 @@ class MatterPanelScreen(
} catch (_: NumberFormatException) { } catch (_: NumberFormatException) {
} }
MenuNetworkChannel.sendToServer(ReplicationRequestPacket(pattern, value)) MenuNetworkChannel.sendToServer(ReplicationRequestPacket(pattern.id, value))
frame.remove() frame.remove()
} }
} }

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.core
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag 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: Tag) = put(index, value)
operator fun CompoundTag.set(index: String, value: Int) = putInt(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: IntArray) = putIntArray(index, value)
operator fun CompoundTag.set(index: String, value: LongArray) = putLongArray(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? { inline fun <R, reified T : Tag> CompoundTag.map(s: String, consumer: (T) -> R): R? {
val tag = get(s) val tag = get(s)

View File

@ -10,11 +10,17 @@ import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler 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 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 import ru.dbotthepony.mc.otm.graph.Graph6Node
interface IMatterGraphListener { interface IMatterGraphListener {
fun onPatternAdded(state: PatternState) {} fun onPatternAdded(state: IPatternState) {}
fun onPatternRemoved(state: PatternState) {} fun onPatternRemoved(state: IPatternState) {}
fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {} fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {}
fun onMatterTaskCreated(task: MatterTask) {} fun onMatterTaskCreated(task: IReplicationTask<*>) {}
fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {} fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {}
fun onMatterTaskFinished(state: MatterTask) {} fun onMatterTaskFinished(state: IReplicationTask<*>) {}
fun onMatterTaskRemoved(state: MatterTask) {} fun onMatterTaskRemoved(state: IReplicationTask<*>) {}
} }
interface IMatterGraphNode : IMatterGraphListener { interface IMatterGraphNode : IMatterGraphListener {
fun getMatterHandler(): IMatterHandler? = null fun getMatterHandler(): IMatterHandler? = null
fun getPatternHandler(): IPatternStorage? = null fun getPatternHandler(): IPatternStorage? = null
fun getTaskHandler(): IMatterTaskProvider? = null fun getTaskHandler(): IReplicationTaskProvider? = null
val matterNode: Graph6Node<IMatterGraphNode> val matterNode: Graph6Node<IMatterGraphNode>
val matterGraph: MatterNetworkGraph? get() = matterNode.graph as MatterNetworkGraph? val matterGraph: MatterNetworkGraph? get() = matterNode.graph as MatterNetworkGraph?

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.graph.matter package ru.dbotthepony.mc.otm.graph.matter
import com.google.common.collect.Streams
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.level.block.entity.BlockEntity 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.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import java.util.* import java.util.*
import kotlin.collections.ArrayList import java.util.function.Predicate
import java.util.stream.Stream
import kotlin.collections.HashSet import kotlin.collections.HashSet
@Suppress("unused") @Suppress("unused")
@ -31,26 +33,26 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
val tasks = node.value.getTaskHandler() val tasks = node.value.getTaskHandler()
if (tasks != null) { if (tasks != null) {
for (task in tasks.tasks) { for (task in tasks.replicationTasks) {
onMatterTaskRemoved(task) onMatterTaskRemoved(task)
} }
} }
for (pattern in getStoredPatterns()) { for (pattern in this.patterns) {
node.value.onPatternRemoved(pattern) node.value.onPatternRemoved(pattern)
} }
for (task in getTasks()) { for (task in this.tasks) {
node.value.onMatterTaskRemoved(task) node.value.onMatterTaskRemoved(task)
} }
} }
override fun onNodeAdded(node: Graph6Node<IMatterGraphNode>) { override fun onNodeAdded(node: Graph6Node<IMatterGraphNode>) {
for (pattern in getStoredPatterns()) { for (pattern in this.patterns) {
node.value.onPatternAdded(pattern) node.value.onPatternAdded(pattern)
} }
for (task in getTasks()) { for (task in this.tasks) {
node.value.onMatterTaskCreated(task) node.value.onMatterTaskCreated(task)
} }
@ -65,7 +67,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
val tasks = node.value.getTaskHandler() val tasks = node.value.getTaskHandler()
if (tasks != null) { if (tasks != null) {
for (task in tasks.tasks) { for (task in tasks.replicationTasks) {
onMatterTaskCreated(task) onMatterTaskCreated(task)
} }
} }
@ -103,6 +105,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO) if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch var howMuch = howMuch
var extracted = ImpreciseFraction.ZERO var extracted = ImpreciseFraction.ZERO
@ -126,6 +129,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO) if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch var howMuch = howMuch
var received = ImpreciseFraction.ZERO var received = ImpreciseFraction.ZERO
@ -149,6 +153,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
if (howMuch <= ImpreciseFraction.ZERO) if (howMuch <= ImpreciseFraction.ZERO)
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
@Suppress("name_shadowing")
var howMuch = howMuch var howMuch = howMuch
var received = ImpreciseFraction.ZERO var received = ImpreciseFraction.ZERO
@ -168,7 +173,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return received 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) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.value.getPatternHandler()
@ -184,42 +189,26 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return PatternInsertFailure return PatternInsertFailure
} }
fun insertPattern(state: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus { fun insertPattern(state: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
if (onlyUpdate) return _insertPattern(state, true, simulate) if (onlyUpdate) return doInsertPattern(state, true, simulate)
val status = _insertPattern(state, true, simulate) val status = doInsertPattern(state, true, simulate)
if (!status.isFailed) return status if (!status.isFailed) return status
return _insertPattern(state, false, simulate) return doInsertPattern(state, false, simulate)
} }
fun getTasks(): Collection<MatterTask> { val tasks: Stream<out IReplicationTask<*>> get() {
val list = ArrayList<MatterTask>() return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.replicationTasks }.toTypedArray())
for (node in nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null) {
list.addAll(tasks.tasks)
}
} }
return list val allTasks: Stream<out IReplicationTask<*>> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.allReplicationTasks }.toTypedArray())
} }
fun getStoredPatterns(): Collection<PatternState> { val patterns: Stream<out IPatternState> get() {
val list = ArrayList<PatternState>() return Streams.concat(*nodes.mapNotNull { it.value.getPatternHandler()?.storedPatterns }.toTypedArray())
for (node in nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
list.addAll(storage.storedPatterns)
}
} }
return list val patternCount: Long get() {
}
fun getPatternCount(): Long {
var value = 0L var value = 0L
for (node in nodes) { for (node in nodes) {
@ -233,7 +222,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return value return value
} }
fun getPatternCapacity(): Long { val patternCapacity: Long get() {
var value = 0L var value = 0L
for (node in nodes) { for (node in nodes) {
@ -247,7 +236,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return value return value
} }
fun getPattern(id: UUID): PatternState? { fun getPattern(id: UUID): IPatternState? {
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.value.getPatternHandler()
@ -267,15 +256,15 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun hasPattern(state: PatternState) = getPattern(state.id) != null fun hasPattern(state: PatternState) = getPattern(state.id) != null
fun hasPattern(id: UUID) = getPattern(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) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.value.getPatternHandler()
if (storage != null) { if (storage != null) {
for (state in storage.storedPatterns) { val find = storage.storedPatterns.filter(predicate).findAny()
if (predicate(state)) {
return state if (find.isPresent) {
} return find.get()
} }
} }
} }
@ -285,27 +274,13 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun findPattern(predicate: Item) = findPattern { it.item == predicate } fun findPattern(predicate: Item) = findPattern { it.item == predicate }
fun findPatterns(predicate: (PatternState) -> Boolean): Collection<PatternState> { fun findPatterns(predicate: Predicate<IPatternState>): List<IPatternState> {
val list = ArrayList<PatternState>() return patterns.filter(predicate).toList()
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: Item) = findPatterns { it.item == predicate } fun findPatterns(predicate: Item) = findPatterns { it.item == predicate }
fun allocateTask(simulate: Boolean): MatterTaskAllocation? { fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
for (node in nodes) { for (node in nodes) {
val tasks = node.value.getTaskHandler() val tasks = node.value.getTaskHandler()
@ -321,49 +296,41 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return null return null
} }
fun notifyTaskCompletion(task: MatterTask): Boolean { fun notifyTaskCompletion(taskId: UUID): Boolean {
for (node in nodes) { return nodes.any { it.value.getTaskHandler()?.notifyTaskCompletion(taskId) == true }
val tasks = node.value.getTaskHandler()
if (tasks != null && tasks.notifyTaskCompletion(task)) {
return true
}
} }
return false override fun onPatternAdded(state: IPatternState) {
}
override fun onPatternAdded(state: PatternState) {
for (node in nodes) node.value.onPatternAdded(state) for (node in nodes) node.value.onPatternAdded(state)
for (node in listeners) node.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 nodes) node.value.onPatternRemoved(state)
for (node in listeners) node.onPatternRemoved(state) for (node in listeners) node.onPatternRemoved(state)
} }
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) { override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
for (node in nodes) node.value.onPatternUpdated(new_state, old_state) for (node in nodes) node.value.onPatternUpdated(newState, oldState)
for (node in listeners) node.onPatternUpdated(new_state, old_state) 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 nodes) node.value.onMatterTaskCreated(task)
for (node in listeners) node.onMatterTaskCreated(task) for (node in listeners) node.onMatterTaskCreated(task)
} }
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) { override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {
for (node in nodes) node.value.onMatterTaskUpdated(new_state, old_state) for (node in nodes) node.value.onMatterTaskUpdated(newState, oldState)
for (node in listeners) node.onMatterTaskUpdated(new_state, old_state) 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 nodes) node.value.onMatterTaskFinished(state)
for (node in listeners) node.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 nodes) node.value.onMatterTaskRemoved(state)
for (node in listeners) node.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.capability.matter.*
import ru.dbotthepony.mc.otm.core.ifHas import ru.dbotthepony.mc.otm.core.ifHas
import java.util.* import java.util.*
import java.util.stream.Stream
class PatternStorageItem : Item { class PatternStorageItem : Item {
val capacity: Int val capacity: Int
@ -53,8 +54,8 @@ class PatternStorageItem : Item {
list.add( list.add(
TranslatableComponent( TranslatableComponent(
"otm.item.pattern.line", "otm.item.pattern.line",
state.item().getName(ItemStack(state.item(), 1)), state.item.getName(ItemStack(state.item, 1)),
String.format("%.2f", state.research() * 100.0) String.format("%.2f", state.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA) ).withStyle(ChatFormatting.AQUA)
) )
} }
@ -71,47 +72,40 @@ class PatternStorageItem : Item {
} }
override val stored: Int get() { 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> { 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) { stack.tag?.ifHas("otm_patterns", ListTag::class.java) {
val list = ArrayList<PatternState>() return it.stream().map { PatternState.deserializeNBT(it) }.filter { it != null } as Stream<out IPatternState>
for (tag in it) {
if (tag is CompoundTag) {
val state = PatternState.deserializeNBT(tag)
if (state != null)
list.add(state)
}
} }
return list return Stream.empty()
}
return emptyList()
} }
override fun insertPattern( override fun insertPattern(
pattern: PatternState, pattern: IPatternState,
only_update: Boolean, onlyUpdate: Boolean,
simulate: Boolean simulate: Boolean
): PatternInsertStatus { ): PatternInsertStatus {
val tag = stack.orCreateTag val tag = stack.orCreateTag
var list = tag["otm_patterns"] var list = tag["otm_patterns"]
if (list !is ListTag) { if (list !is ListTag) {
if (only_update) if (onlyUpdate)
return PatternInsertFailure return PatternInsertFailure
if (simulate) { if (simulate) {
if (capacity > 0) if (capacity > 0)
return PatternInsertInserted(pattern) return PatternInsertInserted(pattern.asImmutable())
else else
return PatternInsertFailure return PatternInsertFailure
} }
@ -126,24 +120,24 @@ class PatternStorageItem : Item {
val state = PatternState.deserializeNBT(list.getCompound(i)) val state = PatternState.deserializeNBT(list.getCompound(i))
if (state != null) { if (state != null) {
if (state == pattern) { if (state.id == pattern.id) {
if (!simulate) { if (!simulate) {
list[i] = pattern.serializeNBT() list[i] = pattern.serializeNBT()
} }
return PatternInsertUpdated(pattern, state) return PatternInsertUpdated(pattern.asImmutable(), state)
} }
} else { } else {
invalidCounter++ invalidCounter++
} }
} }
if (only_update || capacity <= list.size - invalidCounter) if (onlyUpdate || capacity <= list.size - invalidCounter)
return PatternInsertFailure return PatternInsertFailure
if (invalidCounter > 0) { if (invalidCounter > 0) {
if (simulate) if (simulate)
return PatternInsertInserted(pattern) return PatternInsertInserted(pattern.asImmutable())
for (i in list.indices) { for (i in list.indices) {
val state = PatternState.deserializeNBT(list.getCompound(i)) val state = PatternState.deserializeNBT(list.getCompound(i))

View File

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

View File

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