Refactor OptionalCapabilityInstance to LazyOptional; clean up

- Move to util package, rename to LazyOptional
- Clean up existing javadocs, add javadocs to everything missing them
- Add more NonNull functional interfaces, and use them everywhere
- Move orEmpty() to Capability, works better here anyways
This commit is contained in:
tterrag 2019-01-27 01:38:53 -05:00
parent 0a11ffb827
commit 8e43dfa7a6
20 changed files with 444 additions and 294 deletions

View file

@ -31,11 +31,11 @@ import net.minecraft.world.IWorldReader;
import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.animation.Event; import net.minecraftforge.common.animation.Event;
import net.minecraftforge.common.animation.IEventHandler; import net.minecraftforge.common.animation.IEventHandler;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance;
import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.common.model.animation.CapabilityAnimation;
import net.minecraftforge.common.model.animation.IAnimationStateMachine; import net.minecraftforge.common.model.animation.IAnimationStateMachine;
import net.minecraftforge.common.property.IExtendedBlockState; import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties; import net.minecraftforge.common.property.Properties;
import net.minecraftforge.common.util.LazyOptional;
import java.util.Random; import java.util.Random;
@ -49,7 +49,7 @@ public class TileEntityRendererAnimation<T extends TileEntity> extends TileEntit
@Override @Override
public void renderTileEntityFast(T te, double x, double y, double z, float partialTick, int breakStage, BufferBuilder renderer) public void renderTileEntityFast(T te, double x, double y, double z, float partialTick, int breakStage, BufferBuilder renderer)
{ {
OptionalCapabilityInstance<IAnimationStateMachine> cap = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY); LazyOptional<IAnimationStateMachine> cap = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY);
if(!cap.isPresent()) if(!cap.isPresent())
{ {
return; return;

View file

@ -25,7 +25,9 @@ import com.google.common.base.Throwables;
import net.minecraft.nbt.INBTBase; import net.minecraft.nbt.INBTBase;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
@ -134,6 +136,11 @@ public class Capability<T>
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public @Nonnull <R> LazyOptional<R> orEmpty(Capability<R> toCheck, LazyOptional<T> inst)
{
return this == toCheck ? inst.cast() : LazyOptional.empty();
}
// INTERNAL // INTERNAL
private final String name; private final String name;

View file

@ -33,6 +33,7 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.common.util.LazyOptional;
/** /**
* A high-speed implementation of a capability delegator. * A high-speed implementation of a capability delegator.
@ -92,16 +93,16 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
@Override @Override
public <T> OptionalCapabilityInstance<T> getCapability(Capability<T> cap, @Nullable EnumFacing side) public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable EnumFacing side)
{ {
for (ICapabilityProvider c : caps) for (ICapabilityProvider c : caps)
{ {
OptionalCapabilityInstance<T> ret = c.getCapability(cap, side); LazyOptional<T> ret = c.getCapability(cap, side);
if (ret.isPresent()) { if (ret.isPresent()) {
return ret; return ret;
} }
} }
return OptionalCapabilityInstance.empty(); return LazyOptional.empty();
} }
@Override @Override

View file

@ -26,6 +26,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.ForgeEventFactory;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ -98,9 +99,9 @@ public abstract class CapabilityProvider<B extends CapabilityProvider<B>> implem
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> cap, @Nullable EnumFacing side) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable EnumFacing side)
{ {
final CapabilityDispatcher disp = getCapabilities(); final CapabilityDispatcher disp = getCapabilities();
return disp == null ? OptionalCapabilityInstance.empty() : disp.getCapability(cap, side); return disp == null ? LazyOptional.empty() : disp.getCapability(cap, side);
} }
} }

View file

@ -23,6 +23,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.util.LazyOptional;
public interface ICapabilityProvider public interface ICapabilityProvider
{ {
@ -37,13 +38,13 @@ public interface ICapabilityProvider
* <strong>CAN BE NULL</strong>. Null is defined to represent 'internal' or 'self' * <strong>CAN BE NULL</strong>. Null is defined to represent 'internal' or 'self'
* @return The requested an optional holding the requested capability. * @return The requested an optional holding the requested capability.
*/ */
@Nonnull <T> OptionalCapabilityInstance<T> getCapability(@Nonnull final Capability<T> cap, final @Nullable EnumFacing side); @Nonnull <T> LazyOptional<T> getCapability(@Nonnull final Capability<T> cap, final @Nullable EnumFacing side);
/* /*
* Purely added as a bouncer to sided version, to make modders stop complaining about calling with a null value. * Purely added as a bouncer to sided version, to make modders stop complaining about calling with a null value.
* This should never be OVERRIDDEN, modders should only ever implement the sided version. * This should never be OVERRIDDEN, modders should only ever implement the sided version.
*/ */
@Nonnull default <T> OptionalCapabilityInstance<T> getCapability(@Nonnull final Capability<T> cap) { @Nonnull default <T> LazyOptional<T> getCapability(@Nonnull final Capability<T> cap) {
return getCapability(cap, null); return getCapability(cap, null);
} }
} }

View file

@ -1,241 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.capabilities;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class OptionalCapabilityInstance<T>
{
private final NonNullSupplier<T> supplier;
private AtomicReference<T> resolved;
private Set<Consumer<OptionalCapabilityInstance<T>>> listeners = new HashSet<>();
private boolean isValid = true;
private static final @Nonnull OptionalCapabilityInstance<Void> EMPTY = new OptionalCapabilityInstance<>(null);
@SuppressWarnings("unchecked")
public static <T> OptionalCapabilityInstance<T> empty()
{
return (OptionalCapabilityInstance<T>)EMPTY;
}
@SuppressWarnings("unchecked")
public <X> OptionalCapabilityInstance<X> cast()
{
return (OptionalCapabilityInstance<X>)this;
}
private OptionalCapabilityInstance(@Nullable NonNullSupplier<T> instanceSupplier)
{
this.supplier = instanceSupplier;
}
public static <T> OptionalCapabilityInstance<T> of(final @Nullable NonNullSupplier<T> instanceSupplier)
{
return instanceSupplier == null ? EMPTY.cast() : new OptionalCapabilityInstance<>(instanceSupplier);
}
public static <T, R> OptionalCapabilityInstance<R> orEmpty(Capability<R> cap, Capability<T> toCheck, OptionalCapabilityInstance<T> inst)
{
return cap == toCheck ? inst.cast() : EMPTY.cast();
}
private @Nullable T getValue()
{
if (!isValid)
return null;
if (resolved != null)
return resolved.get();
if (supplier != null)
{
resolved = new AtomicReference<>(null);
try
{
T temp = supplier.get();
if (temp == null)
throw new IllegalStateException("Supplier must not return null value");
resolved.set(temp);
return resolved.get();
}
catch (Throwable e)
{
return null;
}
}
return null;
}
/**
* Return {@code true} if there is a mod object present, otherwise {@code false}.
*
* @return {@code true} if there is a mod object present, otherwise {@code false}
*/
public boolean isPresent()
{
return supplier != null && isValid;
}
/**
* If a mod object is present, invoke the specified consumer with the object,
* otherwise do nothing.
*
* @param consumer block to be executed if a mod object is present
* @throws NullPointerException if mod object is present and {@code consumer} is
* null
*/
public void ifPresent(NonNullConsumer<? super T> consumer)
{
T val = getValue();
if (isValid && val != null)
consumer.accept(val);
}
/**
* If a mod object is present, and the mod object matches the given predicate,
* return an {@code OptionalMod} describing the value, otherwise return an
* empty {@code OptionalMod}.
*
* @param predicate a predicate to apply to the mod object, if present
* @return an {@code OptionalMod} describing the value of this {@code OptionalMod}
* if a mod object is present and the mod object matches the given predicate,
* otherwise an empty {@code OptionalMod}
* @throws NullPointerException if the predicate is null
*/
public OptionalCapabilityInstance<T> filter(Predicate<? super T> predicate)
{
Objects.requireNonNull(predicate);
final T value = getValue(); // To keep the non-null contract we have to evaluate right now. Should we allow this function at all?
return predicate.test(value) ? OptionalCapabilityInstance.of(()->value) : empty();
}
/**
* If a mod object is present, apply the provided mapping function to it,
* and if the result is non-null, return an {@code Optional} describing the
* result. Otherwise return an empty {@code Optional}.
*
* @apiNote This method supports post-processing on optional values, without
* the need to explicitly check for a return status.
*
* @param <U> The type of the result of the mapping function
* @param mapper a mapping function to apply to the mod object, if present
* @return an {@code Optional} describing the result of applying a mapping
* function to the mod object of this {@code OptionalMod}, if a mod object is present,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the mapping function is null
*/
public<U> OptionalCapabilityInstance<U> map(Function<? super T, ? extends U> mapper)
{
Objects.requireNonNull(mapper);
return isPresent() ? OptionalCapabilityInstance.of(()->mapper.apply(getValue())) : empty();
}
/**
* Return the mod object if present, otherwise return {@code other}.
*
* @param other the mod object to be returned if there is no mod object present, may
* be null
* @return the mod object, if present, otherwise {@code other}
*/
public T orElse(T other)
{
T val = getValue();
return val != null ? val : other;
}
/**
* Return the mod object if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no mod object
* is present
* @return the mod object if present otherwise the result of {@code other.get()}
* @throws NullPointerException if mod object is not present and {@code other} is
* null
*/
public T orElseGet(NonNullSupplier<? extends T> other)
{
T val = getValue();
return val != null ? val : other.get();
}
/**
* Return the contained mod object, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier The supplier which will return the exception to
* be thrown
* @return the present mod object
* @throws X if there is no mod object present
* @throws NullPointerException if no mod object is present and
* {@code exceptionSupplier} is null
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
{
T val = getValue();
if (val != null)
return val;
throw exceptionSupplier.get();
}
/**
* Registers a listener that will be called when this Optional becomes invalid.
*/
public void addListener(Consumer<OptionalCapabilityInstance<T>> listener)
{
if (!isPresent())
listener.accept(this); // They are stupid so just directly call them.
else
this.listeners.add(listener);
}
/*
* Should only be called by the 'Owner' of this capability, this is to notify any listerners that this has become invalid and they should update.
* For example, a TE would call this, if they are covered with a microblock panel, thus cutting off pipe connectivity to this side.
* Also should be called for all caps when a TE is invalidated, or a world/chunk unloads, or a entity dies, etc...
* This allows modders to keep a cache of Capabilities instead of re-checking them every tick.
*/
public void invalidate()
{
this.isValid = false;
this.listeners.forEach(e -> e.accept(this));
}
}

