fix(client): restore retail interaction parity
Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
This commit is contained in:
parent
0c699240e0
commit
f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions
|
|
@ -473,6 +473,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
}
|
||||
|
||||
float opacity = PackedPartOpacity(
|
||||
entity.ServerGuid,
|
||||
entity.LocalEntityId,
|
||||
(uint)setupPartIndex);
|
||||
if (opacity < 1f)
|
||||
|
|
@ -527,6 +528,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
// one-part assumption and kept the Bind Stone's four
|
||||
// hook-hidden shard parts visible.
|
||||
float opacity = PackedPartOpacity(
|
||||
entity.ServerGuid,
|
||||
entity.LocalEntityId,
|
||||
(uint)partIndex);
|
||||
if (opacity < 1f)
|
||||
|
|
@ -585,20 +587,24 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
anyVao != 0 && alphaQueueCollecting;
|
||||
|
||||
private float PackedPartOpacity(
|
||||
uint serverGuid,
|
||||
uint localEntityId,
|
||||
uint setupPartIndex)
|
||||
{
|
||||
float opacity = EntityOpacity(serverGuid);
|
||||
if (opacity <= 0f)
|
||||
return 0f;
|
||||
if (!_translucencyFades.TryGetCurrentValue(
|
||||
localEntityId,
|
||||
setupPartIndex,
|
||||
out float translucency))
|
||||
{
|
||||
return 1f;
|
||||
return opacity;
|
||||
}
|
||||
|
||||
return translucency >= 1f
|
||||
? 0f
|
||||
: 1f - translucency;
|
||||
: opacity * (1f - translucency);
|
||||
}
|
||||
|
||||
private bool ClassifyPackedBatches(
|
||||
|
|
|
|||
|
|
@ -176,7 +176,8 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
RetailAlphaQueue? alphaQueue = null,
|
||||
long? alphaScratchBudgetBytes = null,
|
||||
TerrainAtlas.RetailDetailTextureBinding buildingDetail = default,
|
||||
Func<bool>? buildingDetailEnabled = null)
|
||||
Func<bool>? buildingDetailEnabled = null,
|
||||
Func<uint, float>? hierarchicalTranslucency = null)
|
||||
{
|
||||
_device = device ?? throw new ArgumentNullException(nameof(device));
|
||||
_frames = frames ?? throw new ArgumentNullException(nameof(frames));
|
||||
|
|
@ -192,6 +193,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
_selectionSink = selectionSink;
|
||||
_selectionLighting = selectionSink as IRetailSelectionLightingSource;
|
||||
_alphaQueue = alphaQueue;
|
||||
_hierarchicalTranslucency = hierarchicalTranslucency;
|
||||
_alphaSource = new AlphaDrawSource(this);
|
||||
_buildingDetail = buildingDetail;
|
||||
_buildingDetailEnabled = buildingDetailEnabled ?? DisableDetailTextures;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
private readonly IRetailSelectionRenderSink? _selectionSink;
|
||||
private readonly IRetailSelectionLightingSource? _selectionLighting;
|
||||
private readonly RetailAlphaQueue? _alphaQueue;
|
||||
private readonly Func<uint, float>? _hierarchicalTranslucency;
|
||||
private readonly AlphaDrawSource _alphaSource;
|
||||
private readonly RetainedScratchCapacityPolicy _alphaScratchPolicy;
|
||||
private int _scratchPeakUnits;
|
||||
|
|
@ -1784,11 +1785,12 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
// sets draw_state|=1 and skips the whole part outright — not a
|
||||
// blend to nothing. TranslucencyFadeManager.AdvanceAll guarantees
|
||||
// t=1 commits the bitwise-exact value so this check is safe.
|
||||
float opacityMultiplier = 1.0f;
|
||||
float opacityMultiplier = EntityOpacity(entity.ServerGuid);
|
||||
if (opacityMultiplier <= 0f) continue;
|
||||
if (_translucencyFades.TryGetCurrentValue(entity.Id, (uint)setupPartIndex, out float translucencyValue))
|
||||
{
|
||||
if (translucencyValue >= 1.0f) continue; // skip this part's draw entirely
|
||||
opacityMultiplier = 1f - translucencyValue; // CMaterial::SetTranslucencySimple 0x005396f0
|
||||
opacityMultiplier *= 1f - translucencyValue; // CMaterial::SetTranslucencySimple 0x005396f0
|
||||
}
|
||||
|
||||
if (!ClassifyBatches(partData, model, entity, meshRef, paletteIdentity, restPose, opacityMultiplier, collector, entityHasCutoutSubset))
|
||||
|
|
@ -1818,12 +1820,14 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
// entity — the Bind Stone's idle cycle hides its four authored
|
||||
// shard parts (3-6) with TransparentPartHook start=end=1.0
|
||||
// every loop, and they stayed visible.
|
||||
float opacityMultiplier = 1.0f;
|
||||
float opacityMultiplier = EntityOpacity(entity.ServerGuid);
|
||||
bool fullyInvisible = false;
|
||||
if (opacityMultiplier <= 0f)
|
||||
fullyInvisible = true;
|
||||
if (_translucencyFades.TryGetCurrentValue(entity.Id, (uint)partIdx, out float translucencyValue))
|
||||
{
|
||||
if (translucencyValue >= 1.0f) fullyInvisible = true;
|
||||
else opacityMultiplier = 1f - translucencyValue;
|
||||
else opacityMultiplier *= 1f - translucencyValue;
|
||||
}
|
||||
|
||||
if (!fullyInvisible)
|
||||
|
|
@ -1901,6 +1905,32 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
observeCurrentPath: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Readiness barrier for a private creature viewport. Unlike the world
|
||||
/// reveal queue this has no retained scan state: the caller owns a tiny,
|
||||
/// exact entity list and retries it each frame. A completed result means
|
||||
/// both mesh render data and every palette/original-texture composite can
|
||||
/// be classified without clearing the private target to an empty frame.
|
||||
/// </summary>
|
||||
internal bool PreparePrivateEntityResources(
|
||||
IReadOnlyList<WorldEntity> entities)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entities);
|
||||
bool complete = true;
|
||||
for (int i = 0; i < entities.Count; i++)
|
||||
{
|
||||
if (PrepareCompositeEntity(entities[i]) != CompositeWarmupResult.Complete)
|
||||
complete = false;
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
private float EntityOpacity(uint serverGuid)
|
||||
{
|
||||
float translucency = _hierarchicalTranslucency?.Invoke(serverGuid) ?? 0f;
|
||||
return 1f - Math.Clamp(translucency, 0f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether there is a mesh source to draw from. The encoder arm has no
|
||||
/// vertex array of its own — the pipeline owns one shaped by
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue