@mpgd/cli 0.66.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -151,6 +151,13 @@ function expression(value) {
|
|
|
151
151
|
function quoted(value) {
|
|
152
152
|
return `'${value.replaceAll("'", "''")}'`;
|
|
153
153
|
}
|
|
154
|
+
// Linux jobs pin a runner image instead of `ubuntu-latest`, as the kit's own CI does:
|
|
155
|
+
// the rolling label moves to a new Ubuntu image, with different preinstalled toolchains
|
|
156
|
+
// (for example the Go that ttsc keys its compiled plugins on), without a workflow change.
|
|
157
|
+
// The generated jobs cache only the pnpm store, which no image toolchain keys, so they
|
|
158
|
+
// need no image-keyed cache; a game that adds one should put the image in its key.
|
|
159
|
+
const LINUX_RUNNER = 'ubuntu-24.04';
|
|
160
|
+
const MACOS_RUNNER = 'macos-26';
|
|
154
161
|
function renderNativeDeployWorkflow(input) {
|
|
155
162
|
const options = input.targets.map((target) => ` - ${target}`);
|
|
156
163
|
const lines = [
|
|
@@ -190,7 +197,7 @@ function renderNativeDeployWorkflow(input) {
|
|
|
190
197
|
'jobs:',
|
|
191
198
|
' validate:',
|
|
192
199
|
" if: github.event_name == 'pull_request'",
|
|
193
|
-
|
|
200
|
+
` runs-on: ${LINUX_RUNNER}`,
|
|
194
201
|
' steps:',
|
|
195
202
|
' - uses: actions/checkout@v5',
|
|
196
203
|
' with:',
|
|
@@ -229,7 +236,7 @@ function renderDeployJob(input, target) {
|
|
|
229
236
|
` deploy_${target}:`,
|
|
230
237
|
` if: github.event_name == 'workflow_dispatch' && github.ref == `
|
|
231
238
|
+ `'refs/heads/${input.releaseBranch}' && inputs.target == '${target}'`,
|
|
232
|
-
` runs-on: ${target === 'android' ?
|
|
239
|
+
` runs-on: ${target === 'android' ? LINUX_RUNNER : MACOS_RUNNER}`,
|
|
233
240
|
` environment: ${quoted(input.approvalEnvironment)}`,
|
|
234
241
|
' permissions:',
|
|
235
242
|
' contents: write',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.0",
|
|
4
4
|
"description": "Gunshi CLI for mpgd-kit starter generation and target workflow orchestration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"parse5": "7.3.0",
|
|
71
71
|
"postcss": "8.5.28",
|
|
72
72
|
"postcss-value-parser": "4.2.0",
|
|
73
|
-
"@mpgd/catalog": "0.14.
|
|
73
|
+
"@mpgd/catalog": "0.14.2",
|
|
74
74
|
"@mpgd/phaser-assets": "0.9.1",
|
|
75
|
-
"@mpgd/
|
|
76
|
-
"@mpgd/
|
|
75
|
+
"@mpgd/target-config": "0.24.6",
|
|
76
|
+
"@mpgd/platform": "0.35.0"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@types/node": "^24.0.0",
|
|
@@ -81,19 +81,19 @@
|
|
|
81
81
|
"@types/yauzl": "3.4.0",
|
|
82
82
|
"ttsc": "0.34.2",
|
|
83
83
|
"typescript": "7.0.2",
|
|
84
|
-
"@mpgd/adapter-ait": "0.21.
|
|
85
|
-
"@mpgd/adapter-
|
|
86
|
-
"@mpgd/adapter-
|
|
87
|
-
"@mpgd/
|
|
88
|
-
"@mpgd/adapter-verse8": "0.7.
|
|
89
|
-
"@mpgd/
|
|
90
|
-
"@mpgd/
|
|
91
|
-
"@mpgd/
|
|
92
|
-
"@mpgd/capacitor-
|
|
93
|
-
"@mpgd/game-runtime": "0.
|
|
94
|
-
"@mpgd/game-services": "0.
|
|
95
|
-
"@mpgd/
|
|
96
|
-
"@mpgd/
|
|
84
|
+
"@mpgd/adapter-ait": "0.21.8",
|
|
85
|
+
"@mpgd/adapter-browser": "0.12.4",
|
|
86
|
+
"@mpgd/adapter-capacitor": "0.19.0",
|
|
87
|
+
"@mpgd/analytics": "0.5.8",
|
|
88
|
+
"@mpgd/adapter-verse8": "0.7.19",
|
|
89
|
+
"@mpgd/adapter-devvit": "0.14.10",
|
|
90
|
+
"@mpgd/bridge": "0.18.1",
|
|
91
|
+
"@mpgd/capacitor-storekit": "0.7.0",
|
|
92
|
+
"@mpgd/capacitor-play-billing": "0.6.1",
|
|
93
|
+
"@mpgd/game-runtime": "0.10.0",
|
|
94
|
+
"@mpgd/game-services": "0.33.0",
|
|
95
|
+
"@mpgd/i18n": "0.6.29",
|
|
96
|
+
"@mpgd/lite-shell": "0.1.0"
|
|
97
97
|
},
|
|
98
98
|
"main": "./dist/index.js",
|
|
99
99
|
"types": "./dist/index.d.ts",
|
|
@@ -14,6 +14,9 @@ export type GameMessageKey =
|
|
|
14
14
|
| 'reward'
|
|
15
15
|
| 'rewardError'
|
|
16
16
|
| 'rewardPending'
|
|
17
|
+
| 'rewardNotReady'
|
|
18
|
+
| 'rewardReconciling'
|
|
19
|
+
| 'rewardHistoryFull'
|
|
17
20
|
| 'rewardUnavailable'
|
|
18
21
|
| 'analytics'
|
|
19
22
|
| 'bootError'
|
|
@@ -59,6 +62,9 @@ const messages = {
|
|
|
59
62
|
reward: 'Rewarded ad smoke: {status}',
|
|
60
63
|
rewardError: 'Rewarded ad smoke failed',
|
|
61
64
|
rewardPending: 'Press R to request a rewarded ad smoke',
|
|
65
|
+
rewardNotReady: 'Rewarded ad smoke waits for the current purchase or ad',
|
|
66
|
+
rewardReconciling: 'Rewarded ad smoke waits until an earlier result is confirmed',
|
|
67
|
+
rewardHistoryFull: 'Rewarded ad smoke is unavailable until the game restarts',
|
|
62
68
|
rewardUnavailable: 'Rewarded ads unavailable on this target',
|
|
63
69
|
analytics: 'Analytics events: {count}',
|
|
64
70
|
bootError: 'Failed to start game',
|
|
@@ -108,6 +114,9 @@ const messages = {
|
|
|
108
114
|
reward: '리워드 광고 스모크: {status}',
|
|
109
115
|
rewardError: '리워드 광고 스모크 실패',
|
|
110
116
|
rewardPending: 'R 키로 리워드 광고 스모크 요청',
|
|
117
|
+
rewardNotReady: '진행 중인 구매나 광고가 끝나면 리워드 광고 스모크 요청 가능',
|
|
118
|
+
rewardReconciling: '이전 결과가 확인되면 리워드 광고 스모크 요청 가능',
|
|
119
|
+
rewardHistoryFull: '게임을 다시 시작할 때까지 리워드 광고 스모크를 사용할 수 없음',
|
|
111
120
|
rewardUnavailable: '이 타깃에서는 리워드 광고를 사용할 수 없음',
|
|
112
121
|
analytics: '애널리틱스 이벤트: {count}',
|
|
113
122
|
bootError: '게임 시작 실패',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GameActionController } from '@mpgd/game-runtime/actions';
|
|
1
|
+
import type { GameActionAvailability, GameActionController } from '@mpgd/game-runtime/actions';
|
|
2
2
|
import { bindPhaserGameScene } from '@mpgd/game-runtime/phaser';
|
|
3
3
|
import Phaser from 'phaser';
|
|
4
4
|
|
|
@@ -21,6 +21,8 @@ export class PlayScene extends Phaser.Scene {
|
|
|
21
21
|
private analyticsText!: Phaser.GameObjects.Text;
|
|
22
22
|
private context!: StarterContext;
|
|
23
23
|
private rewardedAction: GameActionController<'rewarded-ad'> | undefined;
|
|
24
|
+
private showingNotReady = false;
|
|
25
|
+
private requesting = false;
|
|
24
26
|
private lastScore = -1;
|
|
25
27
|
private lastAnalyticsCount = -1;
|
|
26
28
|
|
|
@@ -83,19 +85,67 @@ export class PlayScene extends Phaser.Scene {
|
|
|
83
85
|
})
|
|
84
86
|
.setOrigin(0.5);
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
const actions = this.context.gameRuntime.actions;
|
|
89
|
+
this.rewardedAction = actions?.createRewardedAdController();
|
|
87
90
|
const action = this.rewardedAction;
|
|
91
|
+
// Follow the runtime's availability, so the hint changes while any purchase
|
|
92
|
+
// (one from the shop included) or ad holds the screen, without a key press.
|
|
93
|
+
this.showingNotReady = false;
|
|
94
|
+
this.requesting = false;
|
|
95
|
+
const stopAvailability = actions?.subscribeAvailability((availability) => {
|
|
96
|
+
this.showAvailability(availability);
|
|
97
|
+
});
|
|
98
|
+
if (actions !== undefined) {
|
|
99
|
+
this.showAvailability(actions.getAvailability());
|
|
100
|
+
}
|
|
88
101
|
const keyboard = this.input.keyboard;
|
|
89
102
|
const onReward = () => {
|
|
90
103
|
void this.requestRewardedAd();
|
|
91
104
|
};
|
|
92
105
|
keyboard?.on('keydown-R', onReward);
|
|
93
106
|
this.events.once('shutdown', () => {
|
|
107
|
+
stopAvailability?.();
|
|
94
108
|
action?.dispose();
|
|
95
109
|
keyboard?.off('keydown-R', onReward);
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
private showAvailability(availability: GameActionAvailability): void {
|
|
114
|
+
// This scene's own request makes the actions busy too; its result text
|
|
115
|
+
// follows, so only someone else's purchase or ad shows the waiting text.
|
|
116
|
+
if (!this.rewardedAdsAvailable() || this.rewardedAction === undefined || availability === 'disposed'
|
|
117
|
+
|| this.requesting) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (availability === 'ready') {
|
|
121
|
+
// Restore the hint only over the waiting text, never over a result.
|
|
122
|
+
if (this.showingNotReady) {
|
|
123
|
+
this.showingNotReady = false;
|
|
124
|
+
this.rewardText.setText(this.rewardHint());
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
this.showingNotReady = true;
|
|
129
|
+
// `history-full` lasts until the runtime is recreated; only `busy` ends
|
|
130
|
+
// with the other purchase or ad.
|
|
131
|
+
this.rewardText.setText(
|
|
132
|
+
t(
|
|
133
|
+
this.context.locale,
|
|
134
|
+
availability === 'history-full'
|
|
135
|
+
? 'rewardHistoryFull'
|
|
136
|
+
: availability === 'reconciliation-required'
|
|
137
|
+
? 'rewardReconciling'
|
|
138
|
+
: 'rewardNotReady',
|
|
139
|
+
),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** A result or error replaces the waiting text for good: `ready` must not restore the hint over it. */
|
|
144
|
+
private showRewardText(text: string): void {
|
|
145
|
+
this.showingNotReady = false;
|
|
146
|
+
this.rewardText.setText(text);
|
|
147
|
+
}
|
|
148
|
+
|
|
99
149
|
override update(_time: number, delta: number): void {
|
|
100
150
|
this.state = stepStarterRunState(this.state, delta);
|
|
101
151
|
|
|
@@ -139,13 +189,15 @@ export class PlayScene extends Phaser.Scene {
|
|
|
139
189
|
const action = this.rewardedAction;
|
|
140
190
|
|
|
141
191
|
if (!this.rewardedAdsAvailable() || action === undefined) {
|
|
142
|
-
this.
|
|
192
|
+
this.showRewardText(t(this.context.locale, 'rewardUnavailable'));
|
|
143
193
|
return;
|
|
144
194
|
}
|
|
145
195
|
|
|
196
|
+
// The tap-time guard stays: availability can change before the next frame.
|
|
146
197
|
if (this.context.gameRuntime.actions?.getAvailability() !== 'ready') {
|
|
147
198
|
return;
|
|
148
199
|
}
|
|
200
|
+
this.requesting = true;
|
|
149
201
|
try {
|
|
150
202
|
const result = await action.execute({
|
|
151
203
|
placementId: rewardedPlacementId,
|
|
@@ -155,7 +207,7 @@ export class PlayScene extends Phaser.Scene {
|
|
|
155
207
|
if (action.isDisposed() || this.rewardedAction !== action) {
|
|
156
208
|
return;
|
|
157
209
|
}
|
|
158
|
-
this.
|
|
210
|
+
this.showRewardText(
|
|
159
211
|
result.claim?.granted === true
|
|
160
212
|
? t(this.context.locale, 'reward', { status: result.status })
|
|
161
213
|
: t(this.context.locale, 'rewardError'),
|
|
@@ -169,9 +221,13 @@ export class PlayScene extends Phaser.Scene {
|
|
|
169
221
|
},
|
|
170
222
|
});
|
|
171
223
|
if (!action.isDisposed() && this.rewardedAction === action) {
|
|
172
|
-
this.
|
|
224
|
+
this.showRewardText(t(this.context.locale, 'rewardError'));
|
|
173
225
|
}
|
|
174
226
|
console.error('[rewarded-ad]', error);
|
|
227
|
+
} finally {
|
|
228
|
+
if (this.rewardedAction === action) {
|
|
229
|
+
this.requesting = false;
|
|
230
|
+
}
|
|
175
231
|
}
|
|
176
232
|
}
|
|
177
233
|
}
|