View file

@ -25,7 +25,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -53,18 +53,18 @@ public class CapabilityAnimation
public static class DefaultItemAnimationCapabilityProvider implements ICapabilityProvider public static class DefaultItemAnimationCapabilityProvider implements ICapabilityProvider
{ {
@Nonnull @Nonnull
private final OptionalCapabilityInstance<IAnimationStateMachine> asm; private final LazyOptional<IAnimationStateMachine> asm;
public DefaultItemAnimationCapabilityProvider(@Nonnull OptionalCapabilityInstance<IAnimationStateMachine> asm) public DefaultItemAnimationCapabilityProvider(@Nonnull LazyOptional<IAnimationStateMachine> asm)
{ {
this.asm = asm; this.asm = asm;
} }
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
return OptionalCapabilityInstance.orEmpty(capability, ANIMATION_CAPABILITY, asm); return ANIMATION_CAPABILITY.orEmpty(capability, asm);
} }
} }
} }

View file

@ -0,0 +1,298 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.util;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraftforge.common.capabilities.Capability;
/**
* This object encapsulates a lazy value, with typical transformation operations
* (map/ifPresent) available, much like {@link Optional}.
* <p>
* It also provides the ability to listen for invalidation, via
* {@link #addListener(Consumer)}. This method is invoked when the provider of
* this object calls {@link #invalidate()}.
* <p>
* To create an instance of this class, use {@link #of(NonNullSupplier)}. Note
* that this accepts a {@link NonNullSupplier}, so the result of the supplier
* must never be null.
* <p>
* The empty instance can be retrieved with {@link #empty()}.
*
* @param <T> The type of the optional value.
*/
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class LazyOptional<T>
{
private final NonNullSupplier<T> supplier;
private AtomicReference<T> resolved;
private Set<NonNullConsumer<LazyOptional<T>>> listeners = new HashSet<>();
private boolean isValid = true;
private static final @Nonnull LazyOptional<Void> EMPTY = new LazyOptional<>(null);
/**
* Construct a new {@link LazyOptional} that wraps the given
* {@link NonNullSupplier}.
*
* @param instanceSupplier The {@link NonNullSupplier} to wrap. Cannot return
* null, but can be null itself. If null, this method
* returns {@link #empty()}.
*/
public static <T> LazyOptional<T> of(final @Nullable NonNullSupplier<T> instanceSupplier)
{
return instanceSupplier == null ? empty() : new LazyOptional<>(instanceSupplier);
}
/**
* @return The singleton empty instance
*/
public static <T> LazyOptional<T> empty()
{
return EMPTY.cast();
}
/**
* This method hides an unchecked cast to the inferred type. Only use this if
* you are sure the type should match. For capabilities, generally
* {@link Capability#orEmpty(Capability, LazyOptional)} should be used.
*
* @return This {@link LazyOptional}, cast to the inferred generic type
*/
@SuppressWarnings("unchecked")
public <X> LazyOptional<X> cast()
{
return (LazyOptional<X>)this;
}
private LazyOptional(@Nullable NonNullSupplier<T> instanceSupplier)
{
this.supplier = instanceSupplier;
}
private @Nullable T getValue()
{
if (!isValid)
return null;
if (resolved != null)
return resolved.get();
if (supplier != null)
{
resolved = new AtomicReference<>(null);
try
{
T temp = supplier.get();
if (temp == null)
throw new IllegalStateException("Supplier must not return null value");
resolved.set(temp);
return resolved.get();
}
catch (Throwable e)
{
return null;
}
}
return null;
}
private T getValueUnsafe()
{
T ret = getValue();
if (ret == null)
{
throw new IllegalStateException("LazyOptional is empty or otherwise returned null from getValue() unexpectedly");
}
return ret;
}
/**
* Check if this {@link LazyOptional} is non-empty.
*
* @return {@code true} if this {@link LazyOptional} is non-empty, i.e. holds a
* non-null supplier
*/
public boolean isPresent()
{
return supplier != null && isValid;
}
/**
* If non-empty, invoke the specified {@link NonNullConsumer} with the object,
* otherwise do nothing.
*
* @param The {@link NonNullConsumer} to run if this optional is non-empty.
* @throws NullPointerException if {@code consumer} is null and this {@link LazyOptional} is non-empty
*/
public void ifPresent(NonNullConsumer<? super T> consumer)
{
Objects.requireNonNull(consumer);
T val = getValue();
if (isValid && val != null)
consumer.accept(val);
}
/**
* If a this {@link LazyOptional} is non-empty, return a new
* {@link LazyOptional} encapsulating the mapping function. Otherwise, returns
* {@link #empty()}.
* <p>
* The supplier inside this object is <strong>NOT</strong> resolved.
*
* @apiNote This method supports post-processing on optional values, without the
* need to explicitly check for a return status.
*
* @param <U> The type of the result of the mapping function
* @param mapper A mapping function to apply to the mod object, if present
* @return A {@link LazyOptional} describing the result of applying a mapping
* function to the value of this {@link LazyOptional}, if a value is
* present, otherwise an empty {@link LazyOptional}
* @throws NullPointerException if {@code mapper} is null and this {@link LazyOptional} is non-empty
*/
public <U> LazyOptional<U> map(NonNullFunction<? super T, ? extends U> mapper)
{
Objects.requireNonNull(mapper);
return isPresent() ? of(() -> mapper.apply(getValueUnsafe())) : empty();
}
/**
* Resolve the contained supplier if non-empty, and filter it by the given
* {@link NonNullPredicate}, returning empty if false.
* <p>
* <em>It is important to note that this method is <strong>not</strong> lazy, as
* it must resolve the value of the supplier to validate it with the
* predicate.</em>
*
* @param predicate A {@link NonNullPredicate} to apply to the result of the
* contained supplier, if non-empty
* @return A {@link LazyOptional} containing the result of the contained
* supplier, if and only if the passed {@link NonNullPredicate} returns
* true, otherwise an empty {@link LazyOptional}
* @throws NullPointerException If {@code predicate} is null and this
* {@link LazyOptional} is non-empty
*/
public LazyOptional<T> filter(NonNullPredicate<? super T> predicate)
{
Objects.requireNonNull(predicate);
final T value = getValue(); // To keep the non-null contract we have to evaluate right now. Should we allow this function at all?
return value != null && predicate.test(value) ? of(() -> value) : empty();
}
/**
* Resolve the contained supplier if non-empty and return the result, otherwise return
* {@code other}.
*
* @param other the value to be returned if this {@link LazyOptional} is empty
* @return the result of the supplier, if non-empty, otherwise {@code other}
*/
public T orElse(T other)
{
T val = getValue();
return val != null ? val : other;
}
/**
* Resolve the contained supplier if non-empty and return the result, otherwise return the
* result of {@code other}.
*
* @param other A {@link NonNullSupplier} whose result is returned if this
* {@link LazyOptional} is empty
* @return The result of the supplier, if non-empty, otherwise the result of
* {@code other.get()}
* @throws NullPointerException If {@code other} is null and this
* {@link LazyOptional} is non-empty
*/
public T orElseGet(NonNullSupplier<? extends T> other)
{
T val = getValue();
return val != null ? val : other.get();
}
/**
* Resolve the contained supplier if non-empty and return the result, otherwise throw the
* exception created by the provided {@link NonNullSupplier}.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier The {@link NonNullSupplier} which will return the
* exception to be thrown
* @return The result of the supplier
* @throws X If this {@link LazyOptional} is empty
* @throws NullPointerException If {@code exceptionSupplier} is null and this
* {@link LazyOptional} is empty
*/
public <X extends Throwable> T orElseThrow(NonNullSupplier<? extends X> exceptionSupplier) throws X
{
T val = getValue();
if (val != null)
return val;
throw exceptionSupplier.get();
}
/**
* Register a {@link NonNullConsumer listener} that will be called when this {@link LazyOptional} becomes invalid (via {@link #invalidate()}).
* <p>
* If this {@link LazyOptional} is empty, the listener will be called immediately.
*/
public void addListener(NonNullConsumer<LazyOptional<T>> listener)
{
if (isPresent())
{
this.listeners.add(listener);
}
else
{
listener.accept(this);
}
}
/**
* Invalidate this {@link LazyOptional}, making it unavailable for further use,
* and notifying any {@link #addListener(NonNullConsumer) listeners} that this
* has become invalid and they should update.
* <p>
* This would typically be used with capability objects. For example, a TE would
* call this, if they are covered with a microblock panel, thus cutting off pipe
* connectivity to this side.
* <p>
* Also should be called for all when a TE is invalidated, or a world/chunk
* unloads, or a entity dies, etc... This allows modders to keep a cache of
* capability objects instead of re-checking them every tick.
*/
public void invalidate()
{
this.isValid = false;
this.listeners.forEach(e -> e.accept(this));
}
}

