fix(tutorial): gift_receive reward_list carries post-state totals, not deltas
The client's PlayerStaticData.UpdateHaveUserGoodsNumByJsonData does direct assignment on each reward_list entry's reward_num, so currency/item totals must be the new viewer balance — not the gift delta. Fresh accounts were seeing their cached crystal/rupy balances clobbered down to the gift counts until the next /load/index. Matches the project_wire_reward_list_post_state memory and the prod capture (which shows 120 rupy = baseline 20 + gift 100).
This commit is contained in:
@@ -154,19 +154,47 @@ public class GiftController : SVSimController
|
|||||||
.Select(p => Clone(p, nowString))
|
.Select(p => Clone(p, nowString))
|
||||||
.ToList(),
|
.ToList(),
|
||||||
IsUnreceivedPresent = false,
|
IsUnreceivedPresent = false,
|
||||||
|
// reward_list entries must carry POST-STATE TOTALS, not gift deltas.
|
||||||
|
// The client's PlayerStaticData.UpdateHaveUserGoodsNumByJsonData does direct
|
||||||
|
// assignment on each entry's reward_num — emitting the delta would clobber
|
||||||
|
// the client-side cached balance down to the gift amount until the next /load/index.
|
||||||
|
// See project memory: project_wire_reward_list_post_state.
|
||||||
RewardList = TutorialGifts
|
RewardList = TutorialGifts
|
||||||
.Where(p => requestedIds.Contains(p.PresentId))
|
.Where(p => requestedIds.Contains(p.PresentId))
|
||||||
.Select(p => new GiftRewardListEntry
|
.Select(p => new GiftRewardListEntry
|
||||||
{
|
{
|
||||||
RewardType = p.RewardType,
|
RewardType = p.RewardType,
|
||||||
RewardId = p.RewardDetailId,
|
RewardId = p.RewardDetailId,
|
||||||
RewardNum = p.RewardCount,
|
RewardNum = ResolvePostStateRewardNum(p, viewer),
|
||||||
})
|
})
|
||||||
.ToList(),
|
.ToList(),
|
||||||
TutorialStep = 41,
|
TutorialStep = 41,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the post-grant viewer balance for the given gift entry, not the gift delta.
|
||||||
|
/// reward_list on wire carries post-state totals (client does direct assignment).
|
||||||
|
/// </summary>
|
||||||
|
private static string ResolvePostStateRewardNum(PresentDto gift, SVSim.Database.Models.Viewer viewer)
|
||||||
|
{
|
||||||
|
switch (gift.RewardType)
|
||||||
|
{
|
||||||
|
case "1": // Crystal
|
||||||
|
return ((long)viewer.Currency.Crystals).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
case "9": // Rupy
|
||||||
|
return ((long)viewer.Currency.Rupees).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
case "4": // Item
|
||||||
|
{
|
||||||
|
int itemId = int.Parse(gift.RewardDetailId, System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
var owned = viewer.Items.FirstOrDefault(i => i.Item.Id == itemId);
|
||||||
|
return ((long)(owned?.Count ?? 0)).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return gift.RewardCount; // unknown type — fall back to gift count (better than 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static UserGoodsType WireRewardTypeToUserGoodsType(int wireType) => wireType switch
|
private static UserGoodsType WireRewardTypeToUserGoodsType(int wireType) => wireType switch
|
||||||
{
|
{
|
||||||
1 => UserGoodsType.Crystal,
|
1 => UserGoodsType.Crystal,
|
||||||
|
|||||||
@@ -81,6 +81,17 @@ public class GiftControllerTests
|
|||||||
var post = await factory.GetViewerCurrencyAsync(viewerId);
|
var post = await factory.GetViewerCurrencyAsync(viewerId);
|
||||||
Assert.That(post.Crystals - pre.Crystals, Is.EqualTo(400UL));
|
Assert.That(post.Crystals - pre.Crystals, Is.EqualTo(400UL));
|
||||||
Assert.That(post.Rupees - pre.Rupees, Is.EqualTo(100UL));
|
Assert.That(post.Rupees - pre.Rupees, Is.EqualTo(100UL));
|
||||||
|
|
||||||
|
// reward_list carries post-state TOTALS, not deltas, per project_wire_reward_list_post_state.
|
||||||
|
// After claiming gifts, the crystal/rupy entries in reward_list should equal viewer's post-grant totals.
|
||||||
|
var rewardList = root.GetProperty("reward_list").EnumerateArray().ToList();
|
||||||
|
var crystalEntry = rewardList.First(e => e.GetProperty("reward_type").GetString() == "1");
|
||||||
|
var rupyEntry = rewardList.First(e => e.GetProperty("reward_type").GetString() == "9");
|
||||||
|
Assert.That(crystalEntry.GetProperty("reward_num").GetString(),
|
||||||
|
Is.EqualTo(post.Crystals.ToString()),
|
||||||
|
"reward_list currency entries must carry POST-STATE TOTALS, not gift deltas (client does direct assignment).");
|
||||||
|
Assert.That(rupyEntry.GetProperty("reward_num").GetString(),
|
||||||
|
Is.EqualTo(post.Rupees.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
Reference in New Issue
Block a user