Skip to content

Commit 8d601ad

Browse files
authored
Merge pull request #241 from battlecode/blockchainclient
Show blockchain in client
2 parents 604531e + 02e2b44 commit 8d601ad

File tree

7 files changed

+246
-5
lines changed

7 files changed

+246
-5
lines changed

client/playback/out/index.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as metadata from './metadata';
55
import StructOfArrays from './soa';
66
import * as soa from './soa';
77
import Match from './match';
8-
import { Log } from './match';
8+
import { Log, Block, Transaction } from './match';
99
import Game from './game';
1010
import { flatbuffers, schema } from 'battlecode-schema';
11-
export { Game, Log, Match, GameWorld, gameworld, Metadata, metadata, StructOfArrays, soa, flatbuffers, schema };
11+
export { Game, Log, Block, Transaction, Match, GameWorld, gameworld, Metadata, metadata, StructOfArrays, soa, flatbuffers, schema };

client/playback/out/match.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ export declare type Log = {
88
round: number;
99
text: string;
1010
};
11+
export declare type Transaction = {
12+
cost: number;
13+
message: Array<number>;
14+
};
15+
export declare type Block = {
16+
messages: Array<Transaction>;
17+
round: number;
18+
};
1119
/**
1220
* A timeline of a match. Allows you to see what the state of the match was,
1321
* at any particular time.
@@ -46,6 +54,10 @@ export default class Match {
4654
* The logs of this match, bucketed by round.
4755
*/
4856
readonly logs: Array<Array<Log>>;
57+
/**
58+
* The blockchain, an array of blocks per round.
59+
*/
60+
readonly blockchain: Array<Block>;
4961
/**
5062
* The current game world.
5163
* DO NOT CACHE this reference between calls to seek() and compute(), it may
@@ -93,6 +105,10 @@ export default class Match {
93105
* Store a schema.Round and the logs contained in it.
94106
*/
95107
applyDelta(delta: schema.Round): void;
108+
/**
109+
* parses blockchain broadcasts
110+
*/
111+
parseBlockchain(delta: schema.Round): void;
96112
/**
97113
* Parse logs for a round.
98114
*/

client/playback/out/match.js

