1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-20 03:35:51 +00:00

RecipeChoice task is now thread-safe

This commit is contained in:
TheBusyBiscuit 2021-02-06 00:29:57 +01:00
parent a25b470272
commit 2d050a8e35
7 changed files with 58 additions and 23 deletions

View File

@ -41,7 +41,7 @@ import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock;
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine;
import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.RecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem; import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem;
@ -408,7 +408,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
ItemStack result = null; ItemStack result = null;
Optional<MinecraftRecipe<? super Recipe>> optional = MinecraftRecipe.of(recipe); Optional<MinecraftRecipe<? super Recipe>> optional = MinecraftRecipe.of(recipe);
RecipeChoiceTask task = new RecipeChoiceTask(); AsyncRecipeChoiceTask task = new AsyncRecipeChoiceTask();
if (optional.isPresent()) { if (optional.isPresent()) {
showRecipeChoices(recipe, recipeItems, task); showRecipeChoices(recipe, recipeItems, task);
@ -454,7 +454,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
} }
} }
private <T extends Recipe> void showRecipeChoices(T recipe, ItemStack[] recipeItems, RecipeChoiceTask task) { private <T extends Recipe> void showRecipeChoices(T recipe, ItemStack[] recipeItems, AsyncRecipeChoiceTask task) {
RecipeChoice[] choices = SlimefunPlugin.getMinecraftRecipeService().getRecipeShape(recipe); RecipeChoice[] choices = SlimefunPlugin.getMinecraftRecipeService().getRecipeShape(recipe);
if (choices.length == 1 && choices[0] instanceof MaterialChoice) { if (choices.length == 1 && choices[0] instanceof MaterialChoice) {
@ -496,7 +496,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
}); });
} }
RecipeChoiceTask task = new RecipeChoiceTask(); AsyncRecipeChoiceTask task = new AsyncRecipeChoiceTask();
if (addToHistory) { if (addToHistory) {
profile.getGuideHistory().add(item); profile.getGuideHistory().add(item);
@ -519,7 +519,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
} }
} }
private void displayItem(ChestMenu menu, PlayerProfile profile, Player p, Object item, ItemStack output, RecipeType recipeType, ItemStack[] recipe, RecipeChoiceTask task) { private void displayItem(ChestMenu menu, PlayerProfile profile, Player p, Object item, ItemStack output, RecipeType recipeType, ItemStack[] recipe, AsyncRecipeChoiceTask task) {
addBackButton(menu, 0, p, profile); addBackButton(menu, 0, p, profile);
MenuClickHandler clickHandler = (pl, slot, itemstack, action) -> { MenuClickHandler clickHandler = (pl, slot, itemstack, action) -> {

View File

@ -31,7 +31,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.RecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
@ -205,7 +205,7 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
return false; return false;
}); });
RecipeChoiceTask task = new RecipeChoiceTask(); AsyncRecipeChoiceTask task = new AsyncRecipeChoiceTask();
recipe.show(menu, task); recipe.show(menu, task);
menu.open(p); menu.open(p);

View File

