Skip to content

Commit 60923a4

Browse files
committed
Add usage examples/docs for SB data.
1 parent eee504c commit 60923a4

File tree

3 files changed

+259
-4
lines changed

3 files changed

+259
-4
lines changed

broodrep-wasm/README.md

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ fileInput.addEventListener('change', async event => {
3131
console.log('Replay parsed:', replay)
3232
console.log('Game title:', header.title)
3333
console.log('Map name:', header.mapName)
34-
console.log('Players:', replay.players().filter(p => !p.isEmpty && !p.isObserver))
34+
console.log(
35+
'Players:',
36+
replay.players().filter(p => !p.isEmpty && !p.isObserver),
37+
)
3538
} catch (error) {
3639
console.error('Failed to parse replay:', error)
3740
}
@@ -78,16 +81,19 @@ Parses a StarCraft replay file and returns a Replay object for retrieving game i
7881
class Replay {
7982
readonly format: ReplayFormat // "legacy", "modern", or "modern121"
8083
readonly header: ReplayHeader // Game header information
81-
84+
8285
// Methods for retrieving player information
8386
players(): Player[] // All player slots (including empty)
8487
observers(): Player[] // Only observers
8588
slots(): Player[] // All slots
8689
hostPlayer(): Player | undefined // The host player if identifiable
87-
90+
8891
// Methods for retrieving raw section data
8992
getRawSection(section: ReplaySection): Uint8Array | undefined
9093
getRawCustomSection(section_id: number): Uint8Array | undefined
94+
95+
// Method for retrieving parsed ShieldBattery data
96+
getShieldBatterySection(): ShieldBatteryData | undefined
9197
}
9298

9399
interface ReplayHeader {
@@ -115,6 +121,29 @@ interface Player {
115121
isEmpty: boolean // Whether this is an empty slot
116122
isObserver: boolean // Whether this is an observer
117123
}
124+
125+
interface ShieldBatteryData {
126+
starcraftExeBuild: number // StarCraft executable build number
127+
shieldbatteryVersion: string // ShieldBattery client version
128+
teamGameMainPlayers: [number, number, number, number] // Main players in team games
129+
startingRaces: [
130+
number,
131+
number,
132+
number,
133+
number,
134+
number,
135+
number,
136+
number,
137+
number,
138+
number,
139+
number,
140+
number,
141+
number,
142+
] // Starting race for each player
143+
gameId: string // Game UUID on ShieldBattery
144+
userIds: [number, number, number, number, number, number, number, number] // ShieldBattery user IDs
145+
gameLogicVersion: number | undefined // Game logic version (if available)
146+
}
118147
```
119148

120149
### `DecompressionConfig`
@@ -125,7 +154,7 @@ Configuration object for customizing security limits during replay parsing.
125154
// Create decompression config object
126155
const options = {
127156
maxDecompressedSize: 200 * 1024 * 1024, // 200MB
128-
maxCompressionRatio: 1000.0 // Allow 1000:1 compression ratio
157+
maxCompressionRatio: 1000.0, // Allow 1000:1 compression ratio
129158
}
130159

131160
const replay = parseReplay(replayData, options)
@@ -143,6 +172,54 @@ configured due to limitations of Rust's time implementation.
143172

144173
Returns the version of the broodrep library.
145174

175+
## ShieldBattery Support
176+
177+
The library includes support for parsing ShieldBattery-specific data from replays created through the [ShieldBattery](https://shieldbattery.net/) platform. This data provides additional context about games played on ShieldBattery.
178+
179+
### Basic Usage
180+
181+
```javascript
182+
import { parseReplay } from '@shieldbattery/broodrep'
183+
184+
// Parse a replay
185+
const replay = parseReplay(replayData)
186+
187+
// Check for ShieldBattery data
188+
const shieldBatteryData = replay.getShieldBatterySection()
189+
190+
if (shieldBatteryData) {
191+
console.log('Game ID:', shieldBatteryData.gameId)
192+
console.log('StarCraft Build:', shieldBatteryData.starcraftExeBuild)
193+
console.log('ShieldBattery Version:', shieldBatteryData.shieldbatteryVersion)
194+
195+
// Game logic version (if available in newer format)
196+
if (shieldBatteryData.gameLogicVersion !== undefined) {
197+
console.log('Game Logic Version:', shieldBatteryData.gameLogicVersion)
198+
}
199+
200+
// User IDs of active players
201+
const activeUserIds = shieldBatteryData.userIds.filter(id => id !== 0)
202+
console.log('User IDs:', activeUserIds)
203+
204+
// Starting races as numbers (0=Zerg, 1=Terran, 2=Protoss, 6=Random)
205+
const activePlayers = replay.players().filter(p => !p.isEmpty && !p.isObserver)
206+
const startingRaces = shieldBatteryData.startingRaces.slice(0, activePlayers.length)
207+
console.log('Starting Races:', startingRaces)
208+
} else {
209+
console.log('No ShieldBattery data (normal for non-ShieldBattery replays)')
210+
}
211+
```
212+
213+
### ShieldBatteryData Fields
214+
215+
- **`gameId`**: Unique UUID for the game on ShieldBattery platform
216+
- **`starcraftExeBuild`**: Build number of the StarCraft executable used
217+
- **`shieldbatteryVersion`**: Version string of the ShieldBattery client
218+
- **`gameLogicVersion`**: Version of game logic modifications (if available)
219+
- **`userIds`**: Array of ShieldBattery user IDs corresponding to players
220+
- **`teamGameMainPlayers`**: Identifies main players in team games
221+
- **`startingRaces`**: Original race selection for each player slot (before randomization)
222+
146223
## Building
147224

148225
````bash

broodrep-wasm/examples/index.html

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ <h3>Players</h3>
193193
<th>Team</th>
194194
<th>Type</th>
195195
<th>Slot</th>
196+
<th>Network ID</th>
196197
</tr>
197198
</thead>
198199
<tbody id="playersTableBody"></tbody>
@@ -212,6 +213,11 @@ <h3>Observers</h3>
212213
<tbody id="observersTableBody"></tbody>
213214
</table>
214215
</div>
216+
217+
<div class="info-section" id="shieldBatterySection" style="display: none">
218+
<h3>ShieldBattery Data</h3>
219+
<div class="info-grid" id="shieldBatteryInfo"></div>
220+
</div>
215221
</div>
216222
</div>
217223

@@ -327,6 +333,7 @@ <h3>Observers</h3>
327333
<td>${player.team}</td>
328334
<td>${player.playerType}</td>
329335
<td>${player.slotId}</td>
336+
<td>${player.networkId}</td>
330337
</tr>
331338
`,
332339
)
@@ -353,6 +360,82 @@ <h3>Observers</h3>
353360
observersSection.style.display = 'none'
354361
}
355362

