Skip to content

Commit 667a599

Browse files
committed
feat(jsbattle-engine): add battle time limt to UBD schema
1 parent 441d69a commit 667a599

File tree

18 files changed

+243
-18
lines changed

18 files changed

+243
-18
lines changed

packages/jsbattle-docs/docs/dev_guide/ubd_files.md

+53-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
Ultimate Battle Descriptor (UBD) contains all the information required to replay a battle. Battle launched from UBD file is deterministic and always has the same outcome.
33

44
## UBD Player
5-
Distribution of JsBattle contains command line tool that allows processing of UBD files to get result of the battle without watching it. It is located in `/dist/server/ubdplayer.js`. You can run as any shell command (`./ubdplayer.js`) or via NodeJs (`node ubdplayer.js`). For more information, run `./ubdplayer.js --help`.
5+
Distribution of JsBattle contains command line tool that allows processing of UBD files to get result of the battle without watching it. It is located in `/dist/ubdplayer.js`. You can run as any shell command (`./ubdplayer.js`) or via NodeJs (`node ubdplayer.js`). For more information, run `./ubdplayer.js --help`.
66

77
## Changelog
88

99
Date | Version | Schema Location | Description
1010
-----------|---------|---------------------------------|-----------------------------
1111
2018-05-31 | 1 | `src/schema/ubd-schema-v1.json` | Initial Version
1212
2018-06-04 | 2 | `src/schema/ubd-schema-v2.json` | Adding teamMode information
13-
13+
2019-12-09 | 3 | `src/schema/ubd-schema-v3.json` | Adding timeLimit information
1414

1515
## UBD Format
1616
UBD is a JSON file of the following format
@@ -27,13 +27,17 @@ Determine if the battle is played in cooperative mode. Possible values are true
2727
### .aiList
2828
Array of AI definitions that participate in the battle. Each AI definition is a JSON object.
2929

30+
### .timeLimit
31+
Maximum duration of the battle in milliseconds, or zero if unlimited
32+
3033
## UBD example
3134

3235
```json
3336
{
3437
"version": 2,
3538
"rngSeed": 0.850067584253805,
3639
"teamMode": false,
40+
"timeLimit": 30000,
3741
"aiList": [
3842
{
3943
"name": "User Created Tank",
@@ -54,3 +58,50 @@ Array of AI definitions that participate in the battle. Each AI definition is a
5458
]
5559
}
5660
```
61+
62+
## Updating UBD schema
63+
64+
Follow those steps when releasing new version of UBD schema
65+
66+
1. Create JSON Schema in `packages/jsbattle-engine/src/schema/ubd-schema-v[version].json`
67+
2. Update version number in ubd-schema file
68+
3. Update documentation at `packages/jsbattle-docs/docs/dev_guide/ubd_files.md`
69+
- modify change log
70+
- describe changed fields
71+
4. update version of schema at `packages/jsbattle-engine/src/engine/UltimateBattleDescriptor.js`
72+
```javascript
73+
import schema from '../schema/ubd-schema-v[version].json';
74+
// ...
75+
76+
class UltimateBattleDescriptor {
77+
constructor() {
78+
this._version = [version];
79+
}
80+
}
81+
```
82+
5. update `encode` and `decode` methods of at `UltimateBattleDescriptor`
83+
6. Update UbdValidator at `packages/jsbattle-server/app/services/ubdValidator/ubdValidator.js`
84+
85+
```javascript
86+
const schema_v[version] = JsBattleSchema.getVersion([version]);
87+
88+
// ...
89+
90+
function validate(msg, respond ) {
91+
// ...
92+
switch (version) {
93+
// ...
94+
case [version]:
95+
schema = schema_v[version];
96+
break;
97+
}
98+
}
99+
```
100+
7. Update sample UBD at `packages/jsbattle-webpage/src/components/screen/UbdPlayer/UbdPlayer.js`
101+
```javascript
102+
render() {
103+
// ...
104+
let ubdSample ='{"version": [version], ... }';
105+
// ...
106+
}
107+
```

packages/jsbattle-engine/src/engine/Simulation.js

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class Simulation {
156156
}
157157

158158
set timeLimit(v) {
159+
this._ultimateBattleDescriptor.setTimeLimit(v);
159160
this._timeLimit = v;
160161
}
161162

packages/jsbattle-engine/src/engine/UltimateBattleDescriptor.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
import AiDefinition from "./AiDefinition.js";
44
import Ajv from 'ajv';
5-
import schema from '../schema/ubd-schema-v2.json';
5+
import schema from '../schema/ubd-schema-v3.json';
66

