Skip to content

Commit

Permalink
Merge pull request #783 from refinedmods/feat/GH-612/persist-tasks
Browse files Browse the repository at this point in the history
Persist autocrafting tasks
  • Loading branch information
raoulvdberge authored Jan 27, 2025
2 parents a79bc0d + 5af56b4 commit 1ae1b0f
Show file tree
Hide file tree
Showing 18 changed files with 753 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ abstract PatternStepResult step(MutableResourceList internalStorage,

abstract RootStorageListener.InterceptResult interceptInsertion(ResourceKey resource, long amount);

abstract TaskSnapshot.PatternSnapshot createSnapshot();

abstract void appendStatus(TaskStatusBuilder builder);

abstract long getWeight();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import org.apiguardian.api.API;

@FunctionalInterface
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
public interface ExternalPatternInputSinkKey {
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.Objects.requireNonNull;

class ExternalTaskPattern extends AbstractTaskPattern {
private static final Logger LOGGER = LoggerFactory.getLogger(ExternalTaskPattern.class);

private final MutableResourceList expectedOutputs = MutableResourceListImpl.create();
private final MutableResourceList expectedOutputs;
private final ResourceList simulatedIterationInputs;
private final long originalIterationsToSendToSink;
private long iterationsToSendToSink;
Expand All @@ -33,13 +35,30 @@ class ExternalTaskPattern extends AbstractTaskPattern {
ExternalTaskPattern(final Pattern pattern, final TaskPlan.PatternPlan plan) {
super(pattern, plan);
this.originalIterationsToSendToSink = plan.iterations();
this.expectedOutputs = MutableResourceListImpl.create();
pattern.outputs().forEach(
output -> expectedOutputs.add(output.resource(), output.amount() * plan.iterations())
);
this.iterationsToSendToSink = plan.iterations();
this.simulatedIterationInputs = calculateIterationInputs(Action.SIMULATE);
}

ExternalTaskPattern(final TaskSnapshot.PatternSnapshot snapshot) {
super(snapshot.pattern(), new TaskPlan.PatternPlan(
snapshot.root(),
requireNonNull(snapshot.externalPattern()).originalIterationsToSendToSink(),
snapshot.ingredients()
));
this.expectedOutputs = snapshot.externalPattern().copyExpectedOutputs();
this.simulatedIterationInputs = snapshot.externalPattern().simulatedIterationInputs();
this.originalIterationsToSendToSink = snapshot.externalPattern().originalIterationsToSendToSink();
this.iterationsToSendToSink = snapshot.externalPattern().iterationsToSendToSink();
this.iterationsReceived = snapshot.externalPattern().iterationsReceived();
this.interceptedAnythingSinceLastStep = snapshot.externalPattern().interceptedAnythingSinceLastStep();
this.lastSinkResult = snapshot.externalPattern().lastSinkResult();
this.lastSinkResultKey = snapshot.externalPattern().lastSinkResultKey();
}

@Override
PatternStepResult step(final MutableResourceList internalStorage,
final RootStorage rootStorage,
Expand Down Expand Up @@ -168,4 +187,24 @@ private boolean acceptsIterationInputs(final MutableResourceList internalStorage
}
return true;
}

@Override
TaskSnapshot.PatternSnapshot createSnapshot() {
return new TaskSnapshot.PatternSnapshot(
root,
pattern,
ingredients,
null,
new TaskSnapshot.ExternalPatternSnapshot(
expectedOutputs.copy(),
simulatedIterationInputs,
originalIterationsToSendToSink,
iterationsToSendToSink,
iterationsReceived,
interceptedAnythingSinceLastStep,
lastSinkResult,
lastSinkResultKey
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.Objects.requireNonNull;

class InternalTaskPattern extends AbstractTaskPattern {
private static final Logger LOGGER = LoggerFactory.getLogger(InternalTaskPattern.class);

Expand All @@ -26,6 +28,16 @@ class InternalTaskPattern extends AbstractTaskPattern {
this.iterationsRemaining = plan.iterations();
}

InternalTaskPattern(final TaskSnapshot.PatternSnapshot snapshot) {
super(snapshot.pattern(), new TaskPlan.PatternPlan(
snapshot.root(),
requireNonNull(snapshot.internalPattern()).originalIterationsRemaining(),
snapshot.ingredients()
));
this.originalIterationsRemaining = snapshot.internalPattern().originalIterationsRemaining();
this.iterationsRemaining = snapshot.internalPattern().iterationsRemaining();
}

@Override
PatternStepResult step(final MutableResourceList internalStorage,
final RootStorage rootStorage,
Expand Down Expand Up @@ -89,4 +101,15 @@ protected PatternStepResult useIteration() {
LOGGER.debug("Stepped {} with {} iterations remaining", pattern, iterationsRemaining);
return iterationsRemaining == 0 ? PatternStepResult.COMPLETED : PatternStepResult.RUNNING;
}

@Override
TaskSnapshot.PatternSnapshot createSnapshot() {
return new TaskSnapshot.PatternSnapshot(
root,
pattern,
ingredients,
new TaskSnapshot.InternalPatternSnapshot(originalIterationsRemaining, iterationsRemaining),
null
);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;

import com.refinedmods.refinedstorage.api.autocrafting.status.TaskStatus;
import com.refinedmods.refinedstorage.api.resource.ResourceAmount;
import com.refinedmods.refinedstorage.api.resource.ResourceKey;
import com.refinedmods.refinedstorage.api.storage.Actor;
import com.refinedmods.refinedstorage.api.storage.root.RootStorage;
import com.refinedmods.refinedstorage.api.storage.root.RootStorageListener;

import java.util.Collection;

import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
Expand All @@ -25,8 +22,6 @@ public interface Task extends RootStorageListener {

TaskState getState();

Collection<ResourceAmount> copyInternalStorageState();

boolean step(RootStorage rootStorage, ExternalPatternInputSink externalPatternInputSink, StepBehavior stepBehavior);

void cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import com.refinedmods.refinedstorage.api.autocrafting.status.TaskStatus;
import com.refinedmods.refinedstorage.api.autocrafting.status.TaskStatusBuilder;
import com.refinedmods.refinedstorage.api.core.Action;
import com.refinedmods.refinedstorage.api.resource.ResourceAmount;
import com.refinedmods.refinedstorage.api.resource.ResourceKey;
import com.refinedmods.refinedstorage.api.resource.list.MutableResourceList;
import com.refinedmods.refinedstorage.api.resource.list.MutableResourceListImpl;
import com.refinedmods.refinedstorage.api.storage.Actor;
import com.refinedmods.refinedstorage.api.storage.root.RootStorage;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -26,35 +24,58 @@
public class TaskImpl implements Task {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskImpl.class);

private final TaskId id = TaskId.create();
private final TaskId id;
private final ResourceKey resource;
private final long amount;
private final Actor actor;
private final boolean notify;
private final long startTime = System.currentTimeMillis();
private final long startTime;
private final Map<Pattern, AbstractTaskPattern> patterns;
private final List<AbstractTaskPattern> completedPatterns = new ArrayList<>();
private final MutableResourceList initialRequirements = MutableResourceListImpl.create();
private final MutableResourceList initialRequirements;
private final MutableResourceList internalStorage;
private TaskState state = TaskState.READY;
private boolean cancelled;

public TaskImpl(final TaskSnapshot snapshot) {
this.id = snapshot.id();
this.resource = snapshot.resource();
this.amount = snapshot.amount();
this.actor = snapshot.actor();
this.notify = snapshot.notifyActor();
this.startTime = snapshot.startTime();
this.patterns = snapshot.patterns().entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().toTaskPattern(),
(a, b) -> a,
LinkedHashMap::new
));
snapshot.completedPatterns().forEach(patternSnapshot -> completedPatterns.add(patternSnapshot.toTaskPattern()));
this.initialRequirements = snapshot.copyInitialRequirements();
this.internalStorage = snapshot.copyInternalStorage();
this.state = snapshot.state();
this.cancelled = snapshot.cancelled();
}

public TaskImpl(final TaskPlan plan, final Actor actor, final boolean notify) {
this(plan, MutableResourceListImpl.create(), actor, notify);
}

TaskImpl(final TaskPlan plan, final MutableResourceList internalStorage, final Actor actor, final boolean notify) {
this.id = TaskId.create();
this.internalStorage = internalStorage;
this.resource = plan.resource();
this.amount = plan.amount();
this.actor = actor;
this.notify = notify;
this.startTime = System.currentTimeMillis();
this.patterns = plan.patterns().entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
e -> createTaskPattern(e.getKey(), e.getValue()),
(a, b) -> a,
LinkedHashMap::new
));
this.initialRequirements = MutableResourceListImpl.create();
plan.initialRequirements().forEach(initialRequirements::add);
}

Expand Down Expand Up @@ -140,6 +161,32 @@ public TaskStatus getStatus() {
return builder.build(totalWeight == 0 ? 0 : totalWeightedCompleted / totalWeight);
}

public TaskSnapshot createSnapshot() {
return new TaskSnapshot(
id,
resource,
amount,
actor,
notify,
startTime,
patterns.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().createSnapshot(),
(a, b) -> a,
LinkedHashMap::new
)),
completedPatterns.stream()
.filter(InternalTaskPattern.class::isInstance)
.map(InternalTaskPattern.class::cast)
.map(InternalTaskPattern::createSnapshot)
.toList(),
initialRequirements.copy(),
internalStorage.copy(),
state,
cancelled
);
}

private boolean startTask(final RootStorage rootStorage) {
updateState(TaskState.EXTRACTING_INITIAL_RESOURCES);
return extractInitialResourcesAndTryStartRunningTask(rootStorage);
Expand Down Expand Up @@ -243,11 +290,6 @@ private boolean returnInternalStorageAndTryCompleteTask(final RootStorage rootSt
return returnedAny;
}

@Override
public Collection<ResourceAmount> copyInternalStorageState() {
return internalStorage.copyState();
}

@Override
public InterceptResult beforeInsert(final ResourceKey insertedResource,
final long insertedAmount,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;

import com.refinedmods.refinedstorage.api.autocrafting.Pattern;
import com.refinedmods.refinedstorage.api.resource.ResourceKey;
import com.refinedmods.refinedstorage.api.resource.list.MutableResourceList;
import com.refinedmods.refinedstorage.api.resource.list.MutableResourceListImpl;
import com.refinedmods.refinedstorage.api.resource.list.ResourceList;
import com.refinedmods.refinedstorage.api.storage.Actor;

import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

public record TaskSnapshot(
TaskId id,
ResourceKey resource,
long amount,
Actor actor,
boolean notifyActor,
long startTime,
Map<Pattern, PatternSnapshot> patterns,
List<PatternSnapshot> completedPatterns,
ResourceList initialRequirements,
ResourceList internalStorage,
TaskState state,
boolean cancelled
) {
MutableResourceList copyInitialRequirements() {
final MutableResourceList copy = MutableResourceListImpl.create();
initialRequirements.getAll().forEach(key -> copy.add(key, initialRequirements.get(key)));
return copy;
}

public MutableResourceList copyInternalStorage() {
final MutableResourceList copy = MutableResourceListImpl.create();
internalStorage.getAll().forEach(key -> copy.add(key, internalStorage.get(key)));
return copy;
}

public record PatternSnapshot(
boolean root,
Pattern pattern,
Map<Integer, Map<ResourceKey, Long>> ingredients,
@Nullable InternalPatternSnapshot internalPattern,
@Nullable ExternalPatternSnapshot externalPattern
) {
AbstractTaskPattern toTaskPattern() {
return internalPattern != null ? new InternalTaskPattern(this) : new ExternalTaskPattern(this);
}
}

public record InternalPatternSnapshot(long originalIterationsRemaining, long iterationsRemaining) {
}

public record ExternalPatternSnapshot(
ResourceList expectedOutputs,
ResourceList simulatedIterationInputs,
long originalIterationsToSendToSink,
long iterationsToSendToSink,
long iterationsReceived,
boolean interceptedAnythingSinceLastStep,
@Nullable
ExternalPatternInputSink.Result lastSinkResult,
@Nullable
ExternalPatternInputSinkKey lastSinkResultKey
) {
MutableResourceList copyExpectedOutputs() {
final MutableResourceList copy = MutableResourceListImpl.create();
expectedOutputs.getAll().forEach(key -> copy.add(key, expectedOutputs.get(key)));
return copy;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ public ExternalPatternInputSinkKey getKey(final Pattern pattern) {
}

record SinkKey(Pattern pattern) implements ExternalPatternInputSinkKey {
@Override
public String getName() {
return pattern.id().toString();
}
}

static class Sink {
Expand Down
Loading

0 comments on commit 1ae1b0f

Please sign in to comment.