Skip to content

Commit 2dbe917

Browse files
committed
Fix screenshot onSwitchClick is taken before the game had time to rerender
1 parent 40987d9 commit 2dbe917

File tree

6 files changed

+38
-22
lines changed

6 files changed

+38
-22
lines changed

app/gameConfig.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
"researchInfo": REVERSIM_STATIC_URL + "/researchInfo/researchInfo.html"
4444
}
4545

46+
# Used by the screenshot tool to decide which format to decode
47+
BASE64_PREAMBLE = 'data:image/png;base64,'
48+
SCREENSHOT_EXTENSION = '.png'
49+
4650
class GroupNotFound(Exception):
4751
"""Raised when a group is requested, which is not in the config"""
4852
pass

app/router/routerGame.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from werkzeug import Response
99
from markupsafe import escape
1010

11-
from app.gameConfig import BACK_ONLINE_THRESHOLD_S, LOGFILE_VERSION, GroupNotFound
11+
from app.gameConfig import BACK_ONLINE_THRESHOLD_S, BASE64_PREAMBLE, LOGFILE_VERSION, GroupNotFound
1212
from app.model.Participant import Participant
1313

1414
import app.config as gameConfig
@@ -228,15 +228,18 @@ def saveCanvasImage():
228228
The Request params must contain the pseudonym of the player. The request body shall contain the Base64 encoded PNG snapshot of the players canvas.
229229
The pictures are stored under "statistics/<ui>/<phase>/<picNmbr>.png" for most phases and "statistics/<ui>/<phase>/<levelName>/<picNmbr>.png" for the quali and competition phase
230230
"""
231-
imgstring = escape(request.form['canvasImage'])
232-
imgstring = imgstring.replace('data:image/png;base64,', '')
233-
imgdata = base64.b64decode(imgstring)
234231

235232
pseudonym = sanitizeString(request.form['pseudonym'])
236-
237233
if not participantsDict.exists(pseudonym):
238234
return 'Invalid pseudonym', 400
239235

236+
imgstring = escape(request.form['canvasImage'])
237+
if not imgstring.startswith(BASE64_PREAMBLE):
238+
return 'Invalid Image', 400
239+
240+
imgstring = imgstring.removeprefix(BASE64_PREAMBLE)
241+
imgdata = base64.b64decode(imgstring)
242+
240243
participant = participantsDict.get(pseudonym)
241244
phase = participant.getPhase()
242245
path = ScreenshotWriter.getPath(

app/storage/participantScreenshots.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
from typing import Optional
44

5+
from app.gameConfig import SCREENSHOT_EXTENSION
56
from app.utilsGame import safe_join
67

78
class ScreenshotWriter:
@@ -40,7 +41,7 @@ def writeScreenshot(cls, screenshotFolder: str, picNmbr: int, imgData: bytes):
4041
imagePath: Optional[str] = None
4142

4243
for i in range(0, 99):
43-
imagePath = safe_join(screenshotFolder, str(picNmbr + i) + '.png')
44+
imagePath = safe_join(screenshotFolder, str(picNmbr + i) + SCREENSHOT_EXTENSION)
4445

4546
# If filename already exists, continue to increment
4647
if os.path.exists(imagePath):

static/src/createLogs/LogData.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,31 @@ class LogData
2929

3030
/**
3131
* Take a screenshot of the current canvas (this will not include any HTML overlays) and send it to the server.
32+
* @param {Phaser.Scene} scene
3233
*/
33-
static sendCanvasPNG()
34+
static sendCanvasPNG(scene)
3435
{
36+
const IMAGE_FORMAT = 'image/png';
37+
const IMAGE_QUALITY = 0.8; // Only relevant for jpeg
38+
3539
if(!gamerules.enableLogging)
3640
return "Logging is disabled"
3741

3842
// get canvas as image
39-
var htmlCollection = document.getElementsByTagName('canvas');
40-
var canvas = htmlCollection[0];
41-
var imgData = canvas.toDataURL("image/png", 1.0);
42-
43-
let data = {
44-
canvasImage: imgData,
45-
'pseudonym': pseudonym,
46-
'timeStamp': Rq.now()
47-
};
43+
scene.renderer.snapshot((snapshot) => {
44+
if(!(snapshot instanceof HTMLImageElement))
45+
{
46+
console.error('snapshot was not of type HTMLImageElement');
47+
return;
48+
}
49+
50+
let data = {
51+
canvasImage: snapshot.src,
52+
'pseudonym': pseudonym,
53+
'timeStamp': Rq.now()
54+
};
4855

49-
Rq.post('/canvasImage', () => {}, data, "application/x-www-form-urlencoded; charset=UTF-8");
56+
Rq.post('/canvasImage', () => {}, data, "application/x-www-form-urlencoded; charset=UTF-8");
57+
}, IMAGE_FORMAT, IMAGE_QUALITY);
5058
}
51-
}
59+
}

static/src/extras/CanvasDrawing.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,19 @@ class CanvasDrawing
8787
if(this.justPaintedSomething == true)
8888
{
8989
//alert('dude, you painted something');
90-
LogData.sendCanvasPNG();
90+
LogData.sendCanvasPNG(this.scene);
9191
JsonRPC.send("draw", {"tool": "pen", "info": this.drawLine.fillColor})
9292
this.justPaintedSomething = false;
9393
} else if(this.erasedSomething == true)
9494
{
9595
//alert('you erased something');
96-
LogData.sendCanvasPNG();
96+
LogData.sendCanvasPNG(this.scene);
9797
JsonRPC.send("draw", {"tool": "eraser"})
9898
this.erasedSomething = false;
9999
} else if(this.deletedEverything == true)
100100
{
101101
//alert('you deleted everything')
102-
LogData.sendCanvasPNG();
102+
LogData.sendCanvasPNG(this.scene);
103103
JsonRPC.send("draw", {"tool": "purge"})
104104
this.deletedEverything = false;
105105
}

static/src/scenes/GameScene.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ class GameScene extends BaseScene
558558
JsonRPC.send("switch", levelState);
559559

560560
// send screenshot
561-
LogData.sendCanvasPNG();
561+
LogData.sendCanvasPNG(this);
562562

563563
// Update the scoreboard
564564
this.updateScore('switchClick');

0 commit comments

Comments
 (0)