77
class UltimateBattleDescriptor {
88

99
constructor() {
10-
this._version = 2;
10+
this._version = 3;
1111
this._aiList = [];
1212
this._rngSeed = (new Date()).getTime();
1313
this._teamMode = false;
14+
this._timeLimit = 0;
1415
}
1516

1617
addAiDefinition(ai) {
@@ -37,6 +38,14 @@ class UltimateBattleDescriptor {
3738
return this._aiList;
3839
}
3940

41+
setTimeLimit(limit) {
42+
this._timeLimit = limit;
43+
}
44+
45+
getTimeLimit() {
46+
return this._timeLimit;
47+
}
48+
4049
getRngSeed() {
4150
return this._rngSeed;
4251
}
@@ -46,6 +55,7 @@ class UltimateBattleDescriptor {
4655
version: this._version,
4756
rngSeed: this._rngSeed,
4857
teamMode: this._teamMode,
58+
timeLimit: this._timeLimit,
4959
aiList: []
5060
};
5161
for(let ai of this._aiList) {
@@ -68,6 +78,7 @@ class UltimateBattleDescriptor {
6878
this.validateJsonData(json);
6979
this._rngSeed = json.rngSeed;
7080
this._teamMode = json.teamMode;
81+
this._timeLimit = json.timeLimit;
7182

7283
let ai;
7384
for(let aiJson of json.aiList) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
{
2+
"definitions": {},
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"$id": "http://jsbattle.jmrlab.com/schema/ubd-schema-v3.json",
5+
"type": "object",
6+
"title": "The Ultimate Battle Descriptor Schema",
7+
"version": 3.0,
8+
"required": [
9+
"version",
10+
"rngSeed",
11+
"timeLimit",
12+
"teamMode",
13+
"aiList"
14+
],
15+
"properties": {
16+
"version": {
17+
"$id": "#/properties/version",
18+
"enum": [3],
19+
"title": "Version of the schema"
20+
},
21+
"rngSeed": {
22+
"$id": "#/properties/rngSeed",
23+
"type": "number",
24+
"title": "Battle RNG seed",
25+
"default": 0.0,
26+
"examples": [
27+
0.850067584253805
28+
]
29+
},
30+
"timeLimit": {
31+
"$id": "#/properties/timeLimit",
32+
"type": "number",
33+
"title": "Duration of the battle in ms (or zero if no limit defined",
34+
"default": 0,
35+
"examples": [
36+
0,
37+
20000
38+
]
39+
},
40+
"teamMode": {
41+
"$id": "#/properties/teamMode",
42+
"type": "boolean",
43+
"title": "Team death match",
44+
"default": false,
45+
"examples": [
46+
false
47+
]
48+
},
49+
"aiList": {
50+
"$id": "#/properties/aiList",
51+
"type": "array",
52+
"minItems": 2,
53+
"maxItems": 40,
54+
"title": "List of AIs that joins the battle",
55+
"items": {
56+
"$id": "#/properties/aiList/items",
57+
"type": "object",
58+
"title": "Tank AI",
59+
"required": [
60+
"name",
61+
"team",
62+
"code",
63+
"initData",
64+
"useSandbox",
65+
"executionLimit"
66+
],
67+
"properties": {
68+
"name": {
69+
"$id": "#/properties/aiList/items/properties/name",
70+
"type": "string",
71+
"title": "Name of tank",
72+
"default": "",
73+
"examples": [
74+
"User Created Tank"
75+
],
76+
"pattern": "^(.*)$"
77+
},
78+
"team": {
79+
"$id": "#/properties/aiList/items/properties/team",
80+
"type": "string",
81+
"title": "Team of the tank",
82+
"default": "",
83+
"examples": [
84+
"10i42s2ca"
85+
],
86+
"pattern": "^(.*)$"
87+
},
88+
"code": {
89+
"$id": "#/properties/aiList/items/properties/code",
90+
"anyOf": [
91+
{"type": "string"},
92+
{"type": "null"}
93+
],
94+
"title": "Code of the AI",
95+
"default": "",
96+
"examples": [
97+
"var a = 1;"
98+
]
99+
},
100+
"initData": {
101+
"$id": "#/properties/aiList/items/properties/initData",
102+
"default": null,
103+
"title": "Initial data of AI",
104+
"anyOf": [
105+
{"type": "object"},
106+
{"type": "null"}
107+
],
108+
"examples": [
109+
null
110+
]
111+
},
112+
"useSandbox": {
113+
"$id": "#/properties/aiList/items/properties/useSandbox",
114+
"type": "boolean",
115+
"title": "Use sandbox for AI execution",
116+
"default": true,
117+
"examples": [
118+
true
119+
]
120+
},
121+
"executionLimit": {
122+
"$id": "#/properties/aiList/items/properties/executionLimit",
123+
"type": "integer",
124+
"title": "AI code execution time limit in ms",
125+
"default": 100,
126+
"examples": [
127+
100
128+
]
129+
}
130+
}
131+
}
132+
}
133+
}
134+
}

packages/jsbattle-engine/test/engine/UltimateBattleDescriptor.test.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('UltimateBattleDescriptor', function() {
88

99
it('should create empty descriptor with current version', function () {
1010
let desc = new UltimateBattleDescriptor();
11-
assert.equal(2, desc.getVersion());
11+
assert.equal(3, desc.getVersion());
1212
assert.equal(0, desc.getAiList().length);
1313
});
1414
});
@@ -96,6 +96,7 @@ describe('UltimateBattleDescriptor', function() {
9696
desc.setRngSeed(87);
9797

9898
let raw = desc.encode();
99+
console.log(raw);
99100
desc = new UltimateBattleDescriptor();
100101
desc.decode(raw);
101102

@@ -126,9 +127,10 @@ describe('UltimateBattleDescriptor', function() {
126127

127128
it('should support secure mode', function() {
128129
let ubd = {
129-
"version": 2,
130+
"version": 3,
130131
"rngSeed": 0.850067584253805,
131132
"teamMode": false,
133+
"timeLimit": 30000,
132134
"aiList": [
133135
{
134136
"name": "User Created Tank",
@@ -161,9 +163,10 @@ describe('UltimateBattleDescriptor', function() {
161163

162164
it('should support unsecure mode', function() {
163165
let ubd = {
164-
"version": 2,
166+
"version": 3,
165167
"rngSeed": 0.850067584253805,
166168
"teamMode": false,
169+
"timeLimit": 30000,
167170
"aiList": [
168171
{
169172
"name": "User Created Tank",
@@ -196,9 +199,10 @@ describe('UltimateBattleDescriptor', function() {
196199

197200
it('should validate json', function() {
198201
let ubd = {
199-
"version": 2,
202+
"version": 3,
200203
"rngSeed": 0.850067584253805,
201204
"teamMode": false,
205+
"timeLimit": 30000,
202206
"aiList": [
203207
{
204208
"name": "User Created Tank",

packages/jsbattle-server/app/services/ubdValidator/ubdValidator.js

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module.exports = function battleStore( options ) {
66

77
const schema_v1 = JsBattleSchema.getVersion(1);
88
const schema_v2 = JsBattleSchema.getVersion(2);
9+
const schema_v3 = JsBattleSchema.getVersion(3);
910

1011
this.add('role:ubdValidator,cmd:validate', validate);
1112

@@ -40,6 +41,9 @@ module.exports = function battleStore( options ) {
4041
case 2:
4142
schema = schema_v2;
4243
break;
44+
case 3:
45+
schema = schema_v3;
46+
break;
4347
default:
4448
return respond(null, {valid: false, error: `UBD version ${version} is not supported`});
4549
}

packages/jsbattle-webpage/features/support/api.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
{
77
"battleId":"12345678-1234-1234-1234-123456789012",
88
"ubd":{
9-
"version":2,
9+
"version":3,
1010
"rngSeed":0.9590806159338761,
1111
"teamMode":false,
12+
"timeLimit":30000,
1213
"aiList":[
1314
{
1415
"name":"dodge",

packages/jsbattle-webpage/src/components/App.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default class App extends React.Component {
5858
case 'TANK_LIST':
5959
return <StartScreen
6060
{...this.state.battle}
61-
onStart={(aiDefList, teamMode, rngSeed) => this.controller.openBattle(aiDefList, teamMode, rngSeed)}
61+
onStart={(aiDefList, teamMode, rngSeed, timeLimit) => this.controller.openBattle(aiDefList, teamMode, rngSeed, timeLimit)}
6262
onError={(msg) => this.showError(msg)}
6363
onScriptEdit={(name) => this.controller.openCodeEditor(name, 'TANK_LIST')}
6464
onTeamModeToggle={(isEnabled) => this.controller.toggleTeamMode(isEnabled)}

packages/jsbattle-webpage/src/components/common/battle/BattleWidget.js

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default class BattleWidget extends React.Component {
2222
teamList: [],
2323
windowSize: 'md',
2424
rngSeed: (props.rngSeed !== undefined) ? props.rngSeed : Math.random(),
25+
timeLimt: (props.timeLimt !== undefined) ? props.timeLimt : 30000,
2526
error: ""
2627
};
2728
}
@@ -166,6 +167,7 @@ export default class BattleWidget extends React.Component {
166167
<Battlefield
167168
ref={(battlefield) => this.battlefield = battlefield }
168169
rngSeed={this.state.rngSeed}
170+
timeLimit={this.state.timeLimit}
169171
width="900"
170172
height="600"
171173
speed={this.props.speed}

0 commit comments

Comments
 (0)