View file

@ -17,11 +17,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
package net.minecraftforge.common.capabilities; package net.minecraftforge.common.util;
import java.util.function.Consumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
//Exactly like Consumer, except there IS a contract that the parameter must not be null. /**
* Equivalent to {@link Consumer}, except with nonnull contract.
*
* @see Consumer
*/
@FunctionalInterface @FunctionalInterface
public interface NonNullConsumer<T> public interface NonNullConsumer<T>
{ {

View file

@ -0,0 +1,36 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.util;
import java.util.function.Function;
import javax.annotation.Nonnull;
/**
* Equivalent to {@link Function}, except with nonnull contract.
*
* @see Function
*/
@FunctionalInterface
public interface NonNullFunction<T, R>
{
@Nonnull
R apply(@Nonnull T t);
}

View file

@ -0,0 +1,35 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.util;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
/**
* Equivalent to {@link Predicate}, except with nonnull contract.
*
* @see Predicate
*/
@FunctionalInterface
public interface NonNullPredicate<T>
{
boolean test(@Nonnull T t);
}

View file

@ -17,11 +17,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
package net.minecraftforge.common.capabilities; package net.minecraftforge.common.util;
import java.util.function.Supplier;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
//Exactly like Supplier, except there IS a contract that each invocation should return a new unique instance and it must not be null. /**
* Equivalent to {@link Supplier}, except with nonnull contract.
*
* @see Supplier
*/
@FunctionalInterface @FunctionalInterface
public interface NonNullSupplier<T> public interface NonNullSupplier<T>
{ {

View file

@ -41,7 +41,7 @@ import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem; import net.minecraftforge.fluids.capability.IFluidHandlerItem;
@ -434,7 +434,7 @@ public class FluidUtil
* *
* Vanilla buckets will be converted to universal buckets if they are enabled. * Vanilla buckets will be converted to universal buckets if they are enabled.
*/ */
public static OptionalCapabilityInstance<IFluidHandlerItem> getFluidHandler(@Nonnull ItemStack itemStack) public static LazyOptional<IFluidHandlerItem> getFluidHandler(@Nonnull ItemStack itemStack)
{ {
return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY);
} }
@ -442,7 +442,7 @@ public class FluidUtil
/** /**
* Helper method to get the fluid contained in an itemStack * Helper method to get the fluid contained in an itemStack
*/ */
public static OptionalCapabilityInstance<FluidStack> getFluidContained(@Nonnull ItemStack container) public static LazyOptional<FluidStack> getFluidContained(@Nonnull ItemStack container)
{ {
if (!container.isEmpty()) if (!container.isEmpty())
{ {
@ -450,13 +450,13 @@ public class FluidUtil
return getFluidHandler(container) return getFluidHandler(container)
.map(handler -> handler.drain(Integer.MAX_VALUE, false)); .map(handler -> handler.drain(Integer.MAX_VALUE, false));
} }
return OptionalCapabilityInstance.empty(); return LazyOptional.empty();
} }
/** /**
* Helper method to get an IFluidHandler for at a block position. * Helper method to get an IFluidHandler for at a block position.
*/ */
public static OptionalCapabilityInstance<IFluidHandler> getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side) public static LazyOptional<IFluidHandler> getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side)
{ {
IBlockState state = world.getBlockState(blockPos); IBlockState state = world.getBlockState(blockPos);
Block block = state.getBlock(); Block block = state.getBlock();
@ -478,7 +478,7 @@ public class FluidUtil
return OptionalCapabilityInstance.of(() -> new BlockLiquidWrapper((BlockLiquid) block, world, blockPos)); return OptionalCapabilityInstance.of(() -> new BlockLiquidWrapper((BlockLiquid) block, world, blockPos));
} }
*/ */
return OptionalCapabilityInstance.empty(); return LazyOptional.empty();
} }
/** /**

View file

@ -24,7 +24,7 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.FluidTank;
@ -35,7 +35,7 @@ public class TileFluidHandler extends TileEntity
{ {
protected FluidTank tank = new FluidTank(Fluid.BUCKET_VOLUME); protected FluidTank tank = new FluidTank(Fluid.BUCKET_VOLUME);
private final OptionalCapabilityInstance<IFluidHandler> holder = OptionalCapabilityInstance.of(() -> tank); private final LazyOptional<IFluidHandler> holder = LazyOptional.of(() -> tank);
public TileFluidHandler(@Nonnull TileEntityType<?> tileEntityTypeIn) public TileFluidHandler(@Nonnull TileEntityType<?> tileEntityTypeIn)
{ {
@ -59,7 +59,7 @@ public class TileFluidHandler extends TileEntity
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
return holder.cast(); return holder.cast();

View file

@ -27,7 +27,7 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.*; import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.FluidTankProperties; import net.minecraftforge.fluids.capability.FluidTankProperties;
@ -47,7 +47,7 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
{ {
public static final String FLUID_NBT_KEY = "Fluid"; public static final String FLUID_NBT_KEY = "Fluid";
private final OptionalCapabilityInstance<IFluidHandlerItem> holder = OptionalCapabilityInstance.of(() -> this); private final LazyOptional<IFluidHandlerItem> holder = LazyOptional.of(() -> this);
@Nonnull @Nonnull
protected ItemStack container; protected ItemStack container;
@ -205,9 +205,9 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
return OptionalCapabilityInstance.orEmpty(capability, CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, holder); return CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY.orEmpty(capability, holder);
} }
/** /**

View file

@ -27,7 +27,7 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties; import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandlerItem; import net.minecraftforge.fluids.capability.IFluidHandlerItem;
@ -44,7 +44,7 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
{ {
public static final String FLUID_NBT_KEY = "Fluid"; public static final String FLUID_NBT_KEY = "Fluid";
private final OptionalCapabilityInstance<IFluidHandlerItem> holder = OptionalCapabilityInstance.of(() -> this); private final LazyOptional<IFluidHandlerItem> holder = LazyOptional.of(() -> this);
@Nonnull @Nonnull
protected ItemStack container; protected ItemStack container;
@ -182,9 +182,9 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
return OptionalCapabilityInstance.orEmpty(capability, CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, holder); return CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY.orEmpty(capability, holder);
} }
/** /**

View file

@ -30,7 +30,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
@ -46,7 +46,7 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
*/ */
public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvider public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvider
{ {
private final OptionalCapabilityInstance<IFluidHandlerItem> holder = OptionalCapabilityInstance.of(() -> this); private final LazyOptional<IFluidHandlerItem> holder = LazyOptional.of(() -> this);
@Nonnull @Nonnull
protected ItemStack container; protected ItemStack container;
@ -175,8 +175,8 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
@Override @Override
@Nonnull @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
return OptionalCapabilityInstance.orEmpty(capability, CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, holder); return CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY.orEmpty(capability, holder);
} }
} }

