-
Notifications
You must be signed in to change notification settings - Fork 427
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 Support for Custom ColorResolvers #3503
Add Support for Custom ColorResolvers #3503
Conversation
...endering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/ClientWorldMixin.java
Outdated
Show resolved
Hide resolved
Personally I feel like forcing providers to be registered to a registry might be a better option, even if you keep the underlying map population lazy, like it is right now. Otherwise, it's too easy for a mod to silently leak huge amounts of memory by injecting many lambda instances. |
I'm also of the opinion that requiring up-front registration is ultimately for the better here, for the reason stated, and another: Sodium (code) will fetch all biomes and colors for an entire Y-slice of a chunk section when first accessed, and then blend the entire array of colors at once. This allows us to avoid sampling/blending hundreds of biomes every single time we need to fetch the color for a single block vertex, and is one of the reason why Sodium's chunk meshing is often 10+ times faster than Vanilla's. This works fine when there's only a few ColorResolvers, since more likely than not, a chunk is going to have dozens of blocks using a given ColorResolver, and the overhead of sampling more upfront is quickly amortized. But if mods are allowed to register many ColorResolvers which blocks only sparsely use, this begins to create massive overhead on our side (CPU time + Memory), and will greatly slow down chunk meshing. So I prefer any solution where mods are kind of "discouraged" from using ColorResolvers so liberally (especially in the form of inline lambdas) because it will help to avoid exploding things on our side. Also worth mentioning: There are other mods (such as Better Biome Blend) which I believe have the same overhead problem, so this isn't a Sodium-specific thing. |
The |
...endering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/ClientWorldMixin.java
Outdated
Show resolved
Hide resolved
...endering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/ClientWorldMixin.java
Outdated
Show resolved
Hide resolved
...endering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/ClientWorldMixin.java
Outdated
Show resolved
Hide resolved
* Add support for custom color resolvers * Add ColorResolverRegistry * Fix checkstyle * Statically initialize all BiomeColorCaches (cherry picked from commit 6fd945a)
Preliminary Information and The Problem
ColorResolver
is a vanilla functional interface that gets a color using a biome and some positional information. Vanilla has three suchColorResolver
s, namely for grass, foliage, and water, which can be found in theBiomeColors
class.BlockRenderView#getColor(BlockPos, ColorResolver)
is the main way to use aColorResolver
; the default implementation of this method already supports customColorResolver
s, but it is overridden inClientWorld
. This implementation hard-codes the three vanillaColorResolver
s into an array map and invoking it with a customColorResolver
will throw aNullPointerException
and crash the game.BlockView API v2 already provides a standardized method to retrieve the biome at a given position which can be used within
BlockColorProvider
s. However,ClientWorld#getColor(BlockPos, ColorResolver)
also provides color blending and caching; using the biome getter to recreate the functionality of aColorResolver
would either be very inefficient or very complex. Allowing the use of customColorResolver
s would be much easier for the user.API Design
There are two main design options for allowing custom resolvers. Either a registry is added for custom resolvers or the
ClientWorld
implementation is silently patched to accept custom resolvers. The former makes it explicitly known that custom resolvers are supported and makes it very difficult to passColorResolver
objects that are only used once (such as through a capturing lambda; such resolvers are terrible for performance) while the latter is easier to use. This pull request uses the former design of using a registry and throwing an exception inClientWorld#getColor(BlockPos, ColorResolver)
if the passedColorResolver
is not registered.Implementation
ClientWorld
associates eachColorResolver
to aBiomeColorCache
in the hard-coded array map. The custom resolvers are not added to this map because array maps have slower retrieval times than hash maps, especially with many entries. The field type of this map isObject2ObjectArrayMap
, so it is not possible to replace the field value with a hash map. Instead, customColorResolver
s are added to a separateReference2ReferenceOpenHashMap
, which is populated once at construction time with all registered customColorResolver
s. AModifyExpressionValue
was used to change the null cache value so that the localBiomeColorCache
variable would be populated with the correct value, in case other mods use it in their own mixins.Test Mod
The test mod was changed to add a simple block that is rendered as a solid white cube, with the top face tinted using a
BlockColorProvider
and customColorResolver
. The resolver returns a magenta color in biomes with precipitation and a yellow color in biomes without. With maximum biome blending, the following effect is created.