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.21.3] RegisterRenderStateModifiersEvent for appending custom data to render state objects #1650

Open
wants to merge 49 commits into
base: 1.21.x
Choose a base branch
from

Conversation

dhyces
Copy link
Contributor

@dhyces dhyces commented Oct 31, 2024

Closes #1638

This PR targets extensibility of EntityRenderState, MapRenderState, and MapDecorationRenderState due to how inextensible the new render state system is. The system added on top allows for adding client-sided elements to render states. To accomplish this, a new event is added RegisterRenderStateModifiersEvent. The event supplies several methods for registering modifiers for the various types of render state objects. Should be extended with another method registerItemModifier in 1.21.4 for ItemStackRenderStates. Users would then add to the render state by calling IRenderStateExtension#setRenderData with a statically initialized ContextKey and the data they wish to store. Vanilla data may also be modified (at the user's discretion). For entity render states, every modifier that applies to the given renderer class is run, including modifiers that target superclasses, and are cached to be as efficient as possible.

@neoforged-pr-publishing
Copy link

neoforged-pr-publishing bot commented Oct 31, 2024

  • Publish PR to GitHub Packages

Last commit published: d400b27441cfe82f25d2a0d5fc21c986361b6233.

PR Publishing

The artifacts published by this PR:

Repository Declaration

In order to use the artifacts published by the PR, add the following repository to your buildscript:

repositories {
    maven {
        name 'Maven for PR #1650' // https://github.com/neoforged/NeoForge/pull/1650
        url 'https://prmaven.neoforged.net/NeoForge/pr1650'
        content {
            includeModule('net.neoforged', 'testframework')
            includeModule('net.neoforged', 'neoforge')
        }
    }
}

MDK installation

In order to setup a MDK using the latest PR version, run the following commands in a terminal.
The script works on both *nix and Windows as long as you have the JDK bin folder on the path.
The script will clone the MDK in a folder named NeoForge-pr1650.
On Powershell you will need to remove the -L flag from the curl invocation.

mkdir NeoForge-pr1650
cd NeoForge-pr1650
curl -L https://prmaven.neoforged.net/NeoForge/pr1650/net/neoforged/neoforge/21.3.88-beta-pr-1650-feat-render-state-event/mdk-pr1650.zip -o mdk.zip
jar xf mdk.zip
rm mdk.zip || del mdk.zip

To test a production environment, you can download the installer from here.

@XFactHD XFactHD added enhancement New (or improvement to existing) feature or request rendering Related to rendering 1.21.3 Targeted at Minecraft 1.21.3 labels Oct 31, 2024
@Technici4n
Copy link
Member

I think that having:

  • The attachment holder (which is weird if it's mutable I think).
  • The ad-hoc key system to add extensions.
  • The extension/merger system.
    is 3 ways of achieving essentially the same thing. That's too much. I think there should only be one way.

Also, are there thread-safety or similar issues that would force us to make the data immutable? Or is it fine to directly reference the entity or something that it contains?

@dhyces
Copy link
Contributor Author

dhyces commented Nov 1, 2024

I think that having:

  • The attachment holder (which is weird if it's mutable I think).
  • The ad-hoc key system to add extensions.
  • The extension/merger system.
    is 3 ways of achieving essentially the same thing. That's too much. I think there should only be one way.

Also, are there thread-safety or similar issues that would force us to make the data immutable? Or is it fine to directly reference the entity or something that it contains?

I mentioned in the description that the key system and extension system were two different examples for how it could work, only one would be implemented. I somewhat agree that the attachments would be enough (and yes, while it's mutable, it's a copy and wouldn't affect the client entity), though there may be some aspects that simply would be better off not using attachments and should use something else to extend the RenderState. Tslat mentioned in neocord that generic extension outside of attachments would be necessary.

@Technici4n
Copy link
Member

An idea might be to use a context map 🤔

@neoforged-automation
Copy link

@dhyces, this pull request has conflicts, please resolve them for this PR to move forward.

1. Moved callsite to `createRenderState`. This differs from feedback, though I believe is a better location, seeing as the method is final and will apply modifiers if users call the method.
2. Some classes have been renamed to better reflect behavior
3. Use ContextKey instead of custom class
4. Retain each modifier separately so that subclasses may be considered
5. Use lazily evaluated map for storing all modifiers that apply to a given renderer
@dhyces dhyces changed the title [1.21.3] UpdateRenderStateEvent and EntityRenderState extends AttachmentHolder [1.21.3] RegisterRenderStateModifiersEvent and EntityRenderState extends AttachmentHolder Nov 11, 2024
@dhyces dhyces marked this pull request as ready for review November 14, 2024 23:22
@dhyces dhyces requested a review from XFactHD November 14, 2024 23:22
Copy link
Member

@XFactHD XFactHD left a comment

Choose a reason for hiding this comment

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

The overall approach seems sane to me. One thing I'm thinking about though is whether it would make sense to make these extensions a bit more generic from the start by using two base classes for them which the vanilla ones extend from instead of patching the entire machinery into each of the respective vanilla "base" render state class (in this case EntityRenderState). What I'm imagining is a BaseRenderState or AbstractRenderState that holds the generic extension part and a AttachmentAwareRenderState which extends the former and implements IAttachmentHolder. The attachment holder implementation would be immutable which may also allow using an unmodifiable view of the entity's attachments map instead of copying it. The vanilla EntityRenderState (and the respective class for BEs if BERs get the same treatment) would then extend AttachmentAwareRenderState while MapRenderState, MapDecorationRenderState and ItemStackRenderState would extend BaseRenderState. The state modifier registration and retrieval would of course still have to be per "base type" (i.e. entity, map, map decoration, BE, itemstack).

@dhyces
Copy link
Contributor Author

dhyces commented Nov 18, 2024

The overall approach seems sane to me. One thing I'm thinking about though is whether it would make sense to make these extensions a bit more generic from the start by using two base classes for them which the vanilla ones extend from instead of patching the entire machinery into each of the respective vanilla "base" render state class (in this case EntityRenderState). What I'm imagining is a BaseRenderState or AbstractRenderState that holds the generic extension part and a AttachmentAwareRenderState which extends the former and implements IAttachmentHolder. The attachment holder implementation would be immutable which may also allow using an unmodifiable view of the entity's attachments map instead of copying it. The vanilla EntityRenderState (and the respective class for BEs if BERs get the same treatment) would then extend AttachmentAwareRenderState while MapRenderState, MapDecorationRenderState and ItemStackRenderState would extend BaseRenderState. The state modifier registration and retrieval would of course still have to be per "base type" (i.e. entity, map, map decoration, BE, itemstack).

I like this idea a lot. I haven't yet looked into the Map... render states, so I'm not sure how that could be useful. Could you provide an example? I also have a concern with the attachment stuff, since we provide the arbitrary render data already, should we just tell users that if they want to access some data from their synced attachments, they can use a modifier to copy it over themselves? That way everything's not copied every time regardless of whether it's used or not.

@dhyces dhyces requested a review from XFactHD November 20, 2024 01:20
Copy link
Member

@XFactHD XFactHD left a comment

Choose a reason for hiding this comment

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

While testing, I found that registering modifiers for generic renderers leads to really ugly, unchecked casts in the registration. For example, registering a modifier for any LivingEntityRenderer ends up with this:

event.registerEntityModifier(
    (Class<? extends EntityRenderer<LivingEntity, LivingEntityRenderState>>) LivingEntityRenderer.class,
    (entity, renderState) -> {}
);

since you can't specify generics in a class literal. I'm not sure there is anything we can realistically do about this though without just entirely dropping type safety.

@XFactHD
Copy link
Member

XFactHD commented Nov 21, 2024

@neoforged/bots run applyAllFormatting

@neoforged-automation
Copy link

Running Gradle tasks applyAllFormatting...

@neoforged-automation
Copy link

Copy link
Contributor

@lukebemish lukebemish left a comment

Choose a reason for hiding this comment

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

I'd make use of type tokens for checking compatibility in that check -- the current logic has some substantial holes in that and a type token super/subclass comparison lets you avoid all those. If not, please make sure there's no wacky edge cases here in any case -- that's a subtle bug caused by some particular mod interaction waiting to happen. If you're not making use of compile time type safety, the runtime type safety needs to be quite strong so it's guaranteed to fire in dev if something could go wrong.

@dhyces dhyces requested a review from XFactHD November 23, 2024 20:23
@dhyces dhyces requested a review from XFactHD November 24, 2024 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.21.3 Targeted at Minecraft 1.21.3 enhancement New (or improvement to existing) feature or request rendering Related to rendering
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make Entity's Data Attachments visible through EntityRenderState
6 participants