forked from Maxdamantus/recplay
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecHandler.js
114 lines (103 loc) · 5.53 KB
/
recHandler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
var fs = require("fs");
const path = require('path');
const { Replay, Frame } = require('elmajs');
const tempWrite = require('temp-write');
exports.handle = function(recUri, frameRate, outputUri, scale, levUri, level){
var replayBuffer = fs.readFileSync(recUri);
var replay = Replay.from(replayBuffer);
var keptFrameRatio = frameRate/30.0; // 30 fps is default frameRate
var frameStep = Math.round( 1/keptFrameRatio ); // if keptFrameRatio is 0.5 then this value will be 2, since 1 in two frames will remain
var frameMultiplier = Math.round( keptFrameRatio );
var player1 = replay.rides[0]; // the first player in replay
var framesBefore = player1.frames.length;
if (frameStep > 1) console.log("Capturing framerate: ~" + parseInt(30/frameStep) + ": 1 in " +frameStep+ " (approximated from option -C " +frameRate+ ")");
else if (frameMultiplier > 1) console.log("Capturing framerate: " + (30*frameMultiplier) + " (approximated from option -C " +frameRate+ ")");
if ( frameStep > 1 ) replay.rides[0].frames = player1.frames.filter(function(frame, i){
// reduce frames
return i % frameStep == 0;
});
else if ( frameMultiplier > 1 )
{
// todo: bug: interpolated frames are not rendered properly: x, y seems to be jumping
// todo: when finding edges, interpolated frames do not need to be checked
var newFrames = [];
for (var i=0; i<player1.frames.length; i++)
{
var frame = player1.frames[i];
if ( i < player1.frames.length - 1)
{
var nextFrame = player1.frames[i+1];
for (var extraFrame=1; extraFrame<=frameMultiplier-1; extraFrame++)
{
var newFrame = new Frame();
newFrame.bike.x = frame.bike.x + extraFrame * (nextFrame.bike.x - frame.bike.x)/frameMultiplier;
newFrame.bike.y = frame.bike.y + extraFrame * (nextFrame.bike.y - frame.bike.y)/frameMultiplier;
newFrame.leftWheel.x = frame.leftWheel.x + extraFrame * (nextFrame.leftWheel.x - frame.leftWheel.x)/frameMultiplier;
newFrame.leftWheel.y = frame.leftWheel.y + extraFrame * (nextFrame.leftWheel.y - frame.leftWheel.y)/frameMultiplier;
newFrame.rightWheel.x = frame.rightWheel.x + extraFrame * (nextFrame.rightWheel.x - frame.rightWheel.x)/frameMultiplier;
newFrame.rightWheel.y = frame.rightWheel.y + extraFrame * (nextFrame.rightWheel.y - frame.rightWheel.y)/frameMultiplier;
newFrame.head.x = frame.head.x + extraFrame * (nextFrame.head.x - frame.head.x)/frameMultiplier;
newFrame.head.y = frame.head.y + extraFrame * (nextFrame.head.y - frame.head.y)/frameMultiplier;
// bike rotation can jump from around 0 to around 10000, making the in-between around 5000
if (nextFrame.bikeRotation - frame.bikeRotation < 1000 && nextFrame.bikeRotation - frame.bikeRotation > -1000)
newFrame.bikeRotation = frame.bikeRotation + extraFrame * (nextFrame.bikeRotation - frame.bikeRotation)/frameMultiplier;
// so don't interpolate rotation for those frames
else newFrame.bikeRotation = frame.bikeRotation;
// similar to bike rotation, though rec files use a smaller constant for converting the values to coordinates
if (nextFrame.leftWheelRotation - frame.leftWheelRotation < 150 && nextFrame.leftWheelRotation - frame.leftWheelRotation > -150)
newFrame.leftWheelRotation = frame.leftWheelRotation + extraFrame * (nextFrame.leftWheelRotation - frame.leftWheelRotation)/frameMultiplier;
else newFrame.leftWheelRotation = frame.leftWheelRotation;
if (nextFrame.rightWheelRotation - frame.rightWheelRotation < 150 && nextFrame.rightWheelRotation - frame.rightWheelRotation > -150)
newFrame.rightWheelRotation = frame.rightWheelRotation + extraFrame * (nextFrame.rightWheelRotation - frame.rightWheelRotation)/frameMultiplier;
else newFrame.rightWheelRotation = frame.rightWheelRotation;
newFrame.backWheelSpeed = frame.backWheelSpeed;// + extraFrame * (nextFrame.backWheelSpeed - frame.backWheelSpeed)/frameMultiplier
newFrame.collisionStrength = frame.collisionStrength;// + extraFrame * (nextFrame.collisionStrength - frame.collisionStrength)/frameMultiplier
newFrame.throttleAndDirection = frame.throttleAndDirection;
newFrames.push(newFrame);
}
}
newFrames.push(frame);
}
replay.rides[0].frames = newFrames;
}
//console.log( replay.rides[0].frames[93].bikeRotation );
var frameRateRatio = replay.rides[0].frames.length / framesBefore;
// update events according to new framerate
for (i=0; i<player1.events.length; i++)
{
replay.rides[0].events[i].time *= frameRateRatio;
}
if (!outputUri || !outputUri.endsWith('.rec'))
{
var recPath = tempWrite.sync('recpath');
var _recUri = tempWrite.sync('recpath', 'rec.rec');
}
else _recUri = outputUri;
if ( scale && scale != 1.0 )
{
for (i=0; i<replay.rides[0].frames.length; i++)
{
var frame = replay.rides[0].frames[i];
frame.bike.x *= scale;
frame.bike.y *= scale;
frame.leftWheel.x *= scale;
frame.leftWheel.y *= scale;
frame.rightWheel.x *= scale;
frame.rightWheel.y *= scale;
frame.head.x *= scale;
frame.head.y *= scale;
replay.rides[0].frames[i] = frame;
}
}
if (levUri && level)
{
// if a level uri and filename are provided, make the written rec linked to that level
replay.level = path.parse(levUri).base;
replay.link = level.link;
//console.log(replay, level);
}
fs.writeFileSync(_recUri, replay.toBuffer());
if (outputUri.endsWith('.rec')) console.log( "Wrote " + outputUri + ": " + replay.rides[0].frames.length + " frames");
return fs.readFileSync(_recUri, 'binary'); // return changed rec
//return fs.readFileSync(recUri, 'binary'); // return original rec, as before this was created
}