-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathp2p_rollback.zig
More file actions
56 lines (49 loc) · 2.17 KB
/
Copy pathp2p_rollback.zig
File metadata and controls
56 lines (49 loc) · 2.17 KB
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
//! p2p_rollback - GGPO-style peer-to-peer. Each peer advances every tick on its own
//! input plus a *prediction* of the remote's (repeat-the-last). When the real remote
//! input arrives a few ticks late and differs, the peer rolls back to that tick and
//! replays. Both peers converge on the exact same state.
const std = @import("std");
const magnet = @import("magnet");
const Fixed = magnet.core.Fixed(i64, 16);
const Game = struct { x: [2]i64 }; // two players' positions, Q16.16
const Input = struct { dir: i8 }; // -1 / 0 / +1
fn step(s: Game, in: [2]Input) Game {
var out = s;
const quarter = Fixed.fromRatio(1, 4);
inline for (0..2) |p| {
out.x[p] = (Fixed{ .raw = out.x[p] }).add(quarter.scaleInt(in[p].dir)).raw;
}
return out;
}
const P2p = magnet.replication.P2p(Game, Input, step, 256);
pub fn main() void {
var a: P2p = undefined;
a.init(0, .{ .x = .{ 0, 0 } }); // peer A is player 0
var b: P2p = undefined;
b.init(1, .{ .x = .{ 0, 0 } }); // peer B is player 1
var p0: [160]Input = undefined; // what each player actually pressed
var p1: [160]Input = undefined;
var rng = std.Random.DefaultPrng.init(0x6262);
for (&p0, &p1) |*x, *y| {
x.* = .{ .dir = rng.random().intRangeAtMost(i8, -1, 1) };
y.* = .{ .dir = rng.random().intRangeAtMost(i8, -1, 1) };
}
const latency: u32 = 4;
var t: u32 = 1;
while (t <= 150) : (t += 1) {
_ = a.advance(p0[t]); // A advances on its own input, predicting player 1
_ = b.advance(p1[t]); // B likewise, predicting player 0
if (t > latency) {
_ = a.confirmRemote(t - latency, p1[t - latency]); // the truth arrives late
_ = b.confirmRemote(t - latency, p0[t - latency]);
}
}
for (0..latency) |i| { // drain the last in-flight confirmations
const past = 150 - latency + 1 + @as(u32, @intCast(i));
_ = a.confirmRemote(past, p1[past]);
_ = b.confirmRemote(past, p0[past]);
}
std.debug.print("p2p_rollback: A rolled back {d}×, B {d}×; peers converged = {}\n", .{
a.rollbacks, b.rollbacks, a.present.x[0] == b.present.x[0] and a.present.x[1] == b.present.x[1],
});
}