diff --git a/src/client/render/gl/passes/name-pass/index.ts b/src/client/render/gl/passes/name-pass/index.ts index f6201a7319..fd71e3e668 100644 --- a/src/client/render/gl/passes/name-pass/index.ts +++ b/src/client/render/gl/passes/name-pass/index.ts @@ -667,10 +667,21 @@ export class NamePass { d[off + 30] = slot.allianceFraction; d[off + 31] = slot.allianceRemainingTicks; - // Column 8: crownLayerIdx (crown cosmetic), verified badge, rest free + // Column 8: crownLayerIdx (crown cosmetic), verified badge, statusIconCount, free d[off + 32] = slot.crownLayerIdx; d[off + 33] = slot.static.verified === true ? 1.0 : 0.0; - d[off + 34] = 0.0; + // Count of active status-row icons so shaders don't recompute it independently. + d[off + 34] = [ + slot.crown, + slot.traitor, + slot.disconnected, + slot.alliance, + slot.allianceReq, + slot.target, + slot.embargo, + slot.nukeActive, + slot.inDoomsdayClock || slot.doomsdayClockDraining, + ].filter(Boolean).length; d[off + 35] = 0.0; this.playerDataDirty = true; diff --git a/src/client/render/gl/shaders/name/icon.vert.glsl b/src/client/render/gl/shaders/name/icon.vert.glsl index f2a24c5f33..7c6f2db276 100644 --- a/src/client/render/gl/shaders/name/icon.vert.glsl +++ b/src/client/render/gl/shaders/name/icon.vert.glsl @@ -125,12 +125,20 @@ void main() { float atlasW = uEmojiAtlasW; float atlasH = uEmojiAtlasH; - float emojiWorldSize = uFontBase * nameWorldScale * 1.0; + float emojiWorldSize = uFontBase * nameWorldScale * 1.1; - iconOrigin = vec2( - wx - emojiWorldSize * 0.5, - wy - uFontBase * nameWorldScale * uEmojiRowOffset - ); + // Read precomputed active status icon count from pd8.z (set by CPU, avoids + // duplicating flag logic here and in status-icon.vert.glsl). + vec4 pd8 = texelFetch(uPlayerData, ivec2(8, playerIdx), 0); + int totalStatusActive = int(pd8.z); + + // Place emoji as rightmost slot in the combined group, or centered if alone. + float gap = emojiWorldSize * 0.15; + int totalItems = totalStatusActive + 1; + float totalWidth = float(totalItems) * emojiWorldSize + float(totalItems - 1) * gap; + float emojiX = wx - totalWidth * 0.5 + float(totalStatusActive) * (emojiWorldSize + gap); + + iconOrigin = vec2(emojiX, wy - uFontBase * nameWorldScale * uEmojiRowOffset); iconW = emojiWorldSize; iconH = emojiWorldSize; diff --git a/src/client/render/gl/shaders/name/status-icon.vert.glsl b/src/client/render/gl/shaders/name/status-icon.vert.glsl index a9f0d5a1f9..8d9d1a76df 100644 --- a/src/client/render/gl/shaders/name/status-icon.vert.glsl +++ b/src/client/render/gl/shaders/name/status-icon.vert.glsl @@ -105,8 +105,8 @@ void main() { // A crown cosmetic skins the first-place crown (slot 0). vCrownLayer = (iconSlot == 0 && pd8.x >= 0.0) ? int(pd8.x) : -1; - // Early out: dead player OR emoji is active - if (pd1.w <= 0.0 || pd4.y >= 0.0) { + // Early out: dead player only (emoji no longer hides status icons) + if (pd1.w <= 0.0) { gl_Position = vec4(0.0); vUV = vec2(0.0); vLocalUV = vec2(0.0); @@ -182,20 +182,22 @@ void main() { iconX = wx + pd3.w * nameWorldScale + iconWorldSize * 0.12; iconY = wy - iconWorldSize * 0.4; } else { - // Count active icons and position of this one (left-to-right) - int totalActive = 0; - for (int i = 0; i < 9; i++) { - if (statusFlag[i] > 0.5) totalActive++; - } + // Count active status icons and position of this one (left-to-right). + // If an emoji is also active it occupies one extra slot on the right, + // so include it in the total for centering purposes. + // totalActive is precomputed by the CPU into pd8.z — single source of truth. + int totalActive = int(pd8.z); + bool hasEmoji = (pd4.y >= 0.0); + int totalItems = totalActive + (hasEmoji ? 1 : 0); int myIndex = countBelow(iconSlot); - // Horizontal centering: spread icons evenly above the name + // Horizontal centering: treat status icons + emoji as one group. float gap = iconWorldSize * 0.15; - float totalWidth = float(totalActive) * iconWorldSize + float(totalActive - 1) * gap; + float totalWidth = float(totalItems) * iconWorldSize + float(totalItems - 1) * gap; float startX = wx - totalWidth * 0.5; iconX = startX + float(myIndex) * (iconWorldSize + gap); - // Position: row above the emoji row + // Position: same row as the emoji iconY = wy - uFontBase * nameWorldScale * uStatusRowOffset; }