Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ public CraftingJob clone(CraftingHelpers.IIdentifierGenerator identifierGenerato
getIngredientsStorage()
);
clone.setAmountTotal(getAmountTotal());
clone.setInitiatorUuid(getInitiatorUuid());
clone.setNotifyInitiator(isNotifyInitiator());
return clone;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,12 @@ public static void scheduleCraftingJobs(ICraftingNetwork craftingNetwork,
List<CraftingJob> startedJobs = Lists.newArrayList();
craftingNetwork.getCraftingJobDependencyGraph().importDependencies(craftingJobDependencyGraph);
for (CraftingJob craftingJob : craftingJobDependencyGraph.getCraftingJobs()) {
// Set before scheduling, as scheduling may distribute the job over multiple crafting
// interfaces, in which case it is replaced by clones that have to inherit this.
if (initiator != null) {
craftingJob.setInitiatorUuid(initiator.toString());
craftingJob.setNotifyInitiator(notifyInitiator);
}
try {
craftingNetwork.scheduleCraftingJob(craftingJob, allowDistribution, storageGetter);
} catch (UnavailableCraftingInterfacesException e) {
Expand All @@ -740,10 +746,6 @@ public static void scheduleCraftingJobs(ICraftingNetwork craftingNetwork,
throw new UnavailableCraftingInterfacesException(craftingJobDependencyGraph.getCraftingJobs());
}
startedJobs.add(craftingJob);
if (initiator != null) {
craftingJob.setInitiatorUuid(initiator.toString());
craftingJob.setNotifyInitiator(notifyInitiator);
}
}
}

Expand All @@ -763,10 +765,12 @@ public static CraftingJob scheduleCraftingJob(ICraftingNetwork craftingNetwork,
CraftingJob craftingJob,
boolean allowDistribution,
@Nullable UUID initiator) throws UnavailableCraftingInterfacesException {
craftingNetwork.scheduleCraftingJob(craftingJob, allowDistribution, storageGetter);
// Set before scheduling, as scheduling may distribute the job over multiple crafting
// interfaces, in which case it is replaced by clones that have to inherit this.
if (initiator != null) {
craftingJob.setInitiatorUuid(initiator.toString());
}
craftingNetwork.scheduleCraftingJob(craftingJob, allowDistribution, storageGetter);
return craftingJob;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.common.NeoForge;
Expand All @@ -26,6 +27,7 @@
import org.cyclops.integrateddynamics.api.network.IPositionedAddonsNetworkIngredients;
import org.cyclops.integrateddynamics.core.helper.NetworkHelpers;

import java.util.Iterator;
import java.util.List;
import java.util.UUID;

Expand Down Expand Up @@ -120,6 +122,58 @@ public void testNoEventOnCancelledJob(GameTestHelper helper) {
.thenSucceed();
}

/**
* A job that is distributed over multiple crafting interfaces stays attributed to its initiator.
*/
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
public void testDistributedJobRetainsInitiator(GameTestHelper helper) {
GameTestHelpersIntegratedCrafting.INetworkPositions<PartTypeInterfaceCrafting.State> positions =
GameTestHelpersIntegratedCrafting.createBasicNetwork(helper, POS, false,
Blocks.CRAFTING_TABLE, Blocks.CRAFTING_TABLE);
ChestBlockEntity chest = helper.getBlockEntity(POS.east());
chest.setItem(0, new ItemStack(Items.OAK_PLANKS, 64));

// Both interfaces know the recipe, so the job gets split over the two of them
for (int i = 0; i < positions.interfaceRecipeAdders().size(); i++) {
positions.interfaceRecipeAdders().get(i).accept(Triple.of(0, RecipeType.CRAFTING,
ResourceLocation.fromNamespaceAndPath("minecraft", "chest")));
}

UUID initiator = UUID.randomUUID();
EventCollector collector = EventCollector.start(initiator);

helper.startSequence()
.thenIdle(20)
.thenExecute(() -> {
scheduleChestJob(helper, initiator, true, 4);

List<CraftingJob> jobs = getCraftingJobs(helper);
helper.assertTrue(jobs.size() > 1,
"Expected the job to be split over both crafting interfaces, but found "
+ jobs.size() + " job(s)");
for (CraftingJob craftingJob : jobs) {
helper.assertTrue(initiator.toString().equals(craftingJob.getInitiatorUuid()),
"A split job lost its initiator");
helper.assertTrue(craftingJob.isNotifyInitiator(),
"A split job lost its notify flag");
}
})
.thenWaitUntil(() -> helper.assertTrue(!collector.getRootJobs().isEmpty(),
"No completion event was emitted for the distributed job"))
.thenExecute(collector::stop)
.thenSucceed();
}

private static List<CraftingJob> getCraftingJobs(GameTestHelper helper) {
List<CraftingJob> jobs = Lists.newArrayList();
Iterator<CraftingJob> it = CraftingHelpers.getCraftingNetworkChecked(getNetwork(helper))
.getCraftingJobs(IPositionedAddonsNetworkIngredients.WILDCARD_CHANNEL);
while (it.hasNext()) {
jobs.add(it.next());
}
return jobs;
}

private static void prepareNetwork(GameTestHelper helper) {
GameTestHelpersIntegratedCrafting.INetworkPositions<PartTypeInterfaceCrafting.State> positions =
GameTestHelpersIntegratedCrafting.createBasicNetwork(helper, POS);
Expand All @@ -134,12 +188,17 @@ private static void prepareNetwork(GameTestHelper helper) {
}

private static CraftingJob scheduleChestJob(GameTestHelper helper, UUID initiator, boolean notifyInitiator) {
return scheduleChestJob(helper, initiator, notifyInitiator, 1);
}

private static CraftingJob scheduleChestJob(GameTestHelper helper, UUID initiator, boolean notifyInitiator,
int amount) {
INetwork network = getNetwork(helper);
int channel = IPositionedAddonsNetworkIngredients.DEFAULT_CHANNEL;
try {
CraftingJobDependencyGraph dependencyGraph = new CraftingJobDependencyGraph();
CraftingJob craftingJob = CraftingHelpers.calculateCraftingJobs(network, channel,
IngredientComponents.ITEMSTACK, new ItemStack(Items.CHEST), ItemMatch.ITEM, true,
IngredientComponents.ITEMSTACK, new ItemStack(Items.CHEST, amount), ItemMatch.ITEM, true,
CraftingHelpers.getGlobalCraftingJobIdentifier(), dependencyGraph, false);
CraftingHelpers.scheduleCraftingJobs(CraftingHelpers.getCraftingNetworkChecked(network),
CraftingHelpers.getNetworkStorageGetter(network, channel, false), dependencyGraph, true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,25 @@ public void testAmountTotalIsUnaffectedByCrafting() {
assertThat(job.getAmountTotal(), equalTo(3));
}

@Test
public void testCloneRetainsInitiator() {
// Jobs are cloned when they are distributed over multiple crafting interfaces,
// so the clones have to remain attributable to whoever requested them.
job.setInitiatorUuid("00000000-0000-0000-0000-00000000beef");
job.setNotifyInitiator(true);

CraftingJob clone = job.clone(() -> 1);

assertThat(clone.getInitiatorUuid(), equalTo("00000000-0000-0000-0000-00000000beef"));
assertThat(clone.isNotifyInitiator(), equalTo(true));
}

@Test
public void testCloneWithoutInitiator() {
CraftingJob clone = job.clone(() -> 1);

assertThat(clone.getInitiatorUuid(), equalTo(null));
assertThat(clone.isNotifyInitiator(), equalTo(false));
}

}
Loading