aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/api/0484-Registry-Modification-API.patch
blob: 7ae62ac0e9119c7d57a95f609aa97d000f15c3ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 2 Mar 2022 13:36:21 -0800
Subject: [PATCH] Registry Modification API


diff --git a/src/main/java/io/papermc/paper/registry/RegistryBuilder.java b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..6edf300c1d81c1001756141c9efd022ba0e372cd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java
@@ -0,0 +1,13 @@
+package io.papermc.paper.registry;
+
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * To be implemented by any type used for modifying registries.
+ *
+ * @param <T> registry value type
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+public interface RegistryBuilder<T> {
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryView.java b/src/main/java/io/papermc/paper/registry/RegistryView.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc25a03b5c06473300cc1b6d505780e68e5e82fc
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryView.java
@@ -0,0 +1,20 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Provides read-only access to a registry.
+ *
+ * @param <T> registry value type
+ */
+@ApiStatus.Experimental
+@ApiStatus.NonExtendable
+public interface RegistryView<T> extends Iterable<T> {
+
+    @Nullable T get(final @NonNull Key key);
+
+    @NonNull T getOrThrow(final @NonNull Key key);
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6722f7b55e260bab4bab5c361f9c0e9888c6752
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java
@@ -0,0 +1,33 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.registry.RegistryBuilder;
+import io.papermc.paper.registry.TypedKey;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Event object for {@link RegistryEventProvider#entryAdd()}. This
+ * event is fired right before a specific entry is registered in/added to registry.
+ * It provides a way for plugins to modify parts of this entry.
+ *
+ * @param <T> registry entry type
+ * @param <B> registry entry builder type
+ */
+@ApiStatus.Experimental
+@ApiStatus.NonExtendable
+public interface RegistryEntryAddEvent<T, B extends RegistryBuilder<T>> extends RegistryEvent<T> {
+
+    /**
+     * Gets the builder for the entry being added to the registry.
+     *
+     * @return the object builder
+     */
+    @NonNull B builder();
+
+    /**
+     * Gets the key for this entry in the registry.
+     *
+     * @return the key
+     */
+    @NonNull TypedKey<T> key();
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c83dc6ef3cbe5ec40d464ad96387d7c3d04f1458
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java
@@ -0,0 +1,32 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.RegistryView;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Base type for all registry events.
+ *
+ * @param <T> registry entry type
+ */
+@ApiStatus.Experimental
+@ApiStatus.NonExtendable
+public interface RegistryEvent<T> extends LifecycleEvent {
+
+    /**
+     * Get the key for the registry this event pertains to.
+     *
+     * @return the registry key
+     */
+    @NonNull RegistryKey<T> registryKey();
+
+    /**
+     * Get a view of the registry which may or may not
+     * be complete based on the event.
+     *
+     * @return a registry view
+     */
+    @NonNull RegistryView<T> registry();
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..793208a46680d7b9e164c14012d2b7c9af55499f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java
@@ -0,0 +1,83 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration;
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration;
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType;
+import io.papermc.paper.registry.RegistryBuilder;
+import io.papermc.paper.registry.RegistryKey;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Provider for registry events for a specific registry.
+ * <p>
+ * Supported events are:
+ * <ul>
+ *     <li>{@link RegistryEntryAddEvent} (via {@link #entryAdd()})</li>
+ *     <li>{@link RegistryFreezeEvent} (via {@link #freeze()})</li>
+ * </ul>
+ *
+ * @param <T> registry entry type
+ * @param <B> registry entry builder type
+ */
+@ApiStatus.Experimental
+@ApiStatus.NonExtendable
+public interface RegistryEventProvider<T, B extends RegistryBuilder<T>> {
+
+    /**
+     * Gets the event type for {@link RegistryEntryAddEvent} which is fired just before
+     * an object is added to a registry.
+     * <p>
+     * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)}
+     * to register a handler for {@link RegistryEntryAddEvent}.
+     *
+     * @return the addition event type
+     */
+    LifecycleEventType.@NonNull Prioritizable<BootstrapContext, RegistryEntryAddEvent<T, B>> entryAdd();
+
+    /**
+     * Shortcut for calling {@link #entryAdd()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}.
+     * <p>
+     * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)}
+     * to register a handler for {@link RegistryEntryAddEvent}
+     *
+     * @param handler the event handler for {@link RegistryEntryAddEvent}
+     * @return the configuration for further use
+     */
+    default @NonNull PrioritizedLifecycleEventHandlerConfiguration<BootstrapContext> newEntryAddHandler(final @NonNull LifecycleEventHandler<? super RegistryEntryAddEvent<T, B>> handler) {
+        return this.entryAdd().newHandler(handler);
+    }
+
+    /**
+     * Gets the event type for {@link RegistryFreezeEvent} which is fired just before
+     * a registry is frozen. It allows for the registration of new objects.
+     * <p>
+     * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)}
+     * to register a handler for {@link RegistryFreezeEvent}.
+     *
+     * @return the pre-freeze event type
+     */
+    LifecycleEventType.@NonNull Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> freeze();
+
+    /**
+     * Shortcut for calling {@link #freeze()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}.
+     * <p>
+     * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)}
+     * to register a handler for {@link RegistryFreezeEvent}
+     *
+     * @param handler the event handler for {@link RegistryFreezeEvent}
+     * @return the configuration for further use
+     */
+    default @NonNull PrioritizedLifecycleEventHandlerConfiguration<BootstrapContext> newFreezeHandler(final @NonNull LifecycleEventHandler<? super RegistryFreezeEvent<T, B>> handler) {
+        return this.freeze().newHandler(handler);
+    }
+
+    /**
+     * Gets the registry key associated with this event type provider.
+     *
+     * @return the registry key
+     */
+    @NonNull RegistryKey<T> registryKey();
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..85a9fbc6aa59e95aac57aa6e626a7366222cf80e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java
@@ -0,0 +1,29 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType;
+import io.papermc.paper.registry.RegistryBuilder;
+import io.papermc.paper.registry.RegistryKey;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+@DefaultQualifier(NonNull.class)
+record RegistryEventProviderImpl<T, B extends RegistryBuilder<T>>(RegistryKey<T> registryKey) implements RegistryEventProvider<T, B> {
+
+    static <T, B extends RegistryBuilder<T>> RegistryEventProvider<T, B> create(final RegistryKey<T> registryKey) {
+        return new RegistryEventProviderImpl<>(registryKey);
+    }
+
+    @Override
+    public LifecycleEventType.Prioritizable<BootstrapContext, RegistryEntryAddEvent<T, B>> entryAdd() {
+        return RegistryEventTypeProvider.provider().registryAddition(this);
+    }
+
+    @Override
+    public LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> freeze() {
+        return RegistryEventTypeProvider.provider().registryPreFreeze(this);
+    }
+
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e3f041f2c4ee09d806c0528af2f67912525d94c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java
@@ -0,0 +1,23 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType;
+import io.papermc.paper.registry.RegistryBuilder;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+interface RegistryEventTypeProvider {
+
+    Optional<RegistryEventTypeProvider> PROVIDER = ServiceLoader.load(RegistryEventTypeProvider.class)
+        .findFirst();
+
+    static RegistryEventTypeProvider provider() {
+        return PROVIDER.orElseThrow(() -> new IllegalStateException("Could not find a %s service implementation".formatted(RegistryEventTypeProvider.class.getSimpleName())));
+    }
+
+    <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryEntryAddEvent<T, B>> registryAddition(RegistryEventProvider<T, B> type);
+
+    <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> registryPreFreeze(RegistryEventProvider<T, B> type);
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f89945be2ed68f52a544f41f7a151b8fdfe113e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java
@@ -0,0 +1,14 @@
+package io.papermc.paper.registry.event;
+
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Holds providers for {@link RegistryEntryAddEvent} and {@link RegistryFreezeEvent}
+ * handlers for each applicable registry.
+ */
+@ApiStatus.Experimental
+public final class RegistryEvents {
+
+    private RegistryEvents() {
+    }
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d34ab36303337551e6318228fd2b28ec7da75d3
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java
@@ -0,0 +1,27 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.registry.RegistryBuilder;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Event object for {@link RegistryEventProvider#freeze()}. This
+ * event is fired right before a registry is frozen disallowing further changes.
+ * It provides a way for plugins to add new objects to the registry.
+ *
+ * @param <T> registry entry type
+ * @param <B> registry entry builder type
+ */
+@ApiStatus.Experimental
+@ApiStatus.NonExtendable
+public interface RegistryFreezeEvent<T, B extends RegistryBuilder<T>> extends RegistryEvent<T> {
+
+    /**
+     * Get a view of the registry which supports
+     * the registering of new values.
+     *
+     * @return a writable registry view
+     */
+    @Override
+    @NonNull WritableRegistry<T, B> registry();
+}
diff --git a/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a0356b7da3844e7ec9121656dc059f53d48301e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java
@@ -0,0 +1,28 @@
+package io.papermc.paper.registry.event;
+
+import io.papermc.paper.registry.RegistryBuilder;
+import io.papermc.paper.registry.RegistryView;
+import io.papermc.paper.registry.TypedKey;
+import java.util.function.Consumer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * A registry view which supports registering new objects.
+ *
+ * @param <T> registry entry type
+ * @param <B> registry entry builder type
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+public interface WritableRegistry<T, B extends RegistryBuilder<T>> extends RegistryView<T> {
+
+    /**
+     * Register a new value with the specified key. This will
+     * fire a {@link RegistryEntryAddEvent} for the new entry.
+     *
+     * @param key the entry's key (must be unique from others)
+     * @param value a consumer for the entry's builder
+     */
+    void register(@NonNull TypedKey<T> key, @NonNull Consumer<? super B> value);
+}
diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java
index 88bb3b9ae99fae97ec21972b75ec43cb6b7b22b5..661af93e3f73aaf1eca0be08b73fae62c534ecbe 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
@@ -352,6 +352,27 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
      */
     @Nullable
     T get(@NotNull NamespacedKey key);
+    // Paper start
+    /**
+     * Get the object by its key.
+     *
+     * @param key non-null key
+     * @return item or null if it does not exist
+     */
+    default @Nullable T get(final net.kyori.adventure.key.@NotNull Key key) {
+        return key instanceof final NamespacedKey nsKey ? this.get(nsKey) : this.get(new NamespacedKey(key.namespace(), key.value()));
+    }
+
+    /**
+     * Get the object by its typed key.
+     *
+     * @param typedKey non-null typed key
+     * @return item or null if it does not exist
+     */
+    default @Nullable T get(final io.papermc.paper.registry.@NotNull TypedKey<T> typedKey) {
+        return this.get(typedKey.key());
+    }
+    // Paper end
 
     // Paper start - improve Registry
     /**