@ -13,7 +13,7 @@ import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.RecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -42,7 +42,7 @@ public abstract class AbstractRecipe {
return result; return result;
} }
public abstract void show(@Nonnull ChestMenu menu, @Nonnull RecipeChoiceTask task); public abstract void show(@Nonnull ChestMenu menu, @Nonnull AsyncRecipeChoiceTask task);
@Nullable @Nullable
public static AbstractRecipe of(@Nullable Recipe recipe) { public static AbstractRecipe of(@Nullable Recipe recipe) {

View File

@ -7,7 +7,7 @@ import javax.annotation.Nonnull;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.EnhancedCraftingTable; import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.EnhancedCraftingTable;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.RecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
@ -39,7 +39,7 @@ class EnhancedRecipe extends AbstractRecipe {
} }
@Override @Override
public void show(@Nonnull ChestMenu menu, @Nonnull RecipeChoiceTask task) { public void show(@Nonnull ChestMenu menu, @Nonnull AsyncRecipeChoiceTask task) {
menu.addItem(24, getResult().clone(), ChestMenuUtils.getEmptyClickHandler()); menu.addItem(24, getResult().clone(), ChestMenuUtils.getEmptyClickHandler());
ItemStack[] recipe = item.getRecipe(); ItemStack[] recipe = item.getRecipe();

View File

@ -21,12 +21,14 @@ import org.bukkit.inventory.ShapelessRecipe;
import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI; import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
public class VanillaAutoCrafter extends AbstractAutoCrafter { public class VanillaAutoCrafter extends AbstractAutoCrafter {
@ -90,6 +92,11 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
// TODO Choose vanilla recipe // TODO Choose vanilla recipe
} }
} }
@ParametersAreNonnullByDefault
private void offerRecipe(Player p, Block b, List<Recipe> recipes, int page, BlockMenu menu, AsyncRecipeChoiceTask task) {
}
@Nonnull @Nonnull
private List<Recipe> getRecipesFor(@Nonnull ItemStack item) { private List<Recipe> getRecipesFor(@Nonnull ItemStack item) {

View File

@ -15,7 +15,7 @@ import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.RecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
@ -68,7 +68,7 @@ class VanillaRecipe extends AbstractRecipe {
} }
@Override @Override
public void show(@Nonnull ChestMenu menu, @Nonnull RecipeChoiceTask task) { public void show(@Nonnull ChestMenu menu, @Nonnull AsyncRecipeChoiceTask task) {
menu.addItem(24, getResult().clone(), ChestMenuUtils.getEmptyClickHandler()); menu.addItem(24, getResult().clone(), ChestMenuUtils.getEmptyClickHandler());
RecipeChoice[] choices = SlimefunPlugin.getMinecraftRecipeService().getRecipeShape(recipe); RecipeChoice[] choices = SlimefunPlugin.getMinecraftRecipeService().getRecipeShape(recipe);
ItemStack[] items = new ItemStack[9]; ItemStack[] items = new ItemStack[9];

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.tasks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -19,7 +21,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
/** /**
* A {@link RecipeChoiceTask} is an asynchronously repeating task that cycles * A {@link AsyncRecipeChoiceTask} is an asynchronously repeating task that cycles
* through the different variants of {@link Material} that a {@link MaterialChoice} or {@link Tag} can represent. * through the different variants of {@link Material} that a {@link MaterialChoice} or {@link Tag} can represent.
* *
* It is used in the {@link SurvivalSlimefunGuide} for any {@link ItemStack} from Minecraft * It is used in the {@link SurvivalSlimefunGuide} for any {@link ItemStack} from Minecraft
@ -28,11 +30,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunG
* @author TheBusyBiscuit * @author TheBusyBiscuit
* *
*/ */
public class RecipeChoiceTask implements Runnable { public class AsyncRecipeChoiceTask implements Runnable {
private static final int UPDATE_INTERVAL = 14; private static final int UPDATE_INTERVAL = 14;
private final Map<Integer, LoopIterator<Material>> iterators = new HashMap<>(); private final Map<Integer, LoopIterator<Material>> iterators = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private Inventory inventory; private Inventory inventory;
private int id; private int id;
@ -44,21 +48,33 @@ public class RecipeChoiceTask implements Runnable {
*/ */
public void start(@Nonnull Inventory inv) { public void start(@Nonnull Inventory inv) {
Validate.notNull(inv, "Inventory must not be null"); Validate.notNull(inv, "Inventory must not be null");
inventory = inv; inventory = inv;
id = Bukkit.getScheduler().runTaskTimerAsynchronously(SlimefunPlugin.instance(), this, 0, UPDATE_INTERVAL).getTaskId(); id = Bukkit.getScheduler().runTaskTimerAsynchronously(SlimefunPlugin.instance(), this, 0, UPDATE_INTERVAL).getTaskId();
} }
public void add(int slot, @Nonnull MaterialChoice choice) { public void add(int slot, @Nonnull MaterialChoice choice) {
Validate.notNull(choice, "Cannot add a null RecipeChoice"); Validate.notNull(choice, "Cannot add a null RecipeChoice");
iterators.put(slot, new LoopIterator<>(choice.getChoices())); lock.writeLock().lock();
try {
iterators.put(slot, new LoopIterator<>(choice.getChoices()));
} finally {
lock.writeLock().unlock();
}
} }
public void add(int slot, @Nonnull Tag<Material> tag) { public void add(int slot, @Nonnull Tag<Material> tag) {
Validate.notNull(tag, "Cannot add a null Tag"); Validate.notNull(tag, "Cannot add a null Tag");
iterators.put(slot, new LoopIterator<>(tag.getValues())); lock.writeLock().lock();
try {
iterators.put(slot, new LoopIterator<>(tag.getValues()));
} finally {
lock.writeLock().unlock();
}
} }
/** /**
@ -67,7 +83,13 @@ public class RecipeChoiceTask implements Runnable {
* @return Whether this task has nothing to do * @return Whether this task has nothing to do
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return iterators.isEmpty(); lock.readLock().lock();
try {
return iterators.isEmpty();
} finally {
lock.readLock().unlock();
}
} }
@Override @Override
@ -78,8 +100,14 @@ public class RecipeChoiceTask implements Runnable {
return; return;
} }
for (Map.Entry<Integer, LoopIterator<Material>> entry : iterators.entrySet()) { lock.readLock().lock();
inventory.setItem(entry.getKey(), new ItemStack(entry.getValue().next()));
try {
for (Map.Entry<Integer, LoopIterator<Material>> entry : iterators.entrySet()) {
inventory.setItem(entry.getKey(), new ItemStack(entry.getValue().next()));
}
} finally {
lock.readLock().unlock();
} }
} }