363+
// ShieldBattery Data
364+
const shieldBatterySection = document.getElementById('shieldBatterySection')
365+
const shieldBatteryInfo = document.getElementById('shieldBatteryInfo')
366+
367+
const shieldBatteryData = replay.getShieldBatterySection()
368+
if (shieldBatteryData) {
369+
shieldBatterySection.style.display = 'block'
370+
371+
const raceNames = ['Zerg', 'Terran', 'Protoss']
372+
const startingRaces = shieldBatteryData.startingRaces
373+
.map(race => raceNames[race] || `Random`)
374+
.join(', ')
375+
376+
const activeUserIds = shieldBatteryData.userIds.filter(id => id !== 0)
377+
const mainPlayers = shieldBatteryData.teamGameMainPlayers
378+
379+
shieldBatteryInfo.innerHTML = `
380+
<div class="info-item">
381+
<div class="info-label">Game ID</div>
382+
<div class="info-value" style="font-family: monospace; font-size: 0.9em;">${
383+
shieldBatteryData.gameId
384+
}</div>
385+
</div>
386+
<div class="info-item">
387+
<div class="info-label">StarCraft Build</div>
388+
<div class="info-value">${shieldBatteryData.starcraftExeBuild}</div>
389+
</div>
390+
<div class="info-item">
391+
<div class="info-label">ShieldBattery Version</div>
392+
<div class="info-value">${shieldBatteryData.shieldbatteryVersion}</div>
393+
</div>
394+
${
395+
shieldBatteryData.gameLogicVersion !== undefined
396+
? `
397+
<div class="info-item">
398+
<div class="info-label">Game Logic Version</div>
399+
<div class="info-value">${shieldBatteryData.gameLogicVersion}</div>
400+
</div>
401+
`
402+
: ''
403+
}
404+
${
405+
startingRaces
406+
? `
407+
<div class="info-item">
408+
<div class="info-label">Starting Races</div>
409+
<div class="info-value">${startingRaces}</div>
410+
</div>
411+
`
412+
: ''
413+
}
414+
${
415+
activeUserIds.length > 0
416+
? `
417+
<div class="info-item">
418+
<div class="info-label">User IDs</div>
419+
<div class="info-value">[${activeUserIds.join(', ')}]</div>
420+
</div>
421+
`
422+
: ''
423+
}
424+
${
425+
mainPlayers.length > 0
426+
? `
427+
<div class="info-item">
428+
<div class="info-label">Team Game Main Players</div>
429+
<div class="info-value">[${mainPlayers.join(', ')}]</div>
430+
</div>
431+
`
432+
: ''
433+
}
434+
`
435+
} else {
436+
shieldBatterySection.style.display = 'none'
437+
}
438+
356439
replayInfo.style.display = 'block'
357440
}
358441

