/* * 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.fml; import net.minecraft.util.ResourceLocation; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.ForgeRegistryEntry; import net.minecraftforge.registries.RegistryManager; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; public final class RegistryObject> { private final String name; private final IForgeRegistry owningRegistry; private T value; private boolean searched; public static , U extends T> RegistryObject of(final String name, Supplier> registryType) { return new RegistryObject<>(name, registryType); } private static RegistryObject EMPTY = new RegistryObject<>(); private static > RegistryObject empty() { @SuppressWarnings("unchecked") RegistryObject t = (RegistryObject) EMPTY; return t; } private RegistryObject() { this.searched = true; this.name = ""; this.owningRegistry = null; } private > RegistryObject(String name, Supplier> registryType) { this.name = name; IForgeRegistry registry; try { registry = RegistryManager.ACTIVE.getRegistry(registryType.get()); } catch (Throwable t) { registry = null; } this.owningRegistry = registry; } private T getValue() { if (!searched) { if (this.owningRegistry != null) { //noinspection unchecked this.value = (T)this.owningRegistry.getValue(new ResourceLocation(this.name)); } searched = true; } return this.value; } public String getName() { return this.name; } public Stream stream() { return isPresent() ? Stream.of(getValue()) : Stream.of(); } /** * 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 getValue() != null; } /** * 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(Consumer consumer) { if (getValue() != null) consumer.accept(getValue()); } /** * If a mod object is present, and the mod object matches the given predicate, * return an {@code RegistryObject} describing the value, otherwise return an * empty {@code RegistryObject}. * * @param predicate a predicate to apply to the mod object, if present * @return an {@code RegistryObject} describing the value of this {@code RegistryObject} * if a mod object is present and the mod object matches the given predicate, * otherwise an empty {@code RegistryObject} * @throws NullPointerException if the predicate is null */ public RegistryObject filter(Predicate predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(getValue()) ? this : 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 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 RegistryObject}, if a mod object is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null */ public Optional map(Function mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return Optional.empty(); else { return Optional.ofNullable(mapper.apply(getValue())); } } /** * If a value is present, apply the provided {@code Optional}-bearing * mapping function to it, return that result, otherwise return an empty * {@code Optional}. This method is similar to {@link #map(Function)}, * but the provided mapper is one whose result is already an {@code Optional}, * and if invoked, {@code flatMap} does not wrap it with an additional * {@code Optional}. * * @param The type parameter to the {@code Optional} returned by * @param mapper a mapping function to apply to the mod object, if present * the mapping function * @return the result of applying an {@code Optional}-bearing mapping * function to the value of this {@code Optional}, if a value is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null or returns * a null result */ public Optional flatMap(Function> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return Optional.empty(); else { return Objects.requireNonNull(mapper.apply(getValue())); } } /** * 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) { return getValue() != null ? getValue() : 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(Supplier other) { return getValue() != null ? getValue() : 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 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 T orElseThrow(Supplier exceptionSupplier) throws X { if (getValue() != null) { return getValue(); } else { throw exceptionSupplier.get(); } } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof RegistryObject) { return Objects.equals(((RegistryObject)obj).name, name); } return false; } @Override public int hashCode() { return Objects.hashCode(name); } }