Issue. Gesundheit

- Fixed an incompatibility with Supplementaries leading to a server crash
- Fixed fallback damage bar colour for air powered tools
- Various NPE guards
- Fixed sequenced assembly recipes conflicting when starting with a filling step
- Potato cannons can no longer plant crops on the side of farmland
- Fixed Mechanical rollers consuming filter items despite not supporting them
- Fixed brass tunnels not refunding previous filter items when changed
- Fixed catalyst ingredients getting consumed in the basin
This commit is contained in:
simibubi 2023-07-04 17:43:54 +02:00
parent 246543c76b
commit 6819fc1c42
10 changed files with 56 additions and 45 deletions

View file

@ -59,7 +59,11 @@ public interface MovementBehaviour {
if (remainder.isEmpty()) if (remainder.isEmpty())
return; return;
// Actors might void items if their positions is undefined
Vec3 vec = context.position; Vec3 vec = context.position;
if (vec == null)
return;
ItemEntity itemEntity = new ItemEntity(context.world, vec.x, vec.y, vec.z, remainder); ItemEntity itemEntity = new ItemEntity(context.world, vec.x, vec.y, vec.z, remainder);
itemEntity.setDeltaMovement(context.motion.add(0, 0.5f, 0) itemEntity.setDeltaMovement(context.motion.add(0, 0.5f, 0)
.scale(context.world.random.nextFloat() * .3f)); .scale(context.world.random.nextFloat() * .3f));

View file

@ -1,5 +1,9 @@
package com.simibubi.create.content.equipment.armor; package com.simibubi.create.content.equipment.armor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import com.simibubi.create.AllEnchantments; import com.simibubi.create.AllEnchantments;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.AllTags; import com.simibubi.create.AllTags;
@ -15,6 +19,7 @@ import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -22,10 +27,6 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class BacktankUtil { public class BacktankUtil {
private static final List<Function<LivingEntity, List<ItemStack>>> BACKTANK_SUPPLIERS = new ArrayList<>(); private static final List<Function<LivingEntity, List<ItemStack>>> BACKTANK_SUPPLIERS = new ArrayList<>();
@ -174,6 +175,11 @@ public class BacktankUtil {
if (player == null) if (player == null)
return 0; return 0;
List<ItemStack> backtanks = getAllWithAir(player); List<ItemStack> backtanks = getAllWithAir(player);
// Fallback colour
if (backtanks.isEmpty())
return Mth.hsvToRgb(Math.max(0.0F, 1.0F - (float) stack.getDamageValue() / stack.getMaxDamage()) / 3.0F,
1.0F, 1.0F);
// Just return the "first" backtank for the bar color since that's the one we are consuming from // Just return the "first" backtank for the bar color since that's the one we are consuming from
return backtanks.get(0) return backtanks.get(0)

View file

@ -312,6 +312,8 @@ public class BuiltinPotatoProjectileTypes {
if (world instanceof Level l && !l.isLoaded(hitPos)) if (world instanceof Level l && !l.isLoaded(hitPos))
return true; return true;
Direction face = ray.getDirection(); Direction face = ray.getDirection();
if (face != Direction.UP)
return false;
BlockPos placePos = hitPos.relative(face); BlockPos placePos = hitPos.relative(face);
if (!world.getBlockState(placePos) if (!world.getBlockState(placePos)
.getMaterial() .getMaterial()

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.fluids.spout;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate;
import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.fluids.transfer.FillingRecipe; import com.simibubi.create.content.fluids.transfer.FillingRecipe;
@ -37,8 +38,8 @@ public class FillingBySpout {
public static int getRequiredAmountForItem(Level world, ItemStack stack, FluidStack availableFluid) { public static int getRequiredAmountForItem(Level world, ItemStack stack, FluidStack availableFluid) {
WRAPPER.setItem(0, stack); WRAPPER.setItem(0, stack);
Optional<FillingRecipe> assemblyRecipe = Optional<FillingRecipe> assemblyRecipe = SequencedAssemblyRecipe.getRecipe(world, WRAPPER,
SequencedAssemblyRecipe.getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class); AllRecipeTypes.FILLING.getType(), FillingRecipe.class, matchItemAndFluid(world, availableFluid));
if (assemblyRecipe.isPresent()) { if (assemblyRecipe.isPresent()) {
FluidIngredient requiredFluid = assemblyRecipe.get() FluidIngredient requiredFluid = assemblyRecipe.get()
.getRequiredFluid(); .getRequiredFluid();
@ -62,9 +63,10 @@ public class FillingBySpout {
WRAPPER.setItem(0, stack); WRAPPER.setItem(0, stack);
FillingRecipe fillingRecipe = FillingRecipe fillingRecipe = SequencedAssemblyRecipe
SequencedAssemblyRecipe.getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class) .getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class,
.filter(fr -> fr.getRequiredFluid() matchItemAndFluid(world, availableFluid))
.filter(fr -> fr.getRequiredFluid()
.test(toFill)) .test(toFill))
.orElseGet(() -> { .orElseGet(() -> {
for (Recipe<RecipeWrapper> recipe : world.getRecipeManager() for (Recipe<RecipeWrapper> recipe : world.getRecipeManager()
@ -87,4 +89,9 @@ public class FillingBySpout {
return GenericItemFilling.fillItem(world, requiredAmount, stack, availableFluid); return GenericItemFilling.fillItem(world, requiredAmount, stack, availableFluid);
} }
private static Predicate<FillingRecipe> matchItemAndFluid(Level world, FluidStack availableFluid) {
return r -> r.matches(WRAPPER, world) && r.getRequiredFluid()
.test(availableFluid);
}
} }

View file

@ -203,6 +203,9 @@ public abstract class FluidManipulationBehaviour extends BlockEntityBehaviour {
} }
protected void playEffect(Level world, BlockPos pos, Fluid fluid, boolean fillSound) { protected void playEffect(Level world, BlockPos pos, Fluid fluid, boolean fillSound) {
if (fluid == null)
return;
BlockPos splooshPos = pos == null ? blockEntity.getBlockPos() : pos; BlockPos splooshPos = pos == null ? blockEntity.getBlockPos() : pos;
SoundEvent soundevent = fillSound ? fluid.getAttributes() SoundEvent soundevent = fillSound ? fluid.getAttributes()

View file

@ -570,10 +570,6 @@ public class BeltBlock extends HorizontalKineticBlock
return pos; return pos;
} }
public static boolean canAccessFromSide(Direction facing, BlockState belt) {
return true;
}
@Override @Override
public Class<BeltBlockEntity> getBlockEntityClass() { public Class<BeltBlockEntity> getBlockEntityClass() {
return BeltBlockEntity.class; return BeltBlockEntity.class;

View file

@ -58,7 +58,6 @@ import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
public class BeltBlockEntity extends KineticBlockEntity { public class BeltBlockEntity extends KineticBlockEntity {
@ -184,14 +183,11 @@ public class BeltBlockEntity extends KineticBlockEntity {
@Override @Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) { public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (!isItemHandlerCap(cap))
return super.getCapability(cap, side);
if (!isRemoved() && !itemHandler.isPresent()) if (!isRemoved() && !itemHandler.isPresent())
initializeItemHandler(); initializeItemHandler();
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { return itemHandler.cast();
if (side == Direction.UP || BeltBlock.canAccessFromSide(side, getBlockState())) {
return itemHandler.cast();
}
}
return super.getCapability(cap, side);
} }
@Override @Override

View file

@ -547,9 +547,6 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
if (simulate) if (simulate)
return true; return true;
for (ItemStack itemStack : outputItems) { for (ItemStack itemStack : outputItems) {
if (itemStack.hasContainerItem() && itemStack.getContainerItem()
.sameItem(itemStack))
continue;
spoutputBuffer.add(itemStack.copy()); spoutputBuffer.add(itemStack.copy());
} }
if (!externalTankNotPresent) if (!externalTankNotPresent)
@ -591,10 +588,6 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
private boolean acceptItemOutputsIntoBasin(List<ItemStack> outputItems, boolean simulate, IItemHandler targetInv) { private boolean acceptItemOutputsIntoBasin(List<ItemStack> outputItems, boolean simulate, IItemHandler targetInv) {
for (ItemStack itemStack : outputItems) { for (ItemStack itemStack : outputItems) {
// Catalyst items are never consumed
if (itemStack.hasContainerItem() && itemStack.getContainerItem()
.sameItem(itemStack))
continue;
if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate) if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate)
.isEmpty()) .isEmpty())
return false; return false;

View file

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllRecipeTypes;
@ -57,9 +58,13 @@ public class SequencedAssemblyRecipe implements Recipe<RecipeWrapper> {
public static <C extends Container, R extends ProcessingRecipe<C>> Optional<R> getRecipe(Level world, C inv, public static <C extends Container, R extends ProcessingRecipe<C>> Optional<R> getRecipe(Level world, C inv,
RecipeType<R> type, Class<R> recipeClass) { RecipeType<R> type, Class<R> recipeClass) {
//return getRecipe(world, inv.getStackInSlot(0), type, recipeClass).filter(r -> r.matches(inv, world)); return getRecipe(world, inv, type, recipeClass, r -> r.matches(inv, world));
return getRecipes(world, inv.getItem(0), type, recipeClass).filter(r -> r.matches(inv, world)) }
.findFirst();
public static <C extends Container, R extends ProcessingRecipe<C>> Optional<R> getRecipe(Level world, C inv,
RecipeType<R> type, Class<R> recipeClass, Predicate<? super R> recipeFilter) {
return getRecipes(world, inv.getItem(0), type, recipeClass).filter(recipeFilter)
.findFirst();
} }
public static <R extends ProcessingRecipe<?>> Optional<R> getRecipe(Level world, ItemStack item, public static <R extends ProcessingRecipe<?>> Optional<R> getRecipe(Level world, ItemStack item,

View file

@ -271,8 +271,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
public void onShortInteract(Player player, InteractionHand hand, Direction side) { public void onShortInteract(Player player, InteractionHand hand, Direction side) {
Level level = getWorld(); Level level = getWorld();
BlockPos pos = getPos(); BlockPos pos = getPos();
ItemStack toApply = player.getItemInHand(hand) ItemStack itemInHand = player.getItemInHand(hand);
.copy(); ItemStack toApply = itemInHand.copy();
if (AllItems.WRENCH.isIn(toApply)) if (AllItems.WRENCH.isIn(toApply))
return; return;
@ -281,23 +281,13 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
if (level.isClientSide()) if (level.isClientSide())
return; return;
if (!player.isCreative()) { if (getFilter(side).getItem() instanceof FilterItem) {
if (toApply.getItem() instanceof FilterItem) {
if (toApply.getCount() == 1)
player.setItemInHand(hand, ItemStack.EMPTY);
else
player.getItemInHand(hand)
.shrink(1);
}
}
if (getFilter().getItem() instanceof FilterItem) {
if (!player.isCreative() || ItemHelper if (!player.isCreative() || ItemHelper
.extract(new InvWrapper(player.getInventory()), .extract(new InvWrapper(player.getInventory()),
stack -> ItemHandlerHelper.canItemStacksStack(stack, getFilter()), true) stack -> ItemHandlerHelper.canItemStacksStack(stack, getFilter(side)), true)
.isEmpty()) .isEmpty())
player.getInventory() player.getInventory()
.placeItemBackInInventory(getFilter()); .placeItemBackInInventory(getFilter(side));
} }
if (toApply.getItem() instanceof FilterItem) if (toApply.getItem() instanceof FilterItem)
@ -308,6 +298,15 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1); AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1);
return; return;
} }
if (!player.isCreative()) {
if (toApply.getItem() instanceof FilterItem) {
if (itemInHand.getCount() == 1)
player.setItemInHand(hand, ItemStack.EMPTY);
else
itemInHand.shrink(1);
}
}
level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f); level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f);
} }