broodrep-wasm/examples/usage.mjs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,108 @@ function customOptionsExample() {
210210
}
211211
}
212212

213+
/**
214+
* Example 5: ShieldBattery data extraction
215+
*/
216+
function shieldBatteryExample() {
217+
console.log('\n=== ShieldBattery Data Example ===')
218+
219+
// Try to find a ShieldBattery replay
220+
const sbReplayPath = path.join(
221+
import.meta.dirname,
222+
'..',
223+
'..',
224+
'broodrep',
225+
'testdata',
226+
'sb_data.rep',
227+
)
228+
229+
let testReplayPath = sbReplayPath
230+
if (!fs.existsSync(sbReplayPath)) {
231+
// Fall back to a regular replay for demonstration
232+
testReplayPath = path.join(
233+
import.meta.dirname,
234+
'..',
235+
'..',
236+
'broodrep',
237+
'testdata',
238+
'things.rep',
239+
)
240+
console.log('No ShieldBattery replay found, using regular replay for demonstration...')
241+
}
242+
243+
if (!fs.existsSync(testReplayPath)) {
244+
console.log('No test replay found, skipping ShieldBattery example...')
245+
return
246+
}
247+
248+
try {
249+
const replayData = fs.readFileSync(testReplayPath)
250+
const uint8Array = new Uint8Array(replayData)
251+
const replay = parseReplay(uint8Array)
252+
253+
// Try to get ShieldBattery data
254+
const shieldBatteryData = replay.getShieldBatterySection()
255+
256+
if (shieldBatteryData) {
257+
console.log('✓ Found ShieldBattery data!')
258+
console.log('ShieldBattery Information:')
259+
console.log(` Game ID: ${shieldBatteryData.gameId}`)
260+
console.log(` StarCraft Build: ${shieldBatteryData.starcraftExeBuild}`)
261+
console.log(` ShieldBattery Version: ${shieldBatteryData.shieldbatteryVersion}`)
262+
263+
if (shieldBatteryData.gameLogicVersion !== undefined) {
264+
console.log(` Game Logic Version: ${shieldBatteryData.gameLogicVersion}`)
265+
}
266+
267+
// Show team game main players (if applicable)
268+
const mainPlayers = shieldBatteryData.teamGameMainPlayers
269+
console.log(` Team Game Main Players: [${mainPlayers.join(', ')}]`)
270+
271+
// Show user IDs
272+
const activeUserIds = shieldBatteryData.userIds.filter(id => id !== 0)
273+
if (activeUserIds.length > 0) {
274+
console.log(` User IDs: [${activeUserIds.join(', ')}]`)
275+
}
276+
277+
// Show starting races (as race names)
278+
const raceNames = ['Zerg', 'Terran', 'Protoss']
279+
const startingRaces = shieldBatteryData.startingRaces.map(race => raceNames[race] || 'Random')
280+
281+
if (startingRaces.length > 0) {
282+
console.log(` Starting Races: [${startingRaces.join(', ')}]`)
283+
}
284+
} else {
285+
console.log('ℹ No ShieldBattery data found in this replay')
286+
console.log(' This is normal for replays not created through ShieldBattery')
287+
}
288+
289+
// Also demonstrate raw section access
290+
console.log('\nRaw Section Access:')
291+
const headerSection = replay.getRawSection('header')
292+
if (headerSection) {
293+
console.log(` Header section: ${headerSection.length} bytes`)
294+
}
295+
296+
const shieldBatterySection = replay.getRawSection('shieldBattery')
297+
if (shieldBatterySection) {
298+
console.log(` ShieldBattery section: ${shieldBatterySection.length} bytes (raw)`)
299+
} else {
300+
console.log(` No ShieldBattery section found`)
301+
}
302+
} catch (error) {
303+
console.error('✗ ShieldBattery example failed:', error)
304+
}
305+
}
306+
213307
console.log('broodrep-wasm Usage Examples')
214308
console.log('============================')
215309

216310
basicExample()
217311
detailedExample()
218312
errorHandlingExample()
219313
customOptionsExample()
314+
shieldBatteryExample()
220315

221316
console.log('\n✓ All examples completed!')
222317
console.log('\nTip: To use in your project:')

0 commit comments

Comments
 (0)