View file

@ -31,7 +31,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@ -212,7 +212,7 @@ public class VanillaInventoryCodeHooks
return stack; return stack;
} }
private static OptionalCapabilityInstance<Pair<IItemHandler, Object>> getItemHandler(IHopper hopper, EnumFacing hopperFacing) private static LazyOptional<Pair<IItemHandler, Object>> getItemHandler(IHopper hopper, EnumFacing hopperFacing)
{ {
double x = hopper.getXPos() + (double) hopperFacing.getXOffset(); double x = hopper.getXPos() + (double) hopperFacing.getXOffset();
double y = hopper.getYPos() + (double) hopperFacing.getYOffset(); double y = hopper.getYPos() + (double) hopperFacing.getYOffset();
@ -246,7 +246,7 @@ public class VanillaInventoryCodeHooks
return true; return true;
} }
public static OptionalCapabilityInstance<Pair<IItemHandler, Object>> getItemHandler(World worldIn, double x, double y, double z, final EnumFacing side) public static LazyOptional<Pair<IItemHandler, Object>> getItemHandler(World worldIn, double x, double y, double z, final EnumFacing side)
{ {
int i = MathHelper.floor(x); int i = MathHelper.floor(x);
int j = MathHelper.floor(y); int j = MathHelper.floor(y);
@ -264,6 +264,6 @@ public class VanillaInventoryCodeHooks
} }
} }
return OptionalCapabilityInstance.empty(); return LazyOptional.empty();
} }
} }

View file

@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
@ -194,13 +194,13 @@ public abstract class EntityEquipmentInvWrapper implements IItemHandlerModifiabl
return slots.get(slot); return slots.get(slot);
} }
public static OptionalCapabilityInstance<IItemHandlerModifiable>[] create(EntityLivingBase entity) public static LazyOptional<IItemHandlerModifiable>[] create(EntityLivingBase entity)
{ {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
OptionalCapabilityInstance<IItemHandlerModifiable>[] ret = new OptionalCapabilityInstance[3]; LazyOptional<IItemHandlerModifiable>[] ret = new LazyOptional[3];
ret[0] = OptionalCapabilityInstance.of(() -> new EntityHandsInvWrapper(entity)); ret[0] = LazyOptional.of(() -> new EntityHandsInvWrapper(entity));
ret[1] = OptionalCapabilityInstance.of(() -> new EntityArmorInvWrapper(entity)); ret[1] = LazyOptional.of(() -> new EntityArmorInvWrapper(entity));
ret[2] = OptionalCapabilityInstance.of(() -> new CombinedInvWrapper(ret[0].orElse(null), ret[1].orElse(null))); ret[2] = LazyOptional.of(() -> new CombinedInvWrapper(ret[0].orElse(null), ret[1].orElse(null)));
return ret; return ret;
} }
} }

View file

@ -22,7 +22,7 @@ package net.minecraftforge.items.wrapper;
import net.minecraft.inventory.ISidedInventory; import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
@ -34,11 +34,11 @@ public class SidedInvWrapper implements IItemHandlerModifiable
protected final EnumFacing side; protected final EnumFacing side;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static OptionalCapabilityInstance<IItemHandlerModifiable>[] create(ISidedInventory inv, EnumFacing... sides) { public static LazyOptional<IItemHandlerModifiable>[] create(ISidedInventory inv, EnumFacing... sides) {
OptionalCapabilityInstance<IItemHandlerModifiable>[] ret = new OptionalCapabilityInstance[sides.length]; LazyOptional<IItemHandlerModifiable>[] ret = new LazyOptional[sides.length];
for (int x = 0; x < sides.length; x++) { for (int x = 0; x < sides.length; x++) {
final EnumFacing side = sides[x]; final EnumFacing side = sides[x];
ret[x] = OptionalCapabilityInstance.of(() -> new SidedInvWrapper(inv, side)); ret[x] = LazyOptional.of(() -> new SidedInvWrapper(inv, side));
} }
return ret; return ret;
} }