feat(entitlement): pivot to paid app ownership
Check Steam ownership of the paid app with BIsSubscribedApp; keep Debug fake ownership out of Release. Ref: https://partner.steamgames.com/doc/api/ISteamApps#BIsSubscribedApp
This commit is contained in:
+22
-25
@@ -53,8 +53,8 @@ on the partner dashboard — the dashboard's Downloads page only re-offers the S
|
||||
| SDK zip (sign in to partner first) | `partner.steamgames.com/downloads/steamworks_sdk.zip` |
|
||||
| Docs home | `partner.steamgames.com/doc/home` |
|
||||
| SteamPipe upload (steamcmd + VDF fields) | `partner.steamgames.com/doc/sdk/uploading` |
|
||||
| DLC configuration | `partner.steamgames.com/doc/store/application/dlc` |
|
||||
| `BIsDlcInstalled` | `partner.steamgames.com/doc/api/ISteamApps` |
|
||||
| Demo configuration | `partner.steamgames.com/doc/store/application/demos` |
|
||||
| Paid app ownership (`BIsSubscribedApp`) | `partner.steamgames.com/doc/api/ISteamApps#BIsSubscribedApp` |
|
||||
| Store artwork sizes | `partner.steamgames.com/doc/store/assets/standard` |
|
||||
| Coming Soon / 2-week public window | `partner.steamgames.com/doc/store/coming_soon` |
|
||||
| Wallet rule (in-app purchases) | `partner.steamgames.com/doc/features/microtransactions` |
|
||||
@@ -64,17 +64,17 @@ on the partner dashboard — the dashboard's Downloads page only re-offers the S
|
||||
|
||||
1. **Steamworks account** → onboarding (NDA, identity, company details, tax interview, payout bank,
|
||||
then the **$100 Steam Direct fee** per app). The store page cannot be configured before the fee.
|
||||
2. **App IDs.** One **base app** (free) and one **DLC app** (the lifetime Pro). Note both numbers:
|
||||
the DLC app ID is what the app passes to `BIsDlcInstalled`.
|
||||
3. **Depot.** One depot holding the publish output; the base app and the DLC share the install
|
||||
directory, and the DLC package grants no files of its own — it is entitlement only.
|
||||
2. **App IDs.** One paid app and its associated free Demo. The Demo has its own App ID; it checks
|
||||
ownership of the paid app with `BIsSubscribedApp(paidAppId)`.
|
||||
3. **Builds.** Keep one codebase. Steam gives the Demo a separate release checklist/build setup;
|
||||
shared depots can avoid duplicating common files once the paid app is released.
|
||||
4. **Steamworks SDK.** `./scripts/steam-sdk.sh ~/Downloads/steamworks_sdk_165.zip` extracts
|
||||
`steam_api64.dll` from `sdk/redistributable_bin/win64/` into `steam/` (gitignored) and stages
|
||||
`steam_appid.txt` = 480 — Valve's Spacewar app, so `SteamAPI.Init()` works locally before
|
||||
LlamaCasty has an App ID. Add `--contentbuilder` on the machine that uploads a depot. The csproj
|
||||
copies the DLL **beside the exe** (`Link`) with `ExcludeFromSingleFile`, and copies
|
||||
`steam_appid.txt` in Debug only — never into a depot. The managed side is the `Steamworks.NET`
|
||||
package (`SteamApps.BIsDlcInstalled`).
|
||||
package (`SteamApps.BIsSubscribedApp`).
|
||||
5. **Store page** configured and made public **two weeks before release** — Valve's rule, and it is
|
||||
the window where wishlists accumulate.
|
||||
|
||||
@@ -89,31 +89,28 @@ publish → steam-stage → steamcmd + app_build.vdf → build upload → set li
|
||||
2. **Set the build live** in Steamworks → *Builds* → the new build → **Set Build Live** on the
|
||||
default branch. That *is* the release; there is no artifact to hash and no manifest to submit.
|
||||
3. **Announce** with Steam Events (release notes appear in the library and on the store page).
|
||||
4. **Verify**: install from a clean Steam account, confirm `BIsDlcInstalled` returns false, buy the
|
||||
DLC (or use a test licence), confirm the high tiers unlock, then refund the test purchase.
|
||||
4. **Verify**: install the Demo from a clean Steam account, confirm paid-app ownership is false,
|
||||
then test with an account that owns the paid app and confirm the higher tiers unlock.
|
||||
|
||||
**Updates** are the same upload with a higher build ID. The app keeps **no self-updater and no
|
||||
version banner** — Steam is the update path, and that policy has not changed.
|
||||
|
||||
## 4. Entitlement wiring
|
||||
|
||||
- `IEntitlement` (`Services/Entitlement/`) has one method, `IsPro`. **Steam DLC** answers it today
|
||||
(`SteamEntitlement`, `Steamworks.NET` + `steam_api64.dll`); the **Polar** monthly rail plugs in
|
||||
beside it. Resolution is `Pro = steamDlc || polarLease`, then `MainViewModel.HasProOutput` adds
|
||||
the Debug-only `DeveloperMode`; anything unresolved is the free profile.
|
||||
- **`SteamEntitlement.NotConfigured()` is the shipping default** until the DLC app id exists — it
|
||||
answers false without touching the native library. Set the id when Steamworks creates the DLC.
|
||||
- `IEntitlement` reports `IsAppOwned`. Debug uses a fake owned result; Release checks the paid app
|
||||
ID through `BIsSubscribedApp`. `MainViewModel.IsAppOwned` is the app-wide binary ownership flag.
|
||||
- The paid app ID is not yet configured. Until it is assigned, the Release path fails closed without
|
||||
touching the native library.
|
||||
- **Fail closed on every path:** no id, no client, missing DLL, thrown load, not owned.
|
||||
- **Never sell the monthly inside the Steam build.** Steamworks requires in-app purchases to use
|
||||
the Steam Wallet; the app may *state* that monthly plans exist on the site, with no checkout,
|
||||
no price and no payment field. Confirm the wording with Steamworks support before shipping it.
|
||||
- The EULA should expressly allow commercial/monetized streaming use; confirm with counsel or Valve
|
||||
that this satisfies the Steam Subscriber Agreement's software terms.
|
||||
- **Never gate a feature.** The only delta is the output profile.
|
||||
|
||||
## 5. Release checklist
|
||||
|
||||
- Build clean, 0 warnings (`./scripts/verify.sh`), tests green.
|
||||
- `steam_api64.dll` present; app starts **without** Steam and falls back to the free profile.
|
||||
- DLC ownership false → free profile; true → every tier offered.
|
||||
- Paid-app ownership false → free profile; true → higher output tiers offered.
|
||||
- `LlamaCasty.exe` rename landed (never rename a live exe).
|
||||
- Clean Steam install on a second machine, then an update pushed and observed.
|
||||
- Store page public for the full two weeks; support contact and announcements configured.
|
||||
@@ -123,15 +120,15 @@ version banner** — Steam is the update path, and that policy has not changed.
|
||||
|
||||
- **`LICENSE`** (EULA) forbids redistribution, resale, reverse-engineering and circumvention, and
|
||||
disclaims warranty.
|
||||
- **`PRIVACY.md`** must name any third party the app contacts — Google/YouTube today, **Polar** the
|
||||
day licence validation ships. Steam itself is named by Valve's own policy, not ours.
|
||||
- **`PRIVACY.md`** must name any third party the app contacts — Google/YouTube. Steam itself is
|
||||
named by Valve's own policy, not ours.
|
||||
- **`THIRD-PARTY-NOTICES.txt`** stays shipped and shown in About; the ffmpeg pin stays
|
||||
`lgpl-shared`; no GPL component may be linked (see `product.md` → "Licensing").
|
||||
- **DMCA**: a takedown needs only the notice — host, link, good-faith statement, signature.
|
||||
Statutory damages need a registration ($65). Worth doing once there is something to pirate.
|
||||
- **What actually protects the product** is in `commercial.md` → "Anti-piracy posture": a free tier
|
||||
good enough that a crack buys nothing, Steam's own delivery, short Polar leases, and a licence ID
|
||||
in About. **Not obfuscation, not a native DLL, not hardware locking.**
|
||||
- **What actually protects the product** is in `commercial.md` → "Anti-piracy posture": a useful
|
||||
free tier, Steam's own delivery, and Steam ownership of the paid app. **Not obfuscation, not a
|
||||
native DLL, not hardware locking.**
|
||||
|
||||
## 7. Effort, once
|
||||
|
||||
@@ -141,4 +138,4 @@ version banner** — Steam is the update path, and that policy has not changed.
|
||||
| Publish profile + `steam_api64.dll` + `IEntitlement` Steam path | 1 day |
|
||||
| Depot + first `steamcmd` upload | 0.5 day, then ~15 min per release |
|
||||
| Store page + assets (screenshots, capsule art) | 1–2 days |
|
||||
| Clean-account install + DLC purchase/refund test | 0.5 day |
|
||||
| Clean-account Demo install + paid-app ownership test | 0.5 day |
|
||||
|
||||
Reference in New Issue
Block a user