Skip to content

Commit 1799be0

Browse files
author
Builder
committed
Merge branch '4326-sdk-add-a-force-commit-option' into 'master'
[FIX][sdk] Changing the behaviour of the commit and optimization See merge request codingame/game-engine!126
2 parents 88ade7a + e4a5331 commit 1799be0

File tree

9 files changed

+267
-89
lines changed

9 files changed

+267
-89
lines changed

engine/core/src/main/java/com/codingame/gameengine/core/GameManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ private void dumpView() {
240240
if (totalViewDataBytesSent > VIEW_DATA_HARD_QUOTA) {
241241
throw new RuntimeException("The amount of data sent to the viewer is too big!");
242242
} else if (totalViewDataBytesSent > VIEW_DATA_SOFT_QUOTA) {
243-
log.warn("Warning: the amount of data sent to the viewer is too big. Please try to optimize your code to send less data.");
243+
log.warn("Warning: the amount of data sent to the viewer is too big.\nPlease try to optimize your code to send less data (try replacing some commitEntityStates by a commitWorldState).");
244244
}
245245

246246
log.info(viewData);

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

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.List;
66
import java.util.Map;
77
import java.util.Map.Entry;
8+
import java.util.Optional;
89
import java.util.stream.Collectors;
910
import java.util.stream.Stream;
1011

@@ -107,9 +108,7 @@ public SpriteSheetLoader createSpriteSheetLoader() {
107108
* <p>
108109
* Only the most recent commits are kept for a given t.
109110
* </p>
110-
* <p>
111-
* If an entity hasn't changed since its previous commit, its commit is ignored.
112-
* </p>
111+
*
113112
*
114113
* @param t
115114
* The instant of the frame 0 &ge; t &ge; 1.
@@ -118,15 +117,14 @@ public SpriteSheetLoader createSpriteSheetLoader() {
118117
*
119118
*/
120119
public void commitWorldState(double t) {
121-
commitEntityState(t, entities.toArray(new Entity[entities.size()]));
120+
commitState(t, true, entities.toArray(new Entity[entities.size()]));
122121
}
123122

124123
/**
125124
* This entity's graphical counterpart, at instant t of the frame being computed, will have the same properties as the java object as it is now.
126125
* <p>
127126
* Only the most recent commit is kept for a given t.
128127
* <p>
129-
* If the entity hasn't changed since its previous commit, the commit is ignored.
130128
*
131129
* @param t
132130
* The instant of the frame 0 &ge; t &ge; 1.
@@ -137,6 +135,10 @@ public void commitWorldState(double t) {
137135
*
138136
*/
139137
public void commitEntityState(double t, Entity<?>... entities) {
138+
commitState(t, false, entities);
139+
}
140+
141+
private void commitState(double t, boolean commitAll, Entity<?>... entities) {
140142
requireValidFrameInstant(t);
141143
requireNonEmpty(entities);
142144

@@ -148,9 +150,15 @@ public void commitEntityState(double t, Entity<?>... entities) {
148150
worldStates.put(actualT, state);
149151
}
150152

151-
final WorldState finalState = state;
152-
Stream.of(entities).forEach(entity -> finalState.flushEntityState(entity));
153+
if (commitAll) {
154+
state.markAsWorldCommit();
155+
}
156+
flushAllEntityStates(entities, state);
157+
158+
}
153159

160+
private void flushAllEntityStates(Entity<?>[] entities, WorldState state) {
161+
Stream.of(entities).forEach(entity -> state.flushEntityState(entity));
154162
}
155163

156164
private void requireNonEmpty(Object[] items) {
@@ -166,40 +174,48 @@ private static void requireValidFrameInstant(double t) {
166174
}
167175

168176
private void sendFrameData() {
169-
List<Object> commands = new ArrayList<>();
170177

171178
autocommit();
172179

173-
newSpriteSheets.forEach(e -> commands.add(gameSerializer.serializeLoadSpriteSheet(e)));
180+
Optional<String> load = gameSerializer.serializeLoadSpriteSheets(newSpriteSheets);
174181
newSpriteSheets.clear();
175182

176-
newEntities.stream().forEach(e -> {
177-
commands.add(gameSerializer.serializeCreateEntity(e));
178-
});
183+
Optional<String> create = gameSerializer.serializeCreateEntities(newEntities);
179184
newEntities.clear();
180185

181186
List<WorldState> orderedStates = worldStates.entrySet().stream()
182187
.sorted((e1, e2) -> e1.getValue().getFrameTime().compareTo(e2.getValue().getFrameTime()))
183188
.map(Entry::getValue)
184189
.collect(Collectors.toList());
185190

191+
List<String> worldCommitsBuilder = new ArrayList<>();
192+
List<WorldState> updateBuilder = new ArrayList<>();
193+
186194
for (WorldState nextWorldState : orderedStates) {
195+
if (nextWorldState.isWorldCommit()) {
196+
worldCommitsBuilder.add(nextWorldState.getFrameTime());
197+
}
187198
WorldState worldStateDiff = nextWorldState.diffFromOtherWorldState(currentWorldState);
188-
worldStateDiff.getEntityStateMap().forEach((entity, diff) -> {
189-
String serializedStateDiff = gameSerializer.serializeEntitiesStateDiff(entity, diff, worldStateDiff.getFrameTime());
190-
commands.add(serializedStateDiff);
191-
});
192-
199+
updateBuilder.add(worldStateDiff);
193200
currentWorldState.updateAllEntities(nextWorldState);
194201
}
195202

196-
worldStates.clear();
203+
Optional<String> worldCommits = gameSerializer.serializeWorldStateUpdates(worldCommitsBuilder);
197204

198-
gameManager.setViewData("entitymodule", commands);
205+
Optional<String> update = gameSerializer.serializeWorldDiff(updateBuilder);
206+
207+
worldStates.clear();
208+
gameManager.setViewData(
209+
"entitymodule",
210+
Stream.of(load, create, update, worldCommits)
211+
.filter(Optional::isPresent)
212+
.map(Optional::get)
213+
.collect(Collectors.joining("\n"))
214+
);
199215
}
200216

201217
private void autocommit() {
202-
WorldState state = worldStates.computeIfAbsent("1", (key) -> new WorldState("1", true));
218+
WorldState state = worldStates.computeIfAbsent("1", (key) -> new WorldState("1"));
203219
state.flushMissingEntities(entities);
204220
}
205221

@@ -279,7 +295,7 @@ public Group createGroup(Entity<?>... entities) {
279295
return e;
280296

281297
}
282-
298+
283299
/**
284300
* Creates a new BufferedGroup entity, its graphical counterpart will be created on the frame currently being computed.
285301
* <p>

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

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import java.text.DecimalFormat;
44
import java.text.DecimalFormatSymbols;
55
import java.util.Map;
6+
import java.util.Map.Entry;
7+
import java.util.Optional;
8+
import java.util.Set;
69
import java.util.HashMap;
10+
import java.util.List;
711
import java.util.stream.Collectors;
812
import java.util.stream.Stream;
913

@@ -12,8 +16,7 @@
1216

1317
@Singleton
1418
class Serializer {
15-
16-
Map<String, String> commands, keys;
19+
public Map<String, String> commands, keys, separators;
1720
Map<Entity.Type, String> types;
1821
Map<Curve, String> curves;
1922
private static DecimalFormat decimalFormat;
@@ -46,7 +49,7 @@ class Serializer {
4649
keys.put("fontFamily", "ff");
4750
keys.put("fontSize", "s");
4851
keys.put("text", "T");
49-
keys.put("children", "C");
52+
keys.put("children", "ch");
5053
keys.put("scaleX", "sx");
5154
keys.put("scaleY", "sy");
5255
keys.put("anchorX", "ax");
@@ -65,6 +68,13 @@ class Serializer {
6568
commands.put("CREATE", "C");
6669
commands.put("UPDATE", "U");
6770
commands.put("LOADSPRITESHEET", "L");
71+
commands.put("WORLDUPDATE", "W");
72+
73+
separators = new HashMap<>();
74+
separators.put("COMMAND", ";");
75+
separators.put("COMMAND_ARGUMENT", " ");
76+
separators.put("ARGUMENT_DETAILS", ",");
77+
separators.put("COMMAND_TYPE", "\n");
6878

6979
curves = new HashMap<>();
7080
curves.put(Curve.NONE, "_");
@@ -89,6 +99,9 @@ class Serializer {
8999
if (commands.values().stream().distinct().count() != commands.values().size()) {
90100
throw new RuntimeException("Duplicate commands");
91101
}
102+
if (separators.values().stream().distinct().count() != separators.values().size()) {
103+
throw new RuntimeException("Duplicate separators");
104+
}
92105
if (types.values().stream().distinct().count() != types.values().size()) {
93106
throw new RuntimeException("Duplicate types");
94107
}
@@ -98,6 +111,14 @@ class Serializer {
98111
if (keys.values().stream().anyMatch(character -> curves.containsValue(character))) {
99112
throw new RuntimeException("Same string used for a curve and a property");
100113
}
114+
if (separators.values().stream().anyMatch(
115+
character -> curves.containsValue(character) ||
116+
keys.containsValue(character) ||
117+
types.containsValue(character) ||
118+
commands.containsValue(character)
119+
)) {
120+
throw new RuntimeException("String already used as separator");
121+
}
101122

102123
}
103124

@@ -120,11 +141,16 @@ static String escape(String text) {
120141
return escaped;
121142
}
122143

123-
public String serializeEntitiesStateDiff(Entity<?> entity, EntityState diff, String frameInstant) {
124-
return join(
125-
commands.get("UPDATE"),
144+
private String serializeEntitiesStateDiff(Entity<?> entity, EntityState diff, String frameInstant) {
145+
String meta = join(
126146
entity.getId(),
127-
frameInstant,
147+
frameInstant
148+
);
149+
if (diff.isEmpty()) {
150+
return meta;
151+
}
152+
return join(
153+
meta,
128154
minifyDiff(diff)
129155
);
130156
}
@@ -156,22 +182,94 @@ private String minifyKey(String key) {
156182
private String minifyDiff(EntityState diff) {
157183
return diff.entrySet().stream()
158184
.map((entry) -> join(minifyKey(entry.getKey()), minifyParam(entry.getKey(), entry.getValue())))
159-
.collect(Collectors.joining(" "));
185+
.collect(Collectors.joining(separators.get("COMMAND_ARGUMENT")));
160186
}
161187

162-
public String serializeCreateEntity(Entity<?> e) {
188+
private String serializeCreateEntity(Entity<?> e) {
163189
return join(
164-
commands.get("CREATE"),
165190
types.get(e.getType())
166191
);
167192
}
168193

169-
public Object serializeLoadSpriteSheet(SpriteSheetLoader spriteSheet) {
194+
public Optional<String> serializeCreateEntities(List<Entity<?>> entities) {
195+
if (entities.isEmpty()) {
196+
return Optional.empty();
197+
} else {
198+
return Optional.of(
199+
commands.get("CREATE") + entities.stream()
200+
.map(e -> serializeCreateEntity(e))
201+
.collect(Collectors.joining(separators.get("COMMAND")))
202+
);
203+
}
204+
}
205+
206+
private String serializeLoadSpriteSheet(SpriteSheetLoader spriteSheet) {
170207
return join(
171-
commands.get("LOADSPRITESHEET"), spriteSheet.getName(), spriteSheet.getSourceImage(),
208+
spriteSheet.getName(), spriteSheet.getSourceImage(),
172209
spriteSheet.getWidth(), spriteSheet.getHeight(), spriteSheet.getOrigRow(), spriteSheet.getOrigCol(), spriteSheet.getImageCount(),
173210
spriteSheet.getImagesPerRow()
174211
);
175212
}
176213

214+
public Optional<String> serializeLoadSpriteSheets(List<SpriteSheetLoader> spriteSheets) {
215+
if (spriteSheets.isEmpty()) {
216+
return Optional.empty();
217+
} else {
218+
return Optional.of(
219+
commands.get("LOADSPRITESHEET") + spriteSheets.stream()
220+
.map(e -> serializeLoadSpriteSheet(e))
221+
.collect(Collectors.joining(separators.get("COMMAND")))
222+
);
223+
}
224+
}
225+
226+
public Optional<String> serializeWorldStateUpdates(List<String> worldUpdates) {
227+
if (worldUpdates.isEmpty()) {
228+
return Optional.empty();
229+
} else {
230+
return Optional.of(
231+
commands.get("WORLDUPDATE") +
232+
worldUpdates.stream()
233+
.collect(Collectors.joining(separators.get("COMMAND_ARGUMENT")))
234+
);
235+
}
236+
}
237+
238+
public Optional<String> serializeWorldDiff(List<WorldState> diffs) {
239+
if (diffs.isEmpty()) {
240+
return Optional.empty();
241+
} else {
242+
List<String> serialized = diffs.stream()
243+
.map(worldDiff -> {
244+
Optional<String> result;
245+
Set<Entry<Entity<?>, EntityState>> diff = worldDiff.getEntityStateMap().entrySet();
246+
if (diff.isEmpty()) {
247+
result = Optional.empty();
248+
} else {
249+
result = Optional.of(
250+
diff
251+
.stream()
252+
.map(e -> {
253+
return serializeEntitiesStateDiff(e.getKey(), e.getValue(), worldDiff.getFrameTime());
254+
})
255+
.collect(Collectors.joining(separators.get("COMMAND")))
256+
);
257+
}
258+
return result;
259+
})
260+
.filter(Optional::isPresent)
261+
.map(Optional::get)
262+
.collect(Collectors.toList());
263+
if (serialized.isEmpty()) {
264+
return Optional.empty();
265+
} else {
266+
return Optional.of(
267+
commands.get("UPDATE") + serialized
268+
.stream()
269+
.collect(Collectors.joining(separators.get("COMMAND")))
270+
);
271+
}
272+
}
273+
}
274+
177275
}

0 commit comments

Comments
 (0)