Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.20.x] Deprecate RegistryObject for removal #35

Closed
wants to merge 15 commits into from

Conversation

Shadows-of-Fire
Copy link
Contributor

@Shadows-of-Fire Shadows-of-Fire commented Jul 19, 2023

This PR performs the following goals as an initial transition to the vanilla registry system, in accordance with #37:

  1. Forces all forge registries to be backed by a vanilla registry.
  2. Makes RegistryObject implement Holder.
  3. Deprecates RegistryObject for removal, as all uses can be replaced with Holder.
  4. Introduces DeferredHolder to replaces uses of RegistryObject not covered by Holder$Reference.

Due to method signatures, DeferredRegister#register must still return a RegistryObject, but callers can switch the return type of the stored value to Holder or DeferredHolder.

@Shadows-of-Fire Shadows-of-Fire requested a review from a team July 19, 2023 10:18
@cpw
Copy link
Member

cpw commented Jul 20, 2023

Suggestion: while this is still being discussed, can we mark this as a draft PR, please? Thanks.

@Shadows-of-Fire
Copy link
Contributor Author

Shadows-of-Fire commented Jul 20, 2023

Suggestion: while this is still being discussed, can we mark this as a draft PR, please? Thanks.

I could but I think we're past that point now :p

@sciwhiz12 sciwhiz12 added enhancement New (or improvement to existing) feature or request 1.20 Targeted at Minecraft 1.20 labels Jul 28, 2023
ApexModder added a commit to ApexStudios-Dev/ApexCore-Archive that referenced this pull request Jul 30, 2023
…ge changes, and revolve more around vanilla Holder types.

Mentioned NeoForge Registry changes:
neoforged/NeoForge#35
neoforged/NeoForge#37
@Shadows-of-Fire
Copy link
Contributor Author

Changes made, except for the one about the cast in DeferredHolder#create - that one has to stay there, as moving it is a compile -time error (sometimes, the eclipse compiler works fine but gradle does not)

C:\Development\Github\NeoForgeFork\src\main\java\net\minecraftforge\registries\DeferredHolder.java:53: error: no suitable method found for create(ResourceKey<CAP#1>,ResourceLocation)
        return new DeferredHolder<T>((ResourceKey) ResourceKey.create(registryKey, valueName));
                                                              ^
    method ResourceKey.<T#2>create(ResourceKey<? extends Registry<T#2>>,ResourceLocation) is not applicable
      (cannot infer type-variable(s) T#2
        (argument mismatch; ResourceKey<CAP#1> cannot be converted to ResourceKey<? extends Registry<T#2>>))
    method ResourceKey.<T#3>create(ResourceLocation,ResourceLocation) is not applicable
      (cannot infer type-variable(s) T#3
        (argument mismatch; ResourceKey<CAP#1> cannot be converted to ResourceLocation))
  where T#1,T#2,T#3 are type-variables:
    T#1 extends Object declared in method <T#1>create(ResourceKey<? extends Registry<? super T#1>>,ResourceLocation)
    T#2 extends Object declared in method <T#2>create(ResourceKey<? extends Registry<T#2>>,ResourceLocation)
    T#3 extends Object declared in method <T#3>create(ResourceLocation,ResourceLocation)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Registry<? super T#1> from capture of ? extends Registry<? super T#1>

Copy link
Member

@pupnewfster pupnewfster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple more changes. I also still need to try and figure out/validate whether making all forge registries have a backing vanilla one causes compatibility issues when it comes to syncing, as I am not sure if vanilla will then try to sync all the things in BuiltInRegistries.REGISTRY... And if it does:
a. There may be issues when using a client that doesn't have this PR on a server that does (or vice versa)
b. It would be syncing things that RegistryBuilder#disableSync was used to try and disable

Copy link
Contributor

@SizableShrimp SizableShrimp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are my thoughts.

@Shadows-of-Fire
Copy link
Contributor Author

DefReg docs updated, rebased to fix compat check that was failing due to #72

* @param name the name of the object to look up in the forge registry
* @param registry the forge registry
* @return a {@link RegistryObject} that stores the value of an object from the provided forge registry once it is ready
*/
public static <T, U extends T> RegistryObject<U> create(final ResourceLocation name, IForgeRegistry<T> registry)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming that most users of this API would be third parties, should they be directed to IForgeRegistry#getHolder?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a related note, should IForgeRegistry#getHolder be updated to return a DeferredHolder/similar itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should they be directed to IForgeRegistry#getHolder

No, probably not, given that getHolder defers to the vanilla registry, which is implemented as Optional.ofNullable(this.byKey.get(pKey)). This operation requires that the object be registered before the Holder can be accessed (which is usually not the case at the time of creation of DH/RO's)

IForgeRegistry#getHolder be updated to return a DeferredHolder/similar itself

Since those methods are mostly bouncers to vanilla they will be gone after the upcoming refactor. There might be room to add an additional getDeferredHolder method to IForgeRegistry but it would just be a util that wraps create.

* @param <T> The type of object being held by this DeferredHolder.
*/
// TODO: (Breaking Change) - Add a second generic type for the base registry type
public class DeferredHolder<T> implements Holder<T>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be one type for the registry and one type for the actual type. The Holder should have the registry type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bikeshedding here, but I'd prefer DeferredHolder<TRegistry, TInstance extends TRegistry> implements Holder<TRegistry>

Comment on lines +54 to +80
public static <R, T extends R> DeferredHolder<T> create(ResourceKey<? extends Registry<R>> registryKey, ResourceLocation valueName)
{
return create(ResourceKey.create(registryKey, valueName));
}

/**
* Creates a new DeferredHolder targeting the value with the specified name in the specified registry.
*
* @param <T> The registry type.
* @param registryName The name of the registry the target value is a member of.
* @param valueName The name of the target value.
*/
public static <T> DeferredHolder<T> create(ResourceLocation registryName, ResourceLocation valueName)
{
return create(ResourceKey.createRegistryKey(registryName), valueName);
}

/**
* Creates a new DeferredHolder targeting the specified value.
*
* @param <T> The type of the target value.
* @param key The resource key of the target value.
*/
public static <T> DeferredHolder<T> create(ResourceKey<? super T> key)
{
return new DeferredHolder<>(key);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These constructors will take an unbounded actual type, and I'm not a fan - it's easy to make a mistake. Maybe we make these methods protected. Otherwise we can also split DeferredHolder<R> and SomeSubclass<R, T> (R referring to the registry type here).

* The currently cached value.
*/
@Nullable
protected Holder<T> holder = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is thread safety a potential concern here?

Copy link
Contributor

@KnightMiner KnightMiner Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No threading issue is possible here, since bind will get the same value if called multiple times (setting this to null between), and there is no window in which holder is no longer null but not the correct holder.

In other words, threading issues would happen in the middle of a call to bind. If one thread finishes bind before the other starts, you just fetch the holder multiple times and get the same value each time. If one thread makes it past line 141 then the other calls bind, it just gets bound again. Worst case scenario is two threads both throw on missing registry.

@Matyrobbrt Matyrobbrt mentioned this pull request Nov 6, 2023
@sciwhiz12
Copy link
Member

Superseded by #257, the registry rework PR.

@sciwhiz12 sciwhiz12 closed this Nov 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.20 Targeted at Minecraft 1.20 enhancement New (or improvement to existing) feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.