2828import net .kyori .adventure .text .serializer .ComponentSerializer ;
2929import org .checkerframework .checker .nullness .qual .Nullable ;
3030import org .spongepowered .api .Game ;
31- import org .spongepowered .api .ResourceKey ;
3231import org .spongepowered .api .Server ;
3332import org .spongepowered .api .Sponge ;
3433import org .spongepowered .api .command .parameter .CommandContext ;
35- import org .spongepowered .api .command .parameter .Parameter ;
3634import org .spongepowered .api .command .parameter .managed .ValueParameter ;
3735import org .spongepowered .api .registry .DefaultedRegistryReference ;
3836import org .spongepowered .api .registry .DefaultedRegistryType ;
3937import org .spongepowered .api .registry .Registry ;
4038import org .spongepowered .api .registry .RegistryHolder ;
4139import org .spongepowered .api .registry .RegistryKey ;
4240import org .spongepowered .api .registry .RegistryType ;
43- import org .spongepowered .api .registry .RegistryTypes ;
4441import org .spongepowered .api .util .Builder ;
42+ import org .spongepowered .api .world .Locatable ;
43+ import org .spongepowered .api .world .World ;
44+ import org .spongepowered .api .world .server .ServerWorld ;
4545
4646import java .util .Collection ;
4747import java .util .Collections ;
48+ import java .util .List ;
4849import java .util .Map ;
4950import java .util .function .Function ;
5051import java .util .function .Supplier ;
@@ -70,21 +71,23 @@ private VariableValueParameters() {}
7071 */
7172 public static <T > RegistryEntryBuilder <T > registryEntryBuilder (
7273 final Function <CommandContext , @ Nullable RegistryHolder > holderProvider , final RegistryType <T > registryKey ) {
73- return Sponge . game (). factoryProvider (). provide ( Factory . class ). createRegistryEntryBuilder ( holderProvider , registryKey );
74+ return VariableValueParameters . registryEntryBuilder ( Collections . singletonList ( holderProvider ) , registryKey );
7475 }
7576
7677 /**
7778 * Creates a builder that can build a {@link ValueParameter} that returns
7879 * an appropriate {@link Registry registry} entry from an argument.
7980 *
80- * @param registryProvider A {@link Function} that retrieves an appropriate
81- * {@link Registry} to get objects from
81+ * @param holderProviders The providers for {@link RegistryHolder}s to
82+ * retrieve the selected {@link Registry} from
83+ * @param registryKey The {@link RegistryKey} that represents the target
84+ * {@link Registry} to get objects from
8285 * @param <T> The type in the {@link Registry}
8386 * @return The builder
8487 */
8588 public static <T > RegistryEntryBuilder <T > registryEntryBuilder (
86- final Function <CommandContext , @ Nullable ? extends Registry <? extends T >> registryProvider ) {
87- return Sponge .game ().factoryProvider ().provide (Factory .class ).createRegistryEntryBuilder (registryProvider );
89+ final List < Function <CommandContext , @ Nullable RegistryHolder >> holderProviders , final RegistryType < T > registryKey ) {
90+ return Sponge .game ().factoryProvider ().provide (Factory .class ).createRegistryEntryBuilder (holderProviders , registryKey );
8891 }
8992
9093 /**
@@ -243,6 +246,37 @@ public interface RegistryEntryBuilder<T> extends Builder<ValueParameter<T>, Regi
243246 }
244247 };
245248
249+ /**
250+ * A {@link Function} that always provides the {@link World} scoped
251+ * {@link RegistryHolder} from the first {@link Locatable} in the
252+ * provided {@link CommandContext}.
253+ */
254+ Function <CommandContext , @ Nullable RegistryHolder > WORLD_FROM_LOCATABLE_HOLDER_PROVIDER =
255+ in -> in .cause ().first (Locatable .class ).map (Locatable ::world ).map (World ::registries ).orElse (null );
256+
257+ /**
258+ * A {@link Function} that always provides the {@link World} scoped
259+ * {@link RegistryHolder} from the first {@link ServerWorld} in the
260+ * provided {@link CommandContext}.
261+ */
262+ Function <CommandContext , @ Nullable RegistryHolder > WORLD_FROM_CAUSE_HOLDER_PROVIDER =
263+ in -> in .cause ().first (ServerWorld .class ).map (ServerWorld ::registries ).orElse (null );
264+
265+ /**
266+ * Adds an alternative function that retrieves a {@link RegistryHolder}
267+ * to attempt to get the selected {@link RegistryType}.
268+ *
269+ * <p>The order that these functions are added determines their
270+ * priority if there are multiple registries, specifically, the first
271+ * function that is provided will have the highest priority.</p>
272+ *
273+ * <p>Standard functions are available on {@link RegistryEntryBuilder}.</p>
274+ *
275+ * @param holderFunction The holder function
276+ * @return This, for chaining
277+ */
278+ RegistryEntryBuilder <T > addHolderFunction (Function <CommandContext , @ Nullable RegistryHolder > holderFunction );
279+
246280 /**
247281 * Adds a prefix that could be prepended to the input argument if it
248282 * initially does not match any of the chosen {@link RegistryKey}s. Any
@@ -622,46 +656,53 @@ public interface Factory {
622656 * and the provided {@link RegistryHolder}, which may be determined by
623657 * the current state of the {@link CommandContext}.
624658 *
625- * <p>This element can only support <strong>one</strong>
626- * {@link RegistryHolder}, due to the potential of conflicting
627- * {@link ResourceKey resource keys} across multiple registries. If
628- * testing multiple registries across multiple registry holders is
629- * required, consider using {@link Parameter#firstOf(Iterable)} with
630- * multiple versions of this parameter.</p>
631- *
632- * <p>{@link Game} and {@link Server} scoped {@link RegistryHolder}
633- * providers are available via
634- * {@link RegistryEntryBuilder#GLOBAL_HOLDER_PROVIDER} and
635- * {@link RegistryEntryBuilder#SERVER_HOLDER_PROVIDER}</p>
659+ * <p>This element can support multiple functions that return
660+ * {@link RegistryHolder}s, however order matters, the {@link Registry}
661+ * from the first holder that is resolved will be used. Holders may be
662+ * added via {@link RegistryEntryBuilder#addHolderFunction(Function)}.
663+ * </p>
636664 *
637665 * @param <T> The type that the target {@link Registry} holds
638- * @param holderProvider A {@link Function} that provides a
639- * {@link RegistryHolder} based on the {@link CommandContext} up to
640- * this parameter.
641666 * @param registryKey The {@link RegistryKey} that represents the target
642667 * {@link Registry} in the {@link RegistryHolder} provided via
643668 * {@code holderProvider}.
644669 * @return The {@link RegistryEntryBuilder}
645670 */
646- <T > RegistryEntryBuilder <T > createRegistryEntryBuilder (final Function < CommandContext , @ Nullable RegistryHolder > holderProvider , final RegistryType <T > registryKey );
671+ <T > RegistryEntryBuilder <T > createRegistryEntryBuilder (final RegistryType <T > registryKey );
647672
648673 /**
649674 * Creates a {@link RegistryEntryBuilder} that retrieves objects from
650- * the provided {@link Registry}, which provided via the given
651- * {@link Function} which <strong>may</strong> use the current
652- * {@link CommandContext} to determine the appropriate
653- * {@link RegistryHolder} to retrieve the {@link Registry} from.
675+ * the {@link Registry} represented by the given {@link RegistryKey}
676+ * and the provided {@link RegistryHolder}, which may be determined by
677+ * the current state of the {@link CommandContext}.
654678 *
655- * <p>When using a {@link RegistryTypes standard registry}, it is
656- * recommended that consumers use
657- * {@link #createRegistryEntryBuilder(Function, RegistryType)}
658- * instead, providing the appropriate {@link RegistryHolder} instead.</p>
679+ * <p>This element can support multiple functions that return
680+ * {@link RegistryHolder}s, however order matters, the {@link Registry}
681+ * from the first holder that is resolved will be used. Beyond the
682+ * holders provided in this function, additional functions that resolve
683+ * holders can be added through
684+ * {@link RegistryEntryBuilder#addHolderFunction(Function)}.</p>
685+ *
686+ * <p>{@link Game} and {@link Server} scoped {@link RegistryHolder}
687+ * providers are available via
688+ * {@link RegistryEntryBuilder#GLOBAL_HOLDER_PROVIDER} and
689+ * {@link RegistryEntryBuilder#SERVER_HOLDER_PROVIDER}. {@link World}
690+ * scoped providers are available via
691+ * {@link RegistryEntryBuilder#WORLD_FROM_CAUSE_HOLDER_PROVIDER} and
692+ * {@link RegistryEntryBuilder#WORLD_FROM_LOCATABLE_HOLDER_PROVIDER}.</p>
659693 *
660694 * @param <T> The type that the target {@link Registry} holds
661- * @param registryProvider The {@link Registry} to get the values from
695+ * @param holderProvider A {@link Function} that provides a
696+ * {@link RegistryHolder} based on the {@link CommandContext} up to
697+ * this parameter.
698+ * @param registryKey The {@link RegistryKey} that represents the target
699+ * {@link Registry} in the {@link RegistryHolder} provided via
700+ * {@code holderProvider}.
662701 * @return The {@link RegistryEntryBuilder}
663702 */
664- <T > RegistryEntryBuilder <T > createRegistryEntryBuilder (final Function <CommandContext , @ Nullable ? extends Registry <? extends T >> registryProvider );
703+ <T > RegistryEntryBuilder <T > createRegistryEntryBuilder (
704+ final List <Function <CommandContext , @ Nullable RegistryHolder >> holderProvider ,
705+ final RegistryType <T > registryKey );
665706
666707 /**
667708 * Creates a {@link RegistryEntryBuilder} that retrieves objects from
0 commit comments