Skip to content

Commit c108b8e

Browse files
Merge branch 'fix-sdk-improve-gem-performance' into 'master'
[FIX][SDK]Performance update: games require 3000% less RAM See merge request codingame/game-engine!218
2 parents 001087c + b873953 commit c108b8e

File tree

8 files changed

+88
-71
lines changed

8 files changed

+88
-71
lines changed

engine/modules/entities/src/main/java/com/codingame/gameengine/module/entities/GraphicEntityModule.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,12 @@ private void sendFrameData() {
200200
currentWorldState.updateAllEntities(nextWorldState);
201201
}
202202

203-
Optional<String> worldCommits = gameSerializer.serializeWorldCommits(worldCommitsBuilder);
204-
205203
Optional<String> update = gameSerializer.serializeWorldDiff(updateBuilder);
206204

207205
worldStates.clear();
208206
gameManager.setViewData(
209207
"entitymodule",
210-
Stream.of(load, create, update, worldCommits)
208+
Stream.of(load, create, update)
211209
.filter(Optional::isPresent)
212210
.map(Optional::get)
213211
.collect(Collectors.joining("\n"))

engine/modules/entities/src/main/java/com/codingame/gameengine/module/entities/Serializer.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ class Serializer {
7171
commands.put("CREATE", "C");
7272
commands.put("UPDATE", "U");
7373
commands.put("LOADSPRITESHEET", "L");
74-
commands.put("WORLDUPDATE", "W");
7574

7675
separators = new HashMap<>();
7776
separators.put("COMMAND", ";");
@@ -229,18 +228,6 @@ public Optional<String> serializeLoadSpriteSheets(List<SpriteSheetSplitter> spri
229228
}
230229
}
231230

232-
public Optional<String> serializeWorldCommits(List<String> worldCommits) {
233-
if (worldCommits.isEmpty()) {
234-
return Optional.empty();
235-
} else {
236-
return Optional.of(
237-
commands.get("WORLDUPDATE") +
238-
worldCommits.stream()
239-
.collect(Collectors.joining(separators.get("COMMAND_ARGUMENT")))
240-
);
241-
}
242-
}
243-
244231
public Optional<String> serializeWorldDiff(List<WorldState> diffs) {
245232
if (diffs.isEmpty()) {
246233
return Optional.empty();

engine/modules/entities/src/main/resources/view/entity-module/Command.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,6 @@ export class PropertiesCommand {
152152
apply (entities, frameInfo) {
153153
let entity = entities.get(this.id)
154154
entity.addState(this.t, { values: this.params, curve: this.curve }, frameInfo.number, frameInfo)
155-
}
156-
}
157-
export class WorldCommitCommand {
158-
constructor (args, globalData) {
159-
this.times = args.map(v => +v)
160-
}
161-
162-
apply (entities, frameInfo) {
163-
entities.forEach(entity => {
164-
this.times.forEach(time => {
165-
entity.addState(time, { values: {}, curve: {} }, frameInfo.number, frameInfo)
166-
})
167-
})
155+
entity.stateAdded = true
168156
}
169157
}

engine/modules/entities/src/main/resources/view/entity-module/CommandParser.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { CreateCommand, PropertiesCommand, LoadCommand, WorldCommitCommand } from './Command.js'
1+
import { CreateCommand, PropertiesCommand, LoadCommand } from './Command.js'
22

33
const COMMAND_KEY_MAP = {
44
C: CreateCommand,
55
U: PropertiesCommand,
6-
L: LoadCommand,
7-
W: WorldCommitCommand
6+
L: LoadCommand
87
}
98

109
function splitOnCharOutsideQuotes (text, charParam) {

engine/modules/entities/src/main/resources/view/entity-module/Entity.js

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,31 @@ export class Entity {
6262
render (progress, data, globalData) {
6363
let subframes = this.states[data.number]
6464
this.container.visible = false
65+
let start = null
66+
let end
67+
// This t is used to animate the interpolation
68+
let t = 1
6569
if (subframes && subframes.length) {
6670
let index = 0
6771
while (index < subframes.length - 1 && subframes[index].t < progress) {
6872
index++
6973
}
70-
let start = subframes[index - 1]
71-
let end = subframes[index]
72-
// This t is used to animate the interpolation
73-
let t
74+
75+
start = subframes[index - 1]
76+
end = subframes[index]
7477

7578
if (!start) {
76-
// The start frame must be at the end of the previous turn
77-
var prev = this.states[data.previous.number] || []
79+
// The start frame must be at the end of a previous turn
80+
let frameNumbers = Object.keys(this.states)
81+
let index = frameNumbers.indexOf(data.number.toString()) - 1
82+
// Failsafe
83+
if (index === -1) {
84+
index = frameNumbers.length - 1
85+
}
86+
while (index >= 0 && frameNumbers[index] >= data.number) {
87+
index--
88+
}
89+
let prev = this.states[frameNumbers[index]] || []
7890
start = prev[prev.length - 1]
7991

8092
// If it didn't exist on the previous turn, don't even animate it
@@ -88,41 +100,53 @@ export class Entity {
88100
} else {
89101
t = unlerp(start.t, end.t, progress)
90102
}
91-
if (start) {
92-
const changed = {}
93-
const state = Object.assign({}, this.currentState)
94-
95-
for (let property of this.properties) {
96-
const opts = PROPERTIES[property] || PROPERTIES.default
97-
const lerpMethod = opts.lerpMethod
98-
const curve = end.curve[property] || (a => a)
99-
const newValue = lerpMethod(start[property], end[property], curve(t))
100-
if (newValue !== this.currentState[property]) {
101-
changed[property] = true
102-
state[property] = newValue
103-
}
104-
}
105-
this.updateDisplay(state, changed, globalData, data, progress)
106-
Object.assign(this.currentState, state)
107-
this.container.visible = this.container._visible
108-
if (changed.children) {
109-
globalData.mustResetTree = true
110-
if (typeof this.postUpdate === 'function') {
111-
globalData.updatedBuffers.push(this)
112-
}
113-
}
114-
if (changed.zIndex) {
115-
globalData.mustResort = true
116-
}
117-
if (changed.mask) {
118-
globalData.maskUpdates[this.id] = state.mask
103+
} else {
104+
// Look for the most recent state, but don't interpolate?
105+
let frameNumbers = Object.keys(this.states)
106+
let index = frameNumbers.length - 1
107+
while (index >= 0 && frameNumbers[index] > data.number) {
108+
index--
109+
}
110+
let substates = this.states[frameNumbers[index]]
111+
112+
if (substates != null) {
113+
start = substates[substates.length - 1]
114+
end = start
115+
} else {
116+
Object.assign(this.currentState, this.defaultState)
117+
}
118+
}
119+
if (start) {
120+
const changed = {}
121+
const state = Object.assign({}, this.currentState)
122+
for (let property of this.properties) {
123+
const opts = PROPERTIES[property] || PROPERTIES.default
124+
const lerpMethod = opts.lerpMethod
125+
const curve = end.curve[property] || (a => a)
126+
const newValue = lerpMethod(start[property], end[property], curve(t))
127+
if (newValue !== this.currentState[property]) {
128+
changed[property] = true
129+
state[property] = newValue
119130
}
120-
if (Object.keys(changed).length !== 0 && this.parent) {
121-
this.parent.notifyChange()
131+
}
132+
this.updateDisplay(state, changed, globalData, data, progress)
133+
Object.assign(this.currentState, state)
134+
this.container.visible = this.container._visible
135+
if (changed.children) {
136+
globalData.mustResetTree = true
137+
if (typeof this.postUpdate === 'function') {
138+
globalData.updatedBuffers.push(this)
122139
}
123140
}
124-
} else {
125-
Object.assign(this.currentState, this.defaultState)
141+
if (changed.zIndex) {
142+
globalData.mustResort = true
143+
}
144+
if (changed.mask) {
145+
globalData.maskUpdates[this.id] = state.mask
146+
}
147+
if (Object.keys(changed).length !== 0 && this.parent) {
148+
this.parent.notifyChange()
149+
}
126150
}
127151
}
128152

engine/modules/entities/src/main/resources/view/entity-module/GraphicEntityModule.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ export class GraphicEntityModule {
7575
const previousFrameNumber = frameInfo.previous.number
7676
this
7777
.entities.forEach(entity => {
78+
// Only create if entity is affected by this frameInfo
79+
if (entity.stateAdded) {
80+
entity.stateAdded = false
81+
} else {
82+
return
83+
}
84+
7885
// Create empty substate array if none
7986
if (!entity.states[frameNumber]) {
8087
entity.states[frameNumber] = []

engine/modules/tooltip/src/main/resources/view/tooltip-module/TooltipModule.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,21 @@ function getMouseOutFunc (id, tooltip) {
1515
}
1616
}
1717

18+
function getEntityCurrentSubStates (entity, frame) {
19+
if (entity.states[frame]) {
20+
return entity.states[frame]
21+
}
22+
let frameNumbers = Object.keys(entity.states)
23+
let index = frameNumbers.length - 1
24+
25+
while (index >= 0 && frameNumbers[index] > frame) {
26+
index--
27+
}
28+
return entity.states[frameNumbers[index]] || []
29+
}
30+
1831
function getEntityState (entity, frame) {
19-
const subStates = entity.states[frame]
32+
const subStates = getEntityCurrentSubStates(entity, frame)
2033
if (subStates && subStates.length) {
2134
return subStates[subStates.length - 1]
2235
}

playground/misc/misc-3-release-notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The CodinGame SDK is regularly updated and improved. This document lets you know
88

99
- `Invalid negative values for colours no longer crash the game`
1010
- `Fixed missing line breaks in the Game Summary console`
11+
- `Games now require less RAM in the CodinGame IDE`
1112

1213
## 3.4.8
1314

0 commit comments

Comments
 (0)