+83
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Match {
3232
this.snapshots.push(this._current.copy());
3333
this.deltas = new Array(1);
3434
this.logs = new Array(1);
35+
this.blockchain = new Array(1);
3536
this.maxTurn = header.maxRounds();
3637
this._lastTurn = null;
3738
this._seekTo = 0;
@@ -76,6 +77,88 @@ class Match {
7677
if (delta.logs()) {
7778
this.parseLogs(delta.roundID(), delta.logs(battlecode_schema_1.flatbuffers.Encoding.UTF16_STRING));
7879
}
80+
this.parseBlockchain(delta);
81+
}
82+
/**
83+
* parses blockchain broadcasts
84+
*/
85+
parseBlockchain(delta) {
86+
let blockMessages = new Array();
87+
// lol the schema format for this is real weird
88+
// THIS IS THE HACKIEST SOLUTION MANKIND HAS EVER SEEN
89+
// another option is actually changing the schema, but we can't remove parts of it
90+
// so then we would need to add a new thing
91+
// which would (1) break old replays and (2) have twice as big new replays
92+
// sorry this is probably the best solution
93+
// DO NOT COPY THIS CODE FOR FUTURE USE. MODIFY!!!
94+
let j = 0;
95+
let messageStringLen = delta.broadcastedMessagesLength();
96+
for (let i = 0; i < delta.broadcastedMessagesCostsLength(); i++) {
97+
let messageCost = delta.broadcastedMessagesCosts(i);
98+
// console.log(messageCost);
99+
// let x = delta.broadcastedMessages(j, flatbuffers.Encoding.UTF16_STRING);
100+
// var offset = delta.bb!.__offset(delta.bb_pos, 42);
101+
// var h = delta.bb!.__vector(delta.bb_pos + offset)
102+
// console.log(h);
103+
// var k = delta.bb!.readInt32(h);
104+
// console.log(k);
105+
// console.log(delta.bb!.readInt32(h+4));
106+
// console.log(delta.bb!.readInt32(h+8));
107+
// console.log(delta.bb!.readInt32(h+12));
108+
// console.log(delta.bb!.readInt32(h+16));
109+
let thisTransaction = "";
110+
let offset = delta.bb.__offset(delta.bb_pos, 42);
111+
let startPointer = delta.bb.__vector(delta.bb_pos + offset);
112+
if (offset) {
113+
// this is ascii
114+
let x = String.fromCharCode(delta.bb.readInt32(startPointer + 4 * j));
115+
while (x !== ' ') {
116+
// console.log(x);
117+
// this will be
118+
thisTransaction += x;
119+
j += 1;
120+
if (j >= messageStringLen) {
121+
console.log("BLOCKCHAIN ERROR SHOULD NEVER HAPPEN");
122+
break;
123+
}
124+
x = String.fromCharCode(delta.bb.readInt32(startPointer + 4 * j));
125+
}
126+
j += 1;
127+
// now split this transaction on _
128+
let splitMessage = thisTransaction.split("_");
129+
let messageArr = new Array();
130+
for (let j = 0; j < splitMessage.length; j++) {
131+
messageArr.push(parseInt(splitMessage[j]));
132+
}
133+
blockMessages.push({
134+
cost: messageCost,
135+
message: messageArr
136+
});
137+
}
138+
else {
139+
console.log("couldn't display blockchain");
140+
}
141+
}
142+
// console.log(blockMessages);
143+
// for (let i = 0; i < delta.broadcastedMessagesCostsLength(); i++) {
144+
// let messageString = delta.broadcastedMessages(i);
145+
// let messageCost = delta.broadcastedMessagesCosts(i);
146+
// console.log(messageString);
147+
// // string is formatted as int_int_int
148+
// let splitMessage = messageString.split("_");
149+
// let messageArr = new Array<number>();
150+
// for (let j = 0; j < splitMessage.length; j++) {
151+
// messageArr.push(parseInt(splitMessage[j]));
152+
// }
153+
// blockMessages.push({
154+
// cost: messageCost,
155+
// message: messageArr
156+
// });
157+
// }
158+
this.blockchain.push({
159+
messages: blockMessages,
160+
round: delta.roundID()
161+
});
79162
}
80163
/**
81164
* Parse logs for a round.

client/playback/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import * as metadata from './metadata';
55
import StructOfArrays from './soa';
66
import * as soa from './soa';
77
import Match from './match';
8-
import {Log} from './match';
8+
import {Log,Block,Transaction} from './match';
99
import Game from './game';
1010
import { flatbuffers, schema } from 'battlecode-schema';
1111

12-
export {Game, Log, Match, GameWorld, gameworld, Metadata, metadata, StructOfArrays, soa, flatbuffers, schema};
12+
export {Game, Log, Block, Transaction, Match, GameWorld, gameworld, Metadata, metadata, StructOfArrays, soa, flatbuffers, schema};
1313

1414
// TODO provide ergonomic main export

client/playback/src/match.ts

+103
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ export type Log = {
1010
text: string
1111
};
1212

13+
export type Transaction = {
14+
cost: number,
15+
message: Array<number>
16+
}
17+
18+
export type Block = {
19+
messages: Array<Transaction>,
20+
round: number
21+
}
22+
1323
// Return a timestamp representing the _current time in ms, not necessarily from
1424
// any particular epoch.
1525
const timeMS: () => number = typeof window !== 'undefined' && window.performance && window.performance.now?
@@ -57,6 +67,11 @@ export default class Match {
5767
*/
5868
readonly logs: Array<Array<Log>>;
5969

70+
/**
71+
* The blockchain, an array of blocks per round.
72+
*/
73+
readonly blockchain: Array<Block>;
74+
6075
/**
6176
* The current game world.
6277
* DO NOT CACHE this reference between calls to seek() and compute(), it may
@@ -118,6 +133,7 @@ export default class Match {
118133
this.snapshots.push(this._current.copy());
119134
this.deltas = new Array(1);
120135
this.logs = new Array(1);
136+
this.blockchain = new Array(1);
121137
this.maxTurn = header.maxRounds();
122138
this._lastTurn = null;
123139
this._seekTo = 0;
@@ -136,6 +152,93 @@ export default class Match {
136152
if(delta.logs()){
137153
this.parseLogs(delta.roundID(), <string> delta.logs(flatbuffers.Encoding.UTF16_STRING));
138154
}
155+
this.parseBlockchain(delta);
156+
}
157+
158+
/**
159+
* parses blockchain broadcasts
160+
*/
161+
parseBlockchain(delta: schema.Round) {
162+
let blockMessages = new Array<Transaction>();
163+
164+
// lol the schema format for this is real weird
165+
// THIS IS THE HACKIEST SOLUTION MANKIND HAS EVER SEEN
166+
// another option is actually changing the schema, but we can't remove parts of it
167+
// so then we would need to add a new thing
168+
// which would (1) break old replays and (2) have twice as big new replays
169+
// sorry this is probably the best solution
170+
// DO NOT COPY THIS CODE FOR FUTURE USE. MODIFY!!!
171+
172+
let j = 0;
173+
let messageStringLen = delta.broadcastedMessagesLength();
174+
for (let i = 0; i < delta.broadcastedMessagesCostsLength(); i++) {
175+
let messageCost = delta.broadcastedMessagesCosts(i);
176+
// console.log(messageCost);
177+
// let x = delta.broadcastedMessages(j, flatbuffers.Encoding.UTF16_STRING);
178+
// var offset = delta.bb!.__offset(delta.bb_pos, 42);
179+
// var h = delta.bb!.__vector(delta.bb_pos + offset)
180+
// console.log(h);
181+
// var k = delta.bb!.readInt32(h);
182+
// console.log(k);
183+
// console.log(delta.bb!.readInt32(h+4));
184+
// console.log(delta.bb!.readInt32(h+8));
185+
// console.log(delta.bb!.readInt32(h+12));
186+
// console.log(delta.bb!.readInt32(h+16));
187+
let thisTransaction = "";
188+
let offset = delta.bb!.__offset(delta.bb_pos, 42);
189+
let startPointer = delta.bb!.__vector(delta.bb_pos + offset);
190+
if (offset) {
191+
// this is ascii
192+
let x = String.fromCharCode(delta.bb!.readInt32(startPointer + 4*j));
193+
while (x !== ' ') {
194+
// console.log(x);
195+
// this will be
196+
thisTransaction += x;
197+
j += 1;
198+
if (j >= messageStringLen) {
199+
console.log("BLOCKCHAIN ERROR SHOULD NEVER HAPPEN");
200+
break;
201+
}
202+
x = String.fromCharCode(delta.bb!.readInt32(startPointer + 4*j));
203+
}
204+
j += 1;
205+
// now split this transaction on _
206+
let splitMessage = thisTransaction.split("_");
207+
let messageArr = new Array<number>();
208+
for (let j = 0; j < splitMessage.length; j++) {
209+
messageArr.push(parseInt(splitMessage[j]));
210+
}
211+
blockMessages.push({
212+
cost: messageCost,
213+
message: messageArr
214+
});
215+
} else {
216+
console.log("couldn't display blockchain");
217+
}
218+
}
219+
220+
// console.log(blockMessages);
221+
222+
// for (let i = 0; i < delta.broadcastedMessagesCostsLength(); i++) {
223+
// let messageString = delta.broadcastedMessages(i);
224+
// let messageCost = delta.broadcastedMessagesCosts(i);
225+
// console.log(messageString);
226+
// // string is formatted as int_int_int
227+
// let splitMessage = messageString.split("_");
228+
// let messageArr = new Array<number>();
229+
// for (let j = 0; j < splitMessage.length; j++) {
230+
// messageArr.push(parseInt(splitMessage[j]));
231+
// }
232+
// blockMessages.push({
233+
// cost: messageCost,
234+
// message: messageArr
235+
// });
236+
// }
237+
238+
this.blockchain.push({
239+
messages: blockMessages,
240+
round: delta.roundID()
241+
});
139242
}
140243

141244
/**

client/visualizer/src/app.ts

+1
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ export default class Client {
672672
// @ts-ignore
673673
renderer.render(match.current, match.current.minCorner, match.current.maxCorner);
674674

675+
this.stats.showBlock(match.blockchain[match.current.turn]);
675676
this.updateStats(match.current, meta);
676677
this.loopID = window.requestAnimationFrame(loop);
677678

client/visualizer/src/game/sidebar/stats.ts

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Config} from '../../config';
22
import * as cst from '../../constants';
33
import {AllImages} from '../../imageloader';
4+
import {Block,Transaction} from 'battlecode-playback';
45

56
import {schema} from 'battlecode-playback';
67

@@ -34,6 +35,8 @@ export default class Stats {
3435

3536
private robotConsole: HTMLDivElement;
3637

38+
private blockchain: HTMLDivElement;
39+
3740
private conf: Config;
3841

3942
// Note: robot types and number of teams are currently fixed regardless of
@@ -233,7 +236,42 @@ export default class Stats {
233236
this.statsTableElement = this.statsTable(teamIDs);
234237
this.div.appendChild(this.statsTableElement);
235238

236-
this.div.appendChild(this.images.soup);
239+
this.div.appendChild(document.createElement('br'));
240+
241+
const bl = document.createElement("span");
242+
bl.innerText = "Blockchain";
243+
this.div.appendChild(bl);
244+
this.div.appendChild(document.createElement('br'));
245+
this.div.appendChild(this.blockchainViewer());
246+
}
247+
248+
blockchainViewer(): HTMLDivElement {
249+
// create a blockchain
250+
this.blockchain = document.createElement('div');
251+
252+
// make it a console
253+
this.blockchain.id = "blockchain";
254+
this.blockchain.className = "console";
255+
256+
return this.blockchain;
257+
}
258+
259+
public showBlock(block: Block): void {
260+
if (block !== undefined) {
261+
const div = document.createElement("div");
262+
// Replace \n with <br>
263+
const span = document.createElement("span");
264+
let text = "Block #" + String(block.round) + ":<br><br>";
265+
block.messages.forEach(t => {
266+
text += "cost: " + t.cost + "<br>message: " + t.message.join(', ') + "<br><br>";
267+
});
268+
span.innerHTML = text;
269+
div.appendChild(span);
270+
while (this.blockchain.firstChild) {
271+
this.blockchain.removeChild(this.blockchain.firstChild);
272+
}
273+
this.blockchain.appendChild(div);
274+
}
237275
}
238276

239277
addViewOptions(){

0 commit comments

Comments
 (0)