DeployerRecipeSearchEvent

- added an event to add custom deploying recipes for addons(that partly need more data and therefore can't use the existing deploying recipe json format)
- made deploying recipe scanning cancelable by event
- added a safety check to tile entity behaviours to prevent concurrent modification exceptions when loading old worlds (0.2 time, dev 0.3)
This commit is contained in:
grimmauld 2021-08-24 11:17:47 +02:00
parent f1701ae784
commit ce32284d39
4 changed files with 112 additions and 12 deletions

View file

@ -0,0 +1,59 @@
package com.simibubi.create.content.contraptions.components.deployer;
import java.util.Optional;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.foundation.utility.recipe.TileEntityAwareRecipeWrapper;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.eventbus.api.Event;
public class DeployerRecipeSearchEvent extends Event {
private final DeployerTileEntity tileEntity;
private final TileEntityAwareRecipeWrapper inventory;
@Nullable
IRecipe<? extends IInventory> recipe = null;
private int maxPriority = 0;
public DeployerRecipeSearchEvent(DeployerTileEntity tileEntity, TileEntityAwareRecipeWrapper inventory) {
this.tileEntity = tileEntity;
this.inventory = inventory;
}
@Override
public boolean isCancelable() {
return true;
}
public DeployerTileEntity getTileEntity() {
return tileEntity;
}
public TileEntityAwareRecipeWrapper getInventory() {
return inventory;
}
// lazyness to not scan for recipes that aren't selected
public boolean shouldAddRecipeWithPriority(int priority) {
return !isCanceled() && priority > maxPriority;
}
@Nullable
public IRecipe<? extends IInventory> getRecipe() {
if (isCanceled())
return null;
return recipe;
}
public void addRecipe(Supplier<Optional<? extends IRecipe<? extends IInventory>>> recipeSupplier, int priority) {
if (!shouldAddRecipeWithPriority(priority))
return;
recipeSupplier.get().ifPresent(newRecipe -> {
this.recipe = newRecipe;
maxPriority = priority;
});
}
}

View file

@ -4,7 +4,6 @@ import static com.simibubi.create.content.contraptions.base.DirectionalKineticBl
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -26,8 +25,11 @@ import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.recipe.TileEntityAwareRecipeWrapper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
@ -46,6 +48,8 @@ import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.server.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
@ -437,29 +441,37 @@ public class DeployerTileEntity extends KineticTileEntity {
animatedOffset.setValue(offset); animatedOffset.setValue(offset);
} }
RecipeWrapper recipeInv = new RecipeWrapper(new ItemStackHandler(2)); TileEntityAwareRecipeWrapper recipeInv = new TileEntityAwareRecipeWrapper(new ItemStackHandler(2), this);
SandPaperInv sandpaperInv = new SandPaperInv(ItemStack.EMPTY); SandPaperInv sandpaperInv = new SandPaperInv(ItemStack.EMPTY);
@Nullable @Nullable
public IRecipe<?> getRecipe(ItemStack stack) { public IRecipe<? extends IInventory> getRecipe(ItemStack stack) {
if (player == null) // safety checks
if (player == null || level == null)
return null; return null;
// sandpaper = op
ItemStack heldItemMainhand = player.getMainHandItem(); ItemStack heldItemMainhand = player.getMainHandItem();
if (heldItemMainhand.getItem() instanceof SandPaperItem) { if (heldItemMainhand.getItem() instanceof SandPaperItem) {
sandpaperInv.setItem(0, stack); sandpaperInv.setItem(0, stack);
return AllRecipeTypes.SANDPAPER_POLISHING.find(sandpaperInv, level) return AllRecipeTypes.SANDPAPER_POLISHING.find(sandpaperInv, level)
.orElse(null); .orElse(null);
} }
// inventory
recipeInv.setItem(0, stack); recipeInv.setItem(0, stack);
recipeInv.setItem(1, heldItemMainhand); recipeInv.setItem(1, heldItemMainhand);
Optional<DeployerApplicationRecipe> assemblyRecipe = SequencedAssemblyRecipe.getRecipe(level, recipeInv, // event nonsense
AllRecipeTypes.DEPLOYING.getType(), DeployerApplicationRecipe.class); DeployerRecipeSearchEvent event = new DeployerRecipeSearchEvent(this, recipeInv);
if (assemblyRecipe.isPresent())
return assemblyRecipe.get();
return AllRecipeTypes.DEPLOYING.find(recipeInv, level) // creates deployer recipes
.orElse(null); event.addRecipe(() -> SequencedAssemblyRecipe.getRecipe(level, recipeInv,
AllRecipeTypes.DEPLOYING.getType(), DeployerApplicationRecipe.class), 100);
event.addRecipe(() -> AllRecipeTypes.DEPLOYING.find(recipeInv, level), 50);
// post the event, get result
MinecraftForge.EVENT_BUS.post(event);
return event.getRecipe();
} }
} }

View file

@ -10,6 +10,8 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.ConcurrentModificationException;
public abstract class TileEntityBehaviour { public abstract class TileEntityBehaviour {
public SmartTileEntity tileEntity; public SmartTileEntity tileEntity;
@ -85,7 +87,13 @@ public abstract class TileEntityBehaviour {
} }
public static <T extends TileEntityBehaviour> T get(IBlockReader reader, BlockPos pos, BehaviourType<T> type) { public static <T extends TileEntityBehaviour> T get(IBlockReader reader, BlockPos pos, BehaviourType<T> type) {
return get(reader.getBlockEntity(pos), type); TileEntity te;
try {
te = reader.getBlockEntity(pos);
} catch (ConcurrentModificationException e) {
te = null;
}
return get(te, type);
} }
public static <T extends TileEntityBehaviour> void destroy(IBlockReader reader, BlockPos pos, public static <T extends TileEntityBehaviour> void destroy(IBlockReader reader, BlockPos pos,

View file

@ -0,0 +1,21 @@
package com.simibubi.create.foundation.utility.recipe;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.RecipeWrapper;
import java.util.function.Supplier;
public class TileEntityAwareRecipeWrapper extends RecipeWrapper implements Supplier<TileEntity> {
private final TileEntity tileEntity;
public TileEntityAwareRecipeWrapper(IItemHandlerModifiable inv, TileEntity tileEntity) {
super(inv);
this.tileEntity = tileEntity;
}
@Override
public TileEntity get() {
return tileEntity;
}
}