Skip to content

Commit 24a41fc

Browse files
committed
feat: add STF to replay/validate game
- remove sounds - downloads ticks after a game is over
1 parent 91f59f4 commit 24a41fc

14 files changed

+23824
-64
lines changed

client/game/gameMode.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export class GameMode extends EventSource implements IGameState {
2020
}
2121

2222
init() {
23-
Sound.on();
2423
this.world.addShip(WIDTH/2, HEIGHT/2);
2524
this.world.startLevel();
2625
this.thumper = new Thumper();

client/game/rocks.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Screen, OBJECT_SCALE } from './screen';
1+
import { Screen, OBJECT_SCALE, WIDTH, HEIGHT } from './screen';
22
import { Object2D } from './object2d';
33
import { Vector } from './vector';
44
import { random, randomFloat } from './util';
@@ -124,9 +124,9 @@ export class Rock extends Object2D {
124124
break;
125125
}
126126

127-
const rate = randomFloat(.7, 1);
128-
sound.rate(rate);
129-
sound.play();
127+
// const rate = randomFloat(.7, 1);
128+
// sound.rate(rate);
129+
// sound.play();
130130

131131
if (this.size > RockSize.Small) {
132132

@@ -182,20 +182,20 @@ export function createRocks(level: number): Rock[] {
182182

183183
switch (zone) {
184184
case 1:
185-
x = random(offset, screen.width - offset);
185+
x = random(offset, WIDTH - offset);
186186
y = random(offset, offset * 2);
187187
break;
188188
case 2:
189-
x = random(screen.width - (offset * 2), screen.width - offset);
190-
y = random(screen.height - offset, screen.height - offset);
189+
x = random(WIDTH - (offset * 2), WIDTH - offset);
190+
y = random(HEIGHT - offset, HEIGHT - offset);
191191
break;
192192
case 3:
193-
x = random(offset, screen.width - offset);
194-
y = random(screen.height - offset, screen.height - offset);
193+
x = random(offset, WIDTH - offset);
194+
y = random(HEIGHT - offset, HEIGHT - offset);
195195
break;
196196
default:
197197
x = random(offset, offset * 2);
198-
y = random(screen.height - offset, screen.height - offset);
198+
y = random(HEIGHT - offset, HEIGHT - offset);
199199
break;
200200
}
201201

client/game/ship.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,13 @@ export class Ship extends Object2D {
147147
this.flame.velocity = this.velocity;
148148
}
149149

150-
thrust.play();
150+
// thrust.play();
151151
}
152152

153153
private fire() {
154154
if (this.bulletTimer <= 0 && this.bulletCount < MAX_BULLETS) {
155155

156-
fire.play();
156+
// fire.play();
157157

158158
this.bulletTimer = BULLET_TIME;
159159
this.bulletCount++;

client/game/thump.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ export class Thumper {
3434

3535
if (this.thumpBeatTimer >= this.thumpBeat) {
3636
if (this.lo) {
37-
thumpLo.play();
37+
// thumpLo.play();
3838
} else {
39-
thumpHi.play();
39+
// thumpHi.play();
4040
}
4141

4242
this.lo = !this.lo;

client/game/tickRecorder.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,14 @@ export class TickRecorder {
4747

4848
public sendTicks() {
4949
console.log(`Found about ${this.ticks.length} ticks to send`);
50+
const data = JSON.stringify(this.ticks, null, 2);
51+
const blob = new Blob([data], { type: 'application/json' });
52+
const url = URL.createObjectURL(blob);
53+
const a = document.createElement('a');
54+
a.href = url;
55+
a.download = 'ticks.json';
56+
a.click();
57+
URL.revokeObjectURL(url);
58+
console.log('Ticks successfully saved to disk.');
5059
}
5160
}

client/game/world.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ export class World {
214214

215215
shipDestroyed() {
216216
if (this.ship) {
217-
largeExplosion.play();
217+
// largeExplosion.play();
218218
this.createExplosion(this.ship);
219219
this.addFlash(5);
220220
this.ship.destroy();
@@ -288,19 +288,19 @@ export class World {
288288
this.alien = new BigAlien();
289289
}
290290

291-
alienSound.play();
291+
// alienSound.play();
292292

293293
this.alien.on('expired', () => {
294-
alienFire.stop();
295-
alienSound.stop();
296-
largeExplosion.play();
294+
// alienFire.stop();
295+
// alienSound.stop();
296+
// largeExplosion.play();
297297
this.alien = null;
298298
this.alienBullets.forEach(b => b.destroy());
299299
this.alienBullets.length = 0;
300300
});
301301

302302
this.alien.on('fire', (alien, bullet: Bullet) => {
303-
alienFire.play();
303+
// alienFire.play();
304304

305305
bullet.on('expired', () => {
306306
this.alienBullets = this.alienBullets.filter(x => x !== bullet);
@@ -322,14 +322,14 @@ export class World {
322322
if (this.extraLifeScore >= EXTRA_LIFE) {
323323
this.lives++;
324324
this.extraLifeScore -= EXTRA_LIFE;
325-
extraLife.play();
325+
// extraLife.play();
326326
}
327327

328328
this.addScenery(new ScoreMarker(obj, `${obj.score}`));
329329
}
330330

331331
addPowerup() {
332-
getPowerup.play();
332+
// getPowerup.play();
333333
}
334334

335335
shake() {

rollup/.env.example

Lines changed: 0 additions & 6 deletions
This file was deleted.
File renamed without changes.

rollup/index.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { ActionSchema, AllowedInputTypes, MicroRollup } from "@stackr/sdk";
22
import { HDNodeWallet, Wallet } from "ethers";
33
import { stackrConfig } from "./stackr.config";
4-
import { TickActionSchema } from "./stackr/action";
4+
import { ValidateGameSchema } from "./stackr/action";
55
import { machine } from "./stackr/machine";
6+
import { ValidateGameInput } from "./stackr/transitions";
67

78
const wallet = Wallet.createRandom();
89

@@ -22,25 +23,42 @@ const signMessage = async (
2223
const main = async () => {
2324
const mru = await MicroRollup({
2425
config: stackrConfig,
25-
actionSchemas: [TickActionSchema],
26+
actionSchemas: [ValidateGameSchema],
2627
stateMachines: [machine],
2728
});
2829

2930
await mru.init();
3031

31-
// const inputs = {
32-
// timestamp: Date.now(),
33-
// };
32+
const filePath = './ticks2.json';
33+
const fs = require('fs').promises;
3434

35-
// const signature = await signMessage(wallet, TickActionSchema, inputs);
36-
// const incrementAction = TickActionSchema.actionFrom({
37-
// inputs,
38-
// signature,
39-
// msgSender: wallet.address,
40-
// });
35+
let jsonData;
4136

42-
// const ack = await mru.submitAction("increment", incrementAction);
43-
// console.log(ack);
37+
try {
38+
const data = await fs.readFile(filePath, 'utf8');
39+
jsonData = JSON.parse(data);
40+
} catch (error) {
41+
console.error('Error reading or parsing the file:', error);
42+
return null;
43+
}
44+
45+
console.log("Found", jsonData.length, "ticks")
46+
47+
const inputs = {
48+
gameId: 1,
49+
timestamp: 1,
50+
inputs: jsonData,
51+
};
52+
53+
const signature = await signMessage(wallet, ValidateGameSchema, inputs);
54+
const incrementAction = ValidateGameSchema.actionFrom({
55+
inputs,
56+
signature,
57+
msgSender: wallet.address,
58+
});
59+
60+
const ack = await mru.submitAction("validateGame", incrementAction);
61+
console.log(ack);
4462
};
4563

4664
main();

rollup/stackr/action.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { ActionSchema, SolidityType } from "@stackr/sdk";
22

3-
export const TickActionSchema = new ActionSchema("tick", {
3+
export const ValidateGameSchema = new ActionSchema("validateGame", {
44
gameId: SolidityType.UINT,
55
timestamp: SolidityType.UINT, // nonce
66
// Keypresses mapped to action inputs
7-
wasHyperspace: SolidityType.BOOL,
8-
isRotateLeft: SolidityType.BOOL,
9-
wasRotateLeft: SolidityType.BOOL,
10-
isRotateRight: SolidityType.BOOL,
11-
wasRotateRight: SolidityType.BOOL,
12-
isThrust: SolidityType.BOOL,
13-
isFire: SolidityType.BOOL,
7+
inputs: [
8+
{wasHyperspace: SolidityType.BOOL},
9+
{isRotateLeft: SolidityType.BOOL},
10+
{wasRotateLeft: SolidityType.BOOL},
11+
{isRotateRight: SolidityType.BOOL},
12+
{wasRotateRight: SolidityType.BOOL},
13+
{isThrust: SolidityType.BOOL},
14+
{isFire: SolidityType.BOOL},
15+
],
1416
});

rollup/stackr/machine.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
11
import { State, StateMachine } from "@stackr/sdk/machine";
22
import { solidityPackedKeccak256 } from "ethers";
3+
import {World} from "../../client/game/world"
34

45
import { transitions } from "./transitions";
56
import genesisState from "../genesis-state.json";
67

7-
interface World {
8-
time: number;
9-
x: number;
10-
y: number;
11-
}
12-
138
export class WorldState extends State<World> {
149
constructor(state: World) {
1510
super(state);
1611
}
1712

1813
getRootHash() {
1914
return solidityPackedKeccak256(
20-
["uint", "uint", "uint"],
21-
[this.state.time, this.state.x, this.state.y]
15+
["string"],
16+
["test"]
2217
);
2318
}
2419
}
2520

2621
const machine = new StateMachine({
2722
id: "worldEngine",
2823
stateClass: WorldState,
29-
initialState: genesisState.state,
24+
initialState: new World(0),
3025
on: transitions,
3126
});
3227

rollup/stackr/transitions.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
import { STF, Transitions } from "@stackr/sdk/machine";
22
import { WorldState } from "./machine";
3+
import {GameMode} from "../../client/game/gameMode";
4+
import {World} from "../../client/game/world";
35

4-
const tick: STF<WorldState> = {
6+
7+
export type ValidateGameInput = {
8+
gameId: number,
9+
timestamp: number, // nonce
10+
// Keypresses mapped to action inputs
11+
inputs: [
12+
{wasHyperspace: boolean},
13+
{isRotateLeft: boolean},
14+
{wasRotateLeft: boolean},
15+
{isRotateRight: boolean},
16+
{wasRotateRight: boolean},
17+
{isThrust: boolean},
18+
{isFire: boolean},
19+
],
20+
};
21+
22+
const validateGame: STF<WorldState, ValidateGameInput> = {
523
handler: ({ state, inputs }) => {
6-
state.time = inputs.timestamp;
7-
state.x = inputs.x;
8-
state.y = inputs.y;
24+
let world = new World(0);
25+
let gameMode = new GameMode(world);
26+
for (const input of inputs.inputs) {
27+
gameMode.update(1/60, input);
28+
}
29+
console.log("New score: ", world.score)
930
return state;
1031
},
1132
};
1233

1334
export const transitions: Transitions<WorldState> = {
14-
tick,
35+
validateGame,
1536
};

0 commit comments

Comments
 (0)