Repository navigation
feat(player-shop): prices in items and account coins - #1191
Conversation
Deploying openmudocs with
|
| Latest commit: |
4cd5b42
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1d3aace5.openmudocs.pages.dev |
| Branch Preview URL: | https://claude-openmu-1186-shop-curr.openmudocs.pages.dev |
Players can define the price of each item of their personal store in zen, in configured items (by default the Jewels of Bless, Soul, Chaos, Creation and Life) or in the account coins WCoin C/P and Goblin Points. Closes #1186. - Item.StorePriceItemDefinition (reference to the price item) and Item.StorePriceCoinType, both null for zen prices, with migration, compiled models and generated loader code. - PlayerShopCurrenciesFeaturePlugIn (disabled by default) with the list of price items, one flag per account coin and maximum amounts. A new database gets the five jewels as price items. While the plugin is off, the protocol and the behavior stay as before. - ShopPrice describes a price; ShopPrices decides which prices are allowed, names them and parses them in chat commands. - One payment exchange per price kind: zen as before; items move as whole items (singles and jewel mix bundles, exact amount, no change) within the trade context which also moves the sold item; coins are taken from the buyer's account and saved right away, with a rollback when the save fails. - Set price, open store and buy re-validate the price server-side. The original client only sees zen items and can't buy others. - Extended client: the 3F 09 set price handler and the extended item list share one price encoding (MoneyPrice, PriceItemType, RequiredItemAmount); 3F 0A lists the allowed price types on world entry and before a shop list. - /shopprice chat command (disabled by default) for every client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7XufeAZ22z7ocXAXUqUsE
cab3e6f to
4d14134
Compare
|
I tested this feature and found some issues:
1.1 Zero-amount price sells items for free (DB-tamper reachable)
return item.StorePrice is { } amount
? new ShopPrice(amount, item.StorePriceItemDefinition, item.StorePriceCoinType)
: null;
1.2 Bundle levels are honored without any bound
Our branch implements exactly this ( 1.3 Subset-sum array is sized by the price, not by the tendervar reachedBy = new int[price + 1];
1.4 Packet handler throws on hostile input (log flood)
|
- Captions and descriptions for the settings of the plugin, so that the admin panel shows "Is WCoin (C) Allowed" instead of words split at the wrong places. - A stored price of 0 or less counts as no price, so such an item can't be bought for nothing; the buy and the store opening check it. - Bundles with a higher level than the jewel mix creates (10, 20 or 30 pieces) don't count as payment, because they couldn't be unstacked into their pieces. - A truncated set price request is ignored with a warning instead of throwing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7XufeAZ22z7ocXAXUqUsE
|
Thanks for testing and for the review, @eduardosmaniotto! Addressed in ca9f1f2:
Tests: Generated by Claude Code |
Master added the migrations AddGensRewardClaim and AddCrywolfEvent. The migration of the store prices is generated again on top of them (20261014104431_AddItemStorePriceCurrency, same Up and Down as before), and so are the snapshot and the compiled models of the EntityDataContext, AccountContext and TradeContext. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7XufeAZ22z7ocXAXUqUsE
- Rename PlayerShopCurrenciesFeaturePlugIn.GetConfiguration to GetActiveConfiguration, which can't be confused with its Configuration property (S4059). - Walk back the subset-sum selection with a while loop instead of a for loop which changes its counter in the body (S127). - Leave out the heading of the docs page, which the title of the front matter already gives (MD025), and quote the new sidebar entry as the linter wants it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7XufeAZ22z7ocXAXUqUsE

Closes #1186.
Players can price each item of their personal store in:
The feature is disabled by default. While it's off, the protocol and the behavior are unchanged: no new packets are sent and only zen prices are possible.
Design
Item.StorePriceItemDefinitionis a reference to the price item'sItemDefinition, following the model rule of references instead of ids.Item.StorePriceCoinType(CashShopCoinType?) holds a coin price.20261014104431_AddItemStorePriceCurrency: two nullable columns and a foreign key toconfig.ItemDefinition), which was regenerated on top of master's latest migrations. It also includes regenerated compiled models (Entity/Account/Trade contexts), the regeneratedGameConfigurationLoaderand the generated EF and basic models.PlayerShopCurrenciesFeaturePlugIn(IFeaturePlugIn,IDisabledByDefault) with its own config class:PriceItems: a list ofItemDefinition, editable in the admin panel;MaximumItemAmount, capped at 65535 because the amount travels in a 16-bit field;MaximumCoinAmount.DataInitializationBaselike the existing Bless jewel plugin. On an existing database, the plugin configuration is created at startup without game data, so its price items list starts empty. Since the plugin is opt-in, the admin adds items when activating it; the docs say so.ShopPrice/ShopPrices:ShopPriceis the price value: amount, price item or coin type.ShopPricesdecides which prices are allowed, gives the localized currency name (item name or coin) and parses chat commands.PlayerShopPriceEncodingin the GameServer turns a price into the protocol fields and back. The item list, the3F 09handler and the3F 0Aprice types message all use it.IShopCurrencyExchangeper kind. Each returns aShopPaymentResultenum instead of a bool:(level + 1) * 10. Only tradable, option-free items count, and singles must be level 0. A small subset-sum picks a combination that matches the price exactly: bundles are never split and there is no change. The items are moved buyer → seller inside the sameTradeContextsave as the sold item.PlayerPersistenceinvariant).StoreLock;IShowShopCurrenciesPlugIn) is refused for non-zen items;3F 0Alists the allowed price types on world entry and before a shop list, only while the feature is on.LackOfPriceCurrencyand a localized blue message with the real amount./shopprice [position 1-32|slot 204-235] [amount] [currency], disabled by default. The currency iszen, a jewel alias (bless,soul, …),group/number(e.g.14/42) or a coin alias (wcc,wcp,gp). Without arguments it lists the store's prices.docs-website/docs/server-features/player-shop-currencies.md.Testing
dotnet teston the branch merged with current master, all passing:MUnique.OpenMU.Tests: 1819 passed, includingCompiledModelTestsandGameConfigurationLoaderGeneratorTest.MUnique.OpenMU.Persistence.Initialization.Tests: 629 passed, 7 skipped.MUnique.OpenMU.Web.Tests: 242 passed.PlayerShopCurrenciesTest:PlayerShopCurrenciesRemoteViewTests: the price-types message bytes, an encode/decode round trip (including an unknown item and an amount that overflowsint), and the extended list encoding with a disallowed item hidden.PlayerShopCurrenciesDataTest: a new database has the plugin deactivated, with references to the five jewels.🤖 Generated with Claude Code
https://claude.ai/code/session_01Y7XufeAZ22z7ocXAXUqUsE