Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit f9a1d2a

Browse files
Implement DeferredRegister and RegistryObject (#140)
1 parent 82ca90f commit f9a1d2a

File tree

2 files changed

+400
-0
lines changed

2 files changed

+400
-0
lines changed
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.minecraftforge.fml;
21+
22+
import java.util.Objects;
23+
import java.util.Optional;
24+
import java.util.function.Consumer;
25+
import java.util.function.Function;
26+
import java.util.function.Predicate;
27+
import java.util.function.Supplier;
28+
import java.util.stream.Stream;
29+
30+
import javax.annotation.Nullable;
31+
32+
import net.minecraftforge.registries.IForgeRegistry;
33+
import net.minecraftforge.registries.IForgeRegistryEntry;
34+
import net.minecraftforge.registries.RegistryManager;
35+
36+
import net.minecraft.util.Identifier;
37+
38+
import net.patchworkmc.api.registries.ObjectHolderRegistry;
39+
40+
public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> implements Supplier<T> {
41+
private static RegistryObject<?> EMPTY = new RegistryObject<>();
42+
private final Identifier name;
43+
@Nullable
44+
private T value;
45+
46+
private RegistryObject() {
47+
this.name = null;
48+
}
49+
50+
private <V extends IForgeRegistryEntry<V>> RegistryObject(Identifier name, Supplier<Class<? super V>> registryType) {
51+
this(name, RegistryManager.ACTIVE.<V>getRegistry(registryType.get()));
52+
}
53+
54+
@SuppressWarnings("unchecked")
55+
private <V extends IForgeRegistryEntry<V>> RegistryObject(Identifier name, IForgeRegistry<V> registry) {
56+
if (registry == null) {
57+
throw new IllegalArgumentException("Invalid registry argument, must not be null");
58+
}
59+
60+
this.name = name;
61+
ObjectHolderRegistry.INSTANCE.register(registry.getRegistrySuperType(), name.getNamespace(), name.getPath(), value -> {
62+
this.value = (T) value;
63+
});
64+
}
65+
66+
@Deprecated
67+
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final String name, Supplier<Class<? super T>> registryType) {
68+
return of(new Identifier(name), registryType);
69+
}
70+
71+
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final Identifier name, Supplier<Class<? super T>> registryType) {
72+
return new RegistryObject<>(name, registryType);
73+
}
74+
75+
@Deprecated
76+
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final String name, IForgeRegistry<T> registry) {
77+
return of(new Identifier(name), registry);
78+
}
79+
80+
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final Identifier name, IForgeRegistry<T> registry) {
81+
return new RegistryObject<>(name, registry);
82+
}
83+
84+
private static <T extends IForgeRegistryEntry<? super T>> RegistryObject<T> empty() {
85+
@SuppressWarnings("unchecked")
86+
RegistryObject<T> t = (RegistryObject<T>) EMPTY;
87+
return t;
88+
}
89+
90+
/**
91+
* Directly retrieves the wrapped Registry Object. This value will automatically be updated when the backing registry is updated.
92+
*/
93+
@Nullable
94+
@Override
95+
public T get() {
96+
return this.value;
97+
}
98+
99+
public void updateReference(IForgeRegistry<? extends T> registry) {
100+
this.value = registry.getValue(getId());
101+
}
102+
103+
public Identifier getId() {
104+
return this.name;
105+
}
106+
107+
/**
108+
* @deprecated Prefer {@link #getId()}
109+
*/
110+
@Deprecated
111+
public String getName() {
112+
return getId().toString();
113+
}
114+
115+
public Stream<T> stream() {
116+
return isPresent() ? Stream.of(get()) : Stream.of();
117+
}
118+
119+
/**
120+
* Return {@code true} if there is a mod object present, otherwise {@code false}.
121+
*
122+
* @return {@code true} if there is a mod object present, otherwise {@code false}
123+
*/
124+
public boolean isPresent() {
125+
return get() != null;
126+
}
127+
128+
/**
129+
* If a mod object is present, invoke the specified consumer with the object,
130+
* otherwise do nothing.
131+
*
132+
* @param consumer block to be executed if a mod object is present
133+
* @throws NullPointerException if mod object is present and {@code consumer} is
134+
* null
135+
*/
136+
public void ifPresent(Consumer<? super T> consumer) {
137+
if (get() != null) {
138+
consumer.accept(get());
139+
}
140+
}
141+
142+
/**
143+
* If a mod object is present, and the mod object matches the given predicate,
144+
* return an {@code RegistryObject} describing the value, otherwise return an
145+
* empty {@code RegistryObject}.
146+
*
147+
* @param predicate a predicate to apply to the mod object, if present
148+
* @return an {@code RegistryObject} describing the value of this {@code RegistryObject}
149+
* if a mod object is present and the mod object matches the given predicate,
150+
* otherwise an empty {@code RegistryObject}
151+
* @throws NullPointerException if the predicate is null
152+
*/
153+
public RegistryObject<T> filter(Predicate<? super T> predicate) {
154+
Objects.requireNonNull(predicate);
155+
156+
if (!isPresent()) {
157+
return this;
158+
} else {
159+
return predicate.test(get()) ? this : empty();
160+
}
161+
}
162+
163+
/**
164+
* If a mod object is present, apply the provided mapping function to it,
165+
* and if the result is non-null, return an {@code Optional} describing the
166+
* result. Otherwise return an empty {@code Optional}.
167+
*
168+
* @param <U> The type of the result of the mapping function
169+
* @param mapper a mapping function to apply to the mod object, if present
170+
* @return an {@code Optional} describing the result of applying a mapping
171+
* function to the mod object of this {@code RegistryObject}, if a mod object is present,
172+
* otherwise an empty {@code Optional}
173+
* @throws NullPointerException if the mapping function is null
174+
* @apiNote This method supports post-processing on optional values, without
175+
* the need to explicitly check for a return status.
176+
*/
177+
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
178+
Objects.requireNonNull(mapper);
179+
180+
if (!isPresent()) {
181+
return Optional.empty();
182+
} else {
183+
return Optional.ofNullable(mapper.apply(get()));
184+
}
185+
}
186+
187+
/**
188+
* If a value is present, apply the provided {@code Optional}-bearing
189+
* mapping function to it, return that result, otherwise return an empty
190+
* {@code Optional}. This method is similar to {@link #map(Function)},
191+
* but the provided mapper is one whose result is already an {@code Optional},
192+
* and if invoked, {@code flatMap} does not wrap it with an additional
193+
* {@code Optional}.
194+
*
195+
* @param <U> The type parameter to the {@code Optional} returned by
196+
* @param mapper a mapping function to apply to the mod object, if present
197+
* the mapping function
198+
* @return the result of applying an {@code Optional}-bearing mapping
199+
* function to the value of this {@code Optional}, if a value is present,
200+
* otherwise an empty {@code Optional}
201+
* @throws NullPointerException if the mapping function is null or returns
202+
* a null result
203+
*/
204+
public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
205+
Objects.requireNonNull(mapper);
206+
207+
if (!isPresent()) {
208+
return Optional.empty();
209+
} else {
210+
return Objects.requireNonNull(mapper.apply(get()));
211+
}
212+
}
213+
214+
/**
215+
* If a mod object is present, lazily apply the provided mapping function to it,
216+
* returning a supplier for the transformed result. If this object is empty, or the
217+
* mapping function returns {@code null}, the supplier will return {@code null}.
218+
*
219+
* @param <U> The type of the result of the mapping function
220+
* @param mapper A mapping function to apply to the mod object, if present
221+
* @return A {@code Supplier} lazily providing the result of applying a mapping
222+
* function to the mod object of this {@code RegistryObject}, if a mod object is present,
223+
* otherwise a supplier returning {@code null}
224+
* @throws NullPointerException if the mapping function is {@code null}
225+
* @apiNote This method supports post-processing on optional values, without
226+
* the need to explicitly check for a return status.
227+
*/
228+
public <U> Supplier<U> lazyMap(Function<? super T, ? extends U> mapper) {
229+
Objects.requireNonNull(mapper);
230+
return () -> isPresent() ? mapper.apply(get()) : null;
231+
}
232+
233+
/**
234+
* Return the mod object if present, otherwise return {@code other}.
235+
*
236+
* @param other the mod object to be returned if there is no mod object present, may
237+
* be null
238+
* @return the mod object, if present, otherwise {@code other}
239+
*/
240+
public T orElse(T other) {
241+
return isPresent() ? get() : other;
242+
}
243+
244+
/**
245+
* Return the mod object if present, otherwise invoke {@code other} and return
246+
* the result of that invocation.
247+
*
248+
* @param other a {@code Supplier} whose result is returned if no mod object
249+
* is present
250+
* @return the mod object if present otherwise the result of {@code other.get()}
251+
* @throws NullPointerException if mod object is not present and {@code other} is
252+
* null
253+
*/
254+
public T orElseGet(Supplier<? extends T> other) {
255+
return isPresent() ? get() : other.get();
256+
}
257+
258+
/**
259+
* Return the contained mod object, if present, otherwise throw an exception
260+
* to be created by the provided supplier.
261+
*
262+
* @param <X> Type of the exception to be thrown
263+
* @param exceptionSupplier The supplier which will return the exception to
264+
* be thrown
265+
* @return the present mod object
266+
* @throws X if there is no mod object present
267+
* @throws NullPointerException if no mod object is present and
268+
* {@code exceptionSupplier} is null
269+
* @apiNote A method reference to the exception constructor with an empty
270+
* argument list can be used as the supplier. For example,
271+
* {@code IllegalStateException::new}
272+
*/
273+
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
274+
if (get() != null) {
275+
return get();
276+
} else {
277+
throw exceptionSupplier.get();
278+
}
279+
}
280+
281+
@Override
282+
public boolean equals(Object obj) {
283+
if (this == obj) return true;
284+
285+
if (obj instanceof RegistryObject) {
286+
return Objects.equals(((RegistryObject<?>) obj).name, name);
287+
}
288+
289+
return false;
290+
}
291+
292+
@Override
293+
public int hashCode() {
294+
return Objects.hashCode(name);
295+
}
296+
}

0 commit comments

Comments
 (0)