fix(server): allow golden thread mail grants

This commit is contained in:
2026-10-03 00:10:05 +08:00
parent ba388f8a74
commit 1251ab900f
5 changed files with 37 additions and 19 deletions
+1
View File
@@ -46,6 +46,7 @@ var currencyRewardTypes = map[uint64]bool{
3: true, // free jewelry
4: true, // gold
12: true, // catalyst / talent elixir
20: true, // mileage / golden thread
}
// MailDBInfo is the persisted shape used by the client. A mail either has a
+27 -16
View File
@@ -160,17 +160,17 @@ func TestMailOpenGrantsNonResourceItemDBInfoType(t *testing.T) {
}
}
func TestMailOpenGrantsCatalystCurrencyAndPersists(t *testing.T) {
func TestMailOpenGrantsCatalystAndMileageCurrenciesAndPersists(t *testing.T) {
seed := &Starter{Version: "2.35.10", MailCount: 2, MaxMailID: 14, Mails: []MailDBInfo{{
MailID: 14, MailType: 2, ExpiresAt: 100, SentAt: 10,
RewardTypes: []uint64{12}, RewardIDs: []uint64{0}, RewardCounts: []uint64{250},
RewardTypes: []uint64{12, 20}, RewardIDs: []uint64{0, 0}, RewardCounts: []uint64{250, 300},
}}}
storage := stateio.NewMemory()
inv, err := player.OpenInventory(storage, &player.Starter{Version: "2.35.10"})
if err != nil {
t.Fatal(err)
}
wallet, err := player.OpenWallet(storage, player.Currency{Catalyst: 10})
wallet, err := player.OpenWallet(storage, player.Currency{Catalyst: 10, Mileage: 20})
if err != nil {
t.Fatal(err)
}
@@ -184,35 +184,46 @@ func TestMailOpenGrantsCatalystCurrencyAndPersists(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if wallet.Snapshot().Catalyst != 260 || len(inv.All()) != 0 {
if wallet.Snapshot().Catalyst != 260 || wallet.Snapshot().Mileage != 320 || len(inv.All()) != 0 {
t.Fatalf("wallet=%+v items=%+v", wallet.Snapshot(), inv.All())
}
bundle, found, _ := wire.Bytes(response, 1)
if !found {
t.Fatal("reward bundle missing")
}
item, found, _ := wire.Bytes(bundle, 1)
if !found {
t.Fatal("currency ItemDBInfo missing")
gotCurrencies := map[uint64]uint64{}
if err := wire.Walk(bundle, func(field wire.Field) error {
if field.Number != 1 {
return nil
}
typ, _, err := wire.Varint(field.Value, 3)
if err != nil {
return err
}
count, _, err := wire.Varint(field.Value, 4)
if err != nil {
return err
}
gotCurrencies[typ] = count
return nil
}); err != nil {
t.Fatal(err)
}
if typ, _, _ := wire.Varint(item, 3); typ != 12 {
t.Fatalf("currency type=%d", typ)
}
if count, _, _ := wire.Varint(item, 4); count != 250 {
t.Fatalf("currency count=%d", count)
if gotCurrencies[12] != 250 || gotCurrencies[20] != 300 {
t.Fatalf("currency rewards=%v", gotCurrencies)
}
if _, _, _, err := service.Handle("/MailOpen", request); err != nil {
t.Fatal(err)
}
if wallet.Snapshot().Catalyst != 260 {
t.Fatalf("replay catalyst=%d", wallet.Snapshot().Catalyst)
if wallet.Snapshot().Catalyst != 260 || wallet.Snapshot().Mileage != 320 {
t.Fatalf("replay wallet=%+v", wallet.Snapshot())
}
reopened, err := player.OpenWallet(storage, player.Currency{})
if err != nil {
t.Fatal(err)
}
if reopened.Snapshot().Catalyst != 260 {
t.Fatalf("persisted catalyst=%d", reopened.Snapshot().Catalyst)
if reopened.Snapshot().Catalyst != 260 || reopened.Snapshot().Mileage != 320 {
t.Fatalf("persisted wallet=%+v", reopened.Snapshot())
}
}
+5
View File
@@ -328,6 +328,11 @@ func (s *Wallet) GrantQuestOnce(identity string, rewards []gamedata.Reward) (Cur
return Currency{}, errors.New("player: catalyst overflow")
}
next.Catalyst += reward.Count
case 20:
if math.MaxUint64-next.Mileage < reward.Count {
return Currency{}, errors.New("player: mileage overflow")
}
next.Mileage += reward.Count
}
}
next.Granted[identity] = true
+1 -1
View File
@@ -54,7 +54,7 @@ ITEM_SOURCES = (
# and mail-claim path are implemented by this server are offered. Their mail
# reward ID is zero; names still come from the current GameData rather than
# being embedded here.
MAIL_CURRENCY_TYPES = frozenset({3, 4, 12})
MAIL_CURRENCY_TYPES = frozenset({3, 4, 12, 20})
def _varint(value: Any) -> int:
+3 -2
View File
@@ -196,17 +196,18 @@ class DevelopmentMailGrantToolTests(unittest.TestCase):
connection = sqlite3.connect(":memory:")
connection.execute("CREATE TABLE NameTextTable (id INTEGER, ProtoBuf BLOB)")
connection.execute("CREATE TABLE CurrencyTable (id INTEGER, ProtoBuf BLOB)")
for text_id, value in ((264, "天赋神药"), (999, "未支持货币")):
for text_id, value in ((264, "天赋神药"), (681, "金线"), (999, "未支持货币")):
encoded = value.encode("utf-8")
connection.execute(
"INSERT INTO NameTextTable VALUES (?, ?)",
(text_id, proto_field(2, text_id) + import_seed.encode_field(4, 2, encoded)),
)
connection.execute("INSERT INTO CurrencyTable VALUES (?, ?)", (12, proto_field(3, 12) + proto_field(5, 264)))
connection.execute("INSERT INTO CurrencyTable VALUES (?, ?)", (20, proto_field(3, 20) + proto_field(5, 681)))
connection.execute("INSERT INTO CurrencyTable VALUES (?, ?)", (99, proto_field(3, 99) + proto_field(5, 999)))
currencies = dev_mail_grant._mail_currencies(connection)
self.assertEqual([(item["element_type"], item["id"], item["name"]) for item in currencies], [(12, 0, "天赋神药")])
self.assertEqual([(item["element_type"], item["id"], item["name"]) for item in currencies], [(12, 0, "天赋神药"), (20, 0, "金线")])
connection.close()
def test_internal_lost_resource_is_not_mail_safe(self):