Skip to content

26.2refactor#138

Merged
tr7zw merged 3 commits into
mainfrom
26.2refactor
Jun 21, 2026
Merged

26.2refactor#138
tr7zw merged 3 commits into
mainfrom
26.2refactor

Conversation

@tr7zw

@tr7zw tr7zw commented Jun 21, 2026

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR refactors the cape rendering pipeline by introducing a dev.tr7zw.waveycapes.render package. A new CapeInfos record replaces MultiBufferSource-based getVertexConsumer with a getCapeInfo contract. CapeNodeCollector is reimplemented with mod-selection and glint-pass logic. FeatureRenderDispatcherMixin is removed. All mod support integrations are updated. The project is bumped to version 26.2-fabric.

Changes

Cape Rendering Pipeline Refactor

Layer / File(s) Summary
New CapeInfos record and CapeRenderer API
src/main/java/dev/tr7zw/waveycapes/render/CapeInfos.java, src/main/java/dev/tr7zw/waveycapes/render/CapeRenderer.java
Introduces CapeInfos public record (CapeRenderer, RenderType, isGlint). Updates CapeRenderer interface: removes getVertexConsumer(MultiBufferSource, PlayerWrapper), adds abstract getCapeInfo(PlayerWrapper) returning CapeInfos; moves interface to render package.
New render package: CapeNodeCollector, CustomCapeRenderer, VanillaCapeRenderer
src/main/java/dev/tr7zw/waveycapes/render/CapeNodeCollector.java, src/main/java/dev/tr7zw/waveycapes/render/CustomCapeRenderer.java, src/main/java/dev/tr7zw/waveycapes/render/VanillaCapeRenderer.java
Adds CapeNodeCollector with submitCape (mod scan, glint pass, main geometry pass via getCapeRenderer). Refactors CustomCapeRenderer.render to accept pre-selected CapeRenderer and VertexConsumer; removes internal getCapeRenderer and vanillaCape field. Adds VanillaCapeRenderer using translucent render type.
ModSupport, EarsSupport, MinecraftCapesSupport adaptations
src/main/java/dev/tr7zw/waveycapes/support/ModSupport.java, src/main/java/dev/tr7zw/waveycapes/support/EarsSupport.java, src/main/java/dev/tr7zw/waveycapes/support/MinecraftCapesSupport.java
Updates ModSupport to import CapeRenderer from render package. Rewrites EarsRenderer.getVertexConsumergetCapeInfo returning CapeInfos with armorCutoutNoCull. Rewrites MinecraftCapesRenderer.getVertexConsumergetCapeInfo with entityTranslucent and glint state.
Wiring: CustomCapeRenderLayer, WaveyCapesBase, mixin removal
src/main/java/dev/tr7zw/waveycapes/renderlayers/CustomCapeRenderLayer.java, src/main/java/dev/tr7zw/waveycapes/WaveyCapesBase.java, src/main/java/dev/tr7zw/waveycapes/mixin/FeatureRenderDispatcherMixin.java, src/main/resources/waveycapes.mixins.json
Updates CustomCapeRenderLayer.submit to route through the new CapeNodeCollector.submitCape signature. Removes FeatureRenderDispatcherMixin (deleted file + removed from mixin JSON). Cleans up version-condition wrappers in WaveyCapesBase.
Stonecutter template comment reformatting
replacements.gradle, src/main/java/dev/tr7zw/waveycapes/mixin/PlayerRendererMixin.java, src/main/java/dev/tr7zw/waveycapes/mixin/PlayerMixin.java, src/main/java/dev/tr7zw/waveycapes/delegate/PlayerDelegate.java, src/main/java/dev/tr7zw/waveycapes/mixin/LivingEntityRendererMixin.java, src/test/java/dev/tr7zw/tests/MixinTests.java
Adds a stonecutter rule to replace RenderType. with RenderTypes. for MC >= 1.21.11. Reformats block-comment boundaries in version-gated inactive code across mixin and delegate files — no active logic changes.
Version bump and config screen update
gradle-compose.yml, modern.json, versions/mainProject, src/main/java/dev/tr7zw/waveycapes/WaveyCapesConfigScreen.java
Bumps waveycapes dependency to 1.10.0, adds 26.2-fabric to version list, bumps mainProject to 26.2-fabric. Updates config screen to use GeneralUtil.setScreen(previous).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tr7zw/WaveyCapes#113: Directly related — this PR removes and rewires the same CapeNodeCollector, CapeRenderer, and VanillaCapeRenderer building blocks that #113 originally introduced under dev.tr7zw.waveycapes, replacing them with the new render.* abstraction.
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title '26.2refactor' is vague and does not clearly convey the main changes; it lacks descriptive terms about what refactoring work was performed. Consider using a more descriptive title such as 'Refactor cape rendering pipeline to support modular renderer selection' or similar that clarifies the primary objective.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess whether the description relates to the changeset. Add a description explaining the refactoring objectives, architectural changes, and impact on the cape rendering system.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 26.2refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/dev/tr7zw/waveycapes/support/EarsSupport.java (1)

80-98: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent entity access between shouldBeUsed and getCapeInfo.

In shouldBeUsed (line 44), the entity UUID is obtained via capeRenderInfo.getAvatar() for version >= 1.21.9, but here getCapeInfo unconditionally uses capeRenderInfo.getEntity().getUUID(). If getAvatar() and getEntity() return different objects with different UUIDs, the EarsFeatures lookup will be inconsistent between the two methods.

🐛 Suggested fix: apply the same version-conditional pattern
 `@Override`
 public CapeInfos getCapeInfo(PlayerWrapper capeRenderInfo) {
-    EarsFeatures playerFeatures = EarsFeatures.getById(capeRenderInfo.getEntity().getUUID());
+    //? if >= 1.21.9 {
+    var entity = capeRenderInfo.getAvatar();
+    //? } else {
+    /*var entity = capeRenderInfo.getEntity();
+    *///? }
+    EarsFeatures playerFeatures = EarsFeatures.getById(entity.getUUID());

     if (playerFeatures != null && playerFeatures.capeEnabled) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/tr7zw/waveycapes/support/EarsSupport.java` around lines 80
- 98, The getCapeInfo method has an inconsistency with the shouldBeUsed method
in how it obtains the entity UUID for EarsFeatures lookup. Currently,
getCapeInfo unconditionally uses capeRenderInfo.getEntity().getUUID() to fetch
player features, but shouldBeUsed uses capeRenderInfo.getAvatar() for version
1.21.9 or later. Apply the same version-conditional pattern in the getCapeInfo
method where you call EarsFeatures.getById() so that it uses getAvatar() for
version >= 1.21.9 and getEntity() for earlier versions, matching the logic in
shouldBeUsed to ensure consistent entity UUID lookups across both methods.
🧹 Nitpick comments (1)
src/main/java/dev/tr7zw/waveycapes/render/CapeRenderer.java (1)

17-17: ⚡ Quick win

Make the nullable getCapeInfo contract explicit.

getCapeInfo(...) is treated as nullable by callers and implementations, but the interface doesn’t state that. Please document this directly in the API to avoid misuse by future renderers/callers.

Proposed contract clarification
 public interface CapeRenderer {
@@
-    CapeInfos getCapeInfo(PlayerWrapper capeRenderInfo);
+    /**
+     * `@return` cape render info, or null when this renderer should not render for the given player.
+     */
+    CapeInfos getCapeInfo(PlayerWrapper capeRenderInfo);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/tr7zw/waveycapes/render/CapeRenderer.java` at line 17, The
getCapeInfo method signature does not explicitly document that it can return
null, even though callers and implementations treat it as nullable. Add a
nullable annotation (such as `@Nullable` from the appropriate null-safety library
being used in the project) to the return type of the getCapeInfo method to make
the nullable contract explicit in the API and prevent potential misuse by future
implementations or callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/dev/tr7zw/waveycapes/render/CapeNodeCollector.java`:
- Around line 39-56: The code is using the preselected `renderer` parameter when
calling `customCapeRenderer.render()`, but it should use the renderer from
`capeInfo.capeRenderer()` instead. This mismatch causes the geometry and UV
behavior to desynchronize from the chosen render type and glint path. Replace
all occurrences of `renderer` with `capeInfo.capeRenderer()` in both the glint
rendering submission (within the `if (capeInfo.isGlint())` block) and the
regular cape rendering submission to ensure consistency between the render type
applied and the actual renderer used.

---

Outside diff comments:
In `@src/main/java/dev/tr7zw/waveycapes/support/EarsSupport.java`:
- Around line 80-98: The getCapeInfo method has an inconsistency with the
shouldBeUsed method in how it obtains the entity UUID for EarsFeatures lookup.
Currently, getCapeInfo unconditionally uses capeRenderInfo.getEntity().getUUID()
to fetch player features, but shouldBeUsed uses capeRenderInfo.getAvatar() for
version 1.21.9 or later. Apply the same version-conditional pattern in the
getCapeInfo method where you call EarsFeatures.getById() so that it uses
getAvatar() for version >= 1.21.9 and getEntity() for earlier versions, matching
the logic in shouldBeUsed to ensure consistent entity UUID lookups across both
methods.

---

Nitpick comments:
In `@src/main/java/dev/tr7zw/waveycapes/render/CapeRenderer.java`:
- Line 17: The getCapeInfo method signature does not explicitly document that it
can return null, even though callers and implementations treat it as nullable.
Add a nullable annotation (such as `@Nullable` from the appropriate null-safety
library being used in the project) to the return type of the getCapeInfo method
to make the nullable contract explicit in the API and prevent potential misuse
by future implementations or callers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fe96ab50-7a60-4a0b-b48e-53726a2df878

📥 Commits

Reviewing files that changed from the base of the PR and between dce2c45 and 559356e.

📒 Files selected for processing (24)
  • gradle-compose.yml
  • modern.json
  • replacements.gradle
  • src/main/java/dev/tr7zw/waveycapes/CapeNodeCollector.java
  • src/main/java/dev/tr7zw/waveycapes/VanillaCapeRenderer.java
  • src/main/java/dev/tr7zw/waveycapes/WaveyCapesBase.java
  • src/main/java/dev/tr7zw/waveycapes/WaveyCapesConfigScreen.java
  • src/main/java/dev/tr7zw/waveycapes/delegate/PlayerDelegate.java
  • src/main/java/dev/tr7zw/waveycapes/mixin/FeatureRenderDispatcherMixin.java
  • src/main/java/dev/tr7zw/waveycapes/mixin/LivingEntityRendererMixin.java
  • src/main/java/dev/tr7zw/waveycapes/mixin/PlayerMixin.java
  • src/main/java/dev/tr7zw/waveycapes/mixin/PlayerRendererMixin.java
  • src/main/java/dev/tr7zw/waveycapes/render/CapeInfos.java
  • src/main/java/dev/tr7zw/waveycapes/render/CapeNodeCollector.java
  • src/main/java/dev/tr7zw/waveycapes/render/CapeRenderer.java
  • src/main/java/dev/tr7zw/waveycapes/render/CustomCapeRenderer.java
  • src/main/java/dev/tr7zw/waveycapes/render/VanillaCapeRenderer.java
  • src/main/java/dev/tr7zw/waveycapes/renderlayers/CustomCapeRenderLayer.java
  • src/main/java/dev/tr7zw/waveycapes/support/EarsSupport.java
  • src/main/java/dev/tr7zw/waveycapes/support/MinecraftCapesSupport.java
  • src/main/java/dev/tr7zw/waveycapes/support/ModSupport.java
  • src/main/resources/waveycapes.mixins.json
  • src/test/java/dev/tr7zw/tests/MixinTests.java
  • versions/mainProject
💤 Files with no reviewable changes (4)
  • src/main/java/dev/tr7zw/waveycapes/mixin/FeatureRenderDispatcherMixin.java
  • src/main/java/dev/tr7zw/waveycapes/CapeNodeCollector.java
  • src/main/resources/waveycapes.mixins.json
  • src/main/java/dev/tr7zw/waveycapes/VanillaCapeRenderer.java

Comment on lines +39 to +56
var capeInfo = renderer.getCapeInfo(playerWrapper);
if (capeInfo == null) {
return;
}
//? if >= 1.21.9 {
if (capeInfo.isGlint()) {
submitNodeCollector.submitCustomGeometry(stack, RenderTypes.entityGlint(), (pose, vertexConsumer) -> {
PoseStack sharedStack = new PoseStack();
sharedStack.last().set(pose);
customCapeRenderer.render(playerWrapper, renderer, vertexConsumer, sharedStack, packedLight, delta);
});
}

submitNodeCollector.submitCustomGeometry(stack, capeInfo.renderType(), (pose, vertexConsumer) -> {
PoseStack sharedStack = new PoseStack();
sharedStack.last().set(pose);
customCapeRenderer.render(playerWrapper, renderer, vertexConsumer, sharedStack, packedLight, delta);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use capeInfo.capeRenderer() for rendering, not the preselected renderer.

submitCape(...) applies capeInfo.renderType() but still calls customCapeRenderer.render(...) with the earlier renderer. If CapeInfos carries a different renderer, geometry/UV behavior can desync from the chosen render type/glint path.

Proposed fix
         var capeInfo = renderer.getCapeInfo(playerWrapper);
         if (capeInfo == null) {
             return;
         }
+        var activeRenderer = capeInfo.capeRenderer() != null ? capeInfo.capeRenderer() : renderer;
@@
         if (capeInfo.isGlint()) {
             submitNodeCollector.submitCustomGeometry(stack, RenderTypes.entityGlint(), (pose, vertexConsumer) -> {
                 PoseStack sharedStack = new PoseStack();
                 sharedStack.last().set(pose);
-                customCapeRenderer.render(playerWrapper, renderer, vertexConsumer, sharedStack, packedLight, delta);
+                customCapeRenderer.render(playerWrapper, activeRenderer, vertexConsumer, sharedStack, packedLight, delta);
             });
         }
@@
         submitNodeCollector.submitCustomGeometry(stack, capeInfo.renderType(), (pose, vertexConsumer) -> {
             PoseStack sharedStack = new PoseStack();
             sharedStack.last().set(pose);
-            customCapeRenderer.render(playerWrapper, renderer, vertexConsumer, sharedStack, packedLight, delta);
+            customCapeRenderer.render(playerWrapper, activeRenderer, vertexConsumer, sharedStack, packedLight, delta);
         });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/tr7zw/waveycapes/render/CapeNodeCollector.java` around
lines 39 - 56, The code is using the preselected `renderer` parameter when
calling `customCapeRenderer.render()`, but it should use the renderer from
`capeInfo.capeRenderer()` instead. This mismatch causes the geometry and UV
behavior to desynchronize from the chosen render type and glint path. Replace
all occurrences of `renderer` with `capeInfo.capeRenderer()` in both the glint
rendering submission (within the `if (capeInfo.isGlint())` block) and the
regular cape rendering submission to ensure consistency between the render type
applied and the actual renderer used.

@tr7zw tr7zw merged commit 1cef6aa into main Jun 21, 2026
5 checks passed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant