Skip to content

Added ItemDecorator Map#8794

Merged
gigaherz merged 15 commits intoMinecraftForge:1.19.xfrom
justliliandev:1.19.x-item_decorator
Aug 17, 2022
Merged

Added ItemDecorator Map#8794
gigaherz merged 15 commits intoMinecraftForge:1.19.xfrom
justliliandev:1.19.x-item_decorator

Conversation

@justliliandev
Copy link
Contributor

This is a retry of #8070 and #8079
So beforehand I'll reply to some of the comments of those PRs, if applicable:

DieSieben07 on #8079

Who has the responsibility to add the decorator capability? How are mods supposed to add decorators to "foreign" items? If they add the capability using AttachCapabilitiesEvent this can cause issues if the capability is already added by the item itself or other mods.

To solve this, there is a helper method in ForgeHooksClient to add an IItemDecorator to the ItemStack, during AttachCapabilitiesEvent, so no one has to check if the cap is present and add a provider themselves if it isn't.

ChampionAsh on #8079

I would suggest implementing a positioning system similar to #7770.

I don't think a positioning system is necessary, as the blitOffset (height) is given to the renderer and everyone can render at a height they want. A positioning System would require the rendering of the durability bar and the count to be made an IItemDecorator as well and as soon as every ItemStack needs this capability, a field in the ItemStack will always be faster.
If this is intended I can change that system to not use a capability, but some kind of positioned List

Performance:
Test done on a full chest gui (63 Slots in total) and all slots filled with the same item
With 2 IItemDecorations:
gui needed on average 4.2 ms or ca. 0.066ms per item
Without IItemDecorations:
gui needed on average 2.7ms or ca. 0.042ms per item

@Shadows-of-Fire
Copy link
Contributor

This is not a good way to go about doing this. Render code should not be present or relevant to the server (which capabilities are), Capabilities also add other complexity when present that is additional overhead that is strictly not necessary in a render context (the cost of getCap is significant to be running every frame).

@Shadows-of-Fire Shadows-of-Fire added Feature This request implements a new feature. Rendering This request deals with rendering. These must be treated with care, and tend to progress slowly. Triage This request requires the active attention of the Triage Team. Requires labelling or reviews. 1.19 labels Jun 24, 2022
@justliliandev
Copy link
Contributor Author

diesieben07 wrote in #8048

As an alternative to the event, we could add a capability that mods can add to either their own or other ItemStacks which would then be called to do this rendering. That way no event dispatching needs to happen but the system is still pluggable even for items from other mods or vanilla.

Which is why this thing was designed as a capability.
The only real thing exposed to the server is the registration of the capability, but as adding IItemDecorations is mostly done using a helper in ForgeHooksClient and rendering obviously happens clientside, mod authors should be able to know, that this code should only be used on the logical Client.

Getting the capability, once initialized, is just an array lookup through the ICapabilityProvider in CapabilityDispatcher until one returns the cap you want.
As shown by the performance test I did, I don't think it's as bad as you describe it to be (especially comparing this to RenderLivingEvent.Pre and Post). A List in the ItemStack class will be faster, but that is imo much more exposed on the serverside and has a higher maintenance cost.

Also during normal gameplay only 9 ItemStacks will be usually visible, so the impact in normal gameplay is more likely around/below 0.25ms on each frame

@cpw cpw added the Needs Rebase This PR requires a rebase to implement upstream changes (usually to fix merge conflicts). label Jul 9, 2022
@justliliandev justliliandev force-pushed the 1.19.x-item_decorator branch from 676545f to 384c930 Compare July 9, 2022 18:09
@sciwhiz12 sciwhiz12 removed the Needs Rebase This PR requires a rebase to implement upstream changes (usually to fix merge conflicts). label Jul 10, 2022
Copy link
Contributor

@marchermans marchermans left a comment

Choose a reason for hiding this comment

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

This is a flatout no.
Capabilities are not a great idea to handle rendering, especially on itemstacks where they are already a problem.

Redesign this to be an event please.

@marchermans marchermans added Needs Update This request requires an update from the author to confirm whether the request is relevant. Work In Progress This request has lots of changes that need attention. and removed Triage This request requires the active attention of the Triage Team. Requires labelling or reviews. labels Jul 11, 2022
@justliliandev
Copy link
Contributor Author

What kind of an event?
one fired for each ItemStack being rendered at the same patch location this PR does this atm similar to #7693 or #8048?
one fired for each gui layer (see #6927)?
or one for each frame rendered?
The first one might has performance concerns as previously commented to the two PRs, but I can create that and provide the data, if wanted.
The latter two have the added difficulty to gather all render positions discord conversation. This would require to get the position of dragged stacks, creativetab icons, merchantoffers etc. to be collected (and a way for mods to add their "slots"/rendered Items to that).
Another way to handle this, would be to not add those decorations to an ItemStack using a Capability, but to add them using the IClientItemExtension added by #8786. That however would be a breaking change as the implementations now need a field to store the Decorations (which would be fine, since no RB is out yet).

Just for my own knowledge: Why is rendering with capabilities on itemstacks such a big problem?

@marchermans
Copy link
Contributor

Because capabilities are not designed for it and they are not supposed to be Client only. But i can ask internally if we might want to add support for it.

@Shadows-of-Fire
Copy link
Contributor

PR's for events that fire on stack rendering have historically been automatically denied, so it may only be accepted as an extension to the client item interface

@justliliandev
Copy link
Contributor Author

The ItemDecorations have been moved to the IClientItemExtension. Notable changes:
Each Item has by default it's own IClientItemExtension created by IClientItemExtension#DEFAULT_FACTORY so that each one has it's own List Instance.
This is a breaking change, since IClientItemExtension got a new non default method

@Shadows-of-Fire
Copy link
Contributor

Just make the method default and return Collections.emptyList() to make it non-breaking. Then you also don't need all these default impl classes.

@Shadows-of-Fire
Copy link
Contributor

Nevermind, I see the intention is to be able to add to other items, which would require an existing mutable list to be accessible.

@Shadows-of-Fire
Copy link
Contributor

You could, however, get around the binary break by adding two methods - one getItemDecorators that returns an immutable view, and one addItemDecorator that allows for adding a decorator.

Then getItemDecorators could default to Collections.emptyList and addItemDecorator could default to doing nothing until implementers fix their implementations.

@justliliandev
Copy link
Contributor Author

That is true, but would mean that mod authors that already implement this interface might not be aware of this change. I've also considered a throw in dev scenario, but that would only throw if someone tries to add a a decorator in dev which might not happen. Logging the default impl with warning might be an option, but also has the problem of only being fixed if someone reports it to the mod author, which is hard to do as there is no context to which item a decorator was tried to be added.

@diesieben07
Copy link
Contributor

The List should probably not live in IClientItemExtensions, but rather another client-only data structure for the items, so that mods using IClientItemExtensions do not have to care about it.

@XFactHD
Copy link
Contributor

XFactHD commented Jul 11, 2022

diesieben sniped me a little here:
I don't think putting the "burden" for such a feature on everyone implementing IClientItemExtension is a good idea. Every implementation would either be exactly the same or completely broken because the modder thinks "I don't need this feature -> return unmodifiable empty list".

@justliliandev
Copy link
Contributor Author

They could extend ClientItemExtensionImpl and override the methods they want similar to how I did it with the CustomArmorModelTest. A seperate client only object stored in Item would increase the patch size and maintenance cost of such a feature as well as duplicate a bit of the code already used by IClientItemExtension and potentially hinders discoverability of this feature.
If another client-only data structure is wanted, I would be open for name suggestions.

@XFactHD
Copy link
Contributor

XFactHD commented Jul 11, 2022

That would still make it a breaking change because you would need to enforce the use of ClientItemExtensionImpl by changing the generic type in the consumer in Item#initializeClient() and also technically still put the burden on the modder.

@justliliandev
Copy link
Contributor Author

It's a breaking change, but there was not Recommended Build yet and with this interface being kinda new I doubt many people will be effected by this break. The generic change in initializeClient is not necessary, and anyone can create their own implementation of IClientItemExtension and provide the list themselves.

@XFactHD
Copy link
Contributor

XFactHD commented Jul 11, 2022

The IClientItemExtension interface is not new, it was just renamed from IItemRenderProperties

@justliliandev
Copy link
Contributor Author

justliliandev commented Jul 12, 2022

Performance tests:

How I acquired the data

  • All measures where taken over 10000 frames
  • The IItemDecoration used for this is the StackSizeDurabilityBar from the TestMod or an implementation that does nothing for the "without rendering happening" column
  • Map implementation used is the Object2ObjectFastOpenHashMap from fastutil
  • Jei measurements where taken with default maxsize of 9x16 items
  • Jei measurements where taken over GuiEventHandler#onDrawBackgroundPost from this Update to support the breaking changes in forge mezz/JustEnoughItems#2886 PR by pupnewster
  • Creative screen measurements where taken with all 5 CreativeRows filled and the hotbar filled (so 54 itemstacks being catched by the measurement)
  • Creative screen measurements where taken over the AbstractContainerScreen#render call without JEI
  • Time measurements are obtained using System#nanoTime and averaged before rounding to ms with three decimal places
  • All the data was obtained with a i5-7500 and Geforce GTX 1060 with a few (but the same programs running)

Time Measurements

JEI

decoration system no decorations 1 decoration 50 decorations 50 decorations without rendering happening
no DecorationSystem 3.007 ~ ~ ~
field in item 3.157 5.688 102.672 3.331
map 3.208 5.701 103.608 3.382

Creative Menu

decoration system no decorations 1 decoration 50 decorations 50 decorations without rendering happening
no DecorationSystem 1.819 ~ ~ ~
field in item 1.840 2.791 47.148 1.860
map 1.843 2.845 46.866 1.886

My Conclusion

Performance is not a big problem, if not too many decorators are used. Most of the code execution time is coming from rendering and not the overhead of this feature, hence modders should be careful what they do with this feature, but providing this feature is not too big of a problem.
Using a Map is surprisingly fast, even though the direct field is usually faster. Patchwise I would say that the added field in Item is not too big of a problem, as a similar patch in the exact same place is already present and the performance benefits might when mods add a lot of items.

Further actions

I'm going to fix the things mentioned by diesieben and add javadocs where necessary.

With the data provided, I await a decision regarding Map or field in Item

@Rover656 Rover656 mentioned this pull request Jul 13, 2022
10 tasks
@justliliandev justliliandev changed the title Added ItemDecorator Capability Added ItemDecorator Map Jul 14, 2022
@Rover656 Rover656 mentioned this pull request Jul 26, 2022
3 tasks
@sciwhiz12 sciwhiz12 added Assigned This request has been assigned to a core developer. Will not go stale. Needs Rebase This PR requires a rebase to implement upstream changes (usually to fix merge conflicts). and removed Needs Update This request requires an update from the author to confirm whether the request is relevant. Work In Progress This request has lots of changes that need attention. labels Jul 30, 2022
@sciwhiz12 sciwhiz12 removed the Needs Rebase This PR requires a rebase to implement upstream changes (usually to fix merge conflicts). label Aug 10, 2022
@gigaherz gigaherz merged commit 7a6843f into MinecraftForge:1.19.x Aug 17, 2022
marchermans pushed a commit to marchermans/MinecraftForge that referenced this pull request Aug 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.19 Assigned This request has been assigned to a core developer. Will not go stale. Feature This request implements a new feature. Rendering This request deals with rendering. These must be treated with care, and tend to progress slowly.

Projects

None yet

Development

Successfully merging this pull request may close these issues.