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

Add a tracked data handler registry #3584

Open
wants to merge 3 commits into
base: 1.20.5
Choose a base branch
from

Conversation

haykam821
Copy link
Contributor

@haykam821 haykam821 commented Feb 11, 2024

This pull request introduces a new API for registering tracked data handlers, which reduces conflicts between mods registering tracked data handlers in an order that is inconsistent between clients and servers.

To use the API, simply replace usages of the vanilla method:

- TrackedDataHandlerRegistry.register(TRACKED_DATA_HANDLER);
+ FabricTrackedDataRegistry.registerHandler(TRACKED_DATA_HANDLER_ID, TRACKED_DATA_HANDLER);

An example of a mod introducing tracked data handlers is provided within the testmod. This entity uses tracked data handlers for global positions, items, and optional item groups, all of which are not available as one of the vanilla tracked data handlers.

A few remarks regarding the implementation of this API:

  • Documentation has not been written yet.
  • Note that the class name is FabricTrackedDataRegistry rather than FabricTrackedDataHandlerRegistry so that tracked data support can be added in the future within the same class; see Hooks to allow registration of custom tracked data fields on entities. #1049 for more information.
  • Each registration recomputes the map used by vanilla. I'm not sure whether optimizing this behavior is worthwhile; the work required to delay computation until the map is accessed would be more invasive than the current setup.
  • Mods that do not switch to this API will still work as before. Said mods will not gain the benefits of using this API and will still lack a guarantee of tracked data handlers matching between clients and servers.
  • There isn't any guard against registering a tracked data handler after mod initialization. Should one be added? Currently, the unspoken idea is that mods will only use this API during mod initialization.
  • Mods assuming that tracked data handler IDs are stable during mod initialization (or possibly later, per the last remark) will be broken. I assume this breakage is fine, as I doubt many mods interact with tracked data handlers in this way.

Fixes #3482

@modmuss50 modmuss50 added the enhancement New feature or request label Feb 11, 2024
@modmuss50 modmuss50 self-requested a review February 12, 2024 20:25
@Linguardium
Copy link

Linguardium commented Feb 17, 2024

would it be beneficial to add a warning if a non-vanilla handler is registered? (outside of the api)

@haykam821
Copy link
Contributor Author

@Linguardium A warning already will be logged in that scenario.

@Linguardium
Copy link

Yep, i missed that

private FabricTrackedDataRegistry() {
}

public static void registerHandler(Identifier id, TrackedDataHandler<?> handler) {
Copy link
Member

Choose a reason for hiding this comment

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

Needs some docs.

import net.fabricmc.fabric.api.event.registry.RegistryIdRemapCallback;
import net.fabricmc.fabric.mixin.object.builder.TrackedDataHandlerRegistryAccessor;

public class FabricTrackedDataRegistryImpl {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: final

}

Registry.register(HANDLER_REGISTRY, id, handler);
reorderHandlers();
Copy link
Member

Choose a reason for hiding this comment

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

I dont think this needs to happen here, if the above change is made.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reviews seem to be ordered differently for me; are you talking about changing the event at which reordering occurs? The idea of reordering after registration is so that every tracked data handler registered via Fabric API is immediately available in the map. If that behavior is unnecessary, then this reordering step can be removed.

.attribute(RegistryAttribute.SYNCED)
.buildAndRegister();

RegistryIdRemapCallback.event(HANDLER_REGISTRY).register(state -> reorderHandlers());
Copy link
Member

Choose a reason for hiding this comment

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

Would Client/ServerPlayConnectionEvents.JOIN be a better place to do this? I dont think it would be a bad idea to sort them event when a modded one isnt registered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If there are no tracked data handlers registered via Fabric API, the sort would have no effect.

import net.fabricmc.fabric.impl.object.builder.FabricTrackedDataRegistryImpl;

@Mixin(TrackedDataHandlerRegistry.class)
public class TrackedDataHandlerRegistryMixin {
Copy link
Member

Choose a reason for hiding this comment

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

Would it be worth while injecting into register and logging a warning (or even crashing in dev?) if a handler is registered the vanilla way?

Logging the warning with a stacktrace would be more helpful when trying to track down mods that arent using the API.

import net.minecraft.util.math.GlobalPos;
import net.minecraft.world.World;

public class TrackStackEntity extends MobEntity {
Copy link
Member

Choose a reason for hiding this comment

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

Might be nice to have a gametest that spawns the entity? Just make sure things dont crash?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure how to implement game tests, but using one here seems reasonable. The entity interaction should be simulated as well.

Copy link
Member

Choose a reason for hiding this comment

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

https://github.com/FabricMC/fabric/blob/892bf04af77eebeb135b611785ce6efa97ebd475/fabric-command-api-v2/src/testmod/java/net/fabricmc/fabric/test/command/EntitySelectorGameTest.java might be a good starting point. Happy to guide you through them.

The game tests only run as the server, so they wouldnt be able to check that the data is sycning correctly, but it can at least assume it.

@Mixin(TrackedDataHandlerRegistry.class)
public class TrackedDataHandlerRegistryMixin {
@Inject(method = "<clinit>", at = @At("TAIL"))
private static void storeVanillaHandlers(CallbackInfo ci) {

Choose a reason for hiding this comment

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

Use a static block over an inject.

Copy link
Contributor Author

@haykam821 haykam821 Feb 19, 2024

Choose a reason for hiding this comment

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

Note that TheEndBiomeSourceMixin, RenderLayersMixin, DefaultAttributeRegistryMixin, BlockEntityRendererFactoriesMixin, and EntityRenderersMixin also seem to use a <clinit> inject in a similar way to this mixin; should those be changed as well (at a later time)?

@modmuss50
Copy link
Member

@haykam821 are you intrested in finishing this off? I dont think there was anything too crazy left to do on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants