fix(server): allow golden thread mail grants
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user