summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-01-31 02:28:28 +0100
committerTor Andersson <tor@ccxvii.net>2024-02-12 21:50:53 +0100
commit09cae5d2f687c7df4972f58860fbc3fb9a032c1c (patch)
treea4b1a5a00260a1a7974c64e3ec2a6991d9491dca
parent4429af4150307588409940398ef1ef49371ececa (diff)
downloadserver-09cae5d2f687c7df4972f58860fbc3fb9a032c1c.tar.gz
Add rewind action on join page (for admin only).
-rw-r--r--server.js54
-rw-r--r--views/join.pug6
2 files changed, 56 insertions, 4 deletions
diff --git a/server.js b/server.js
index 98444f1..93a1971 100644
--- a/server.js
+++ b/server.js
@@ -1206,6 +1206,7 @@ const SQL_FINISH_GAME = SQL(`
game_id = ?
`)
+const SQL_REOPEN_GAME = SQL("update games set status=1,active=? where game_id=?")
const SQL_UPDATE_GAME_ACTIVE = SQL("update games set active=?,mtime=datetime(),moves=moves+1 where game_id=?")
const SQL_UPDATE_GAME_SCENARIO = SQL("update games set scenario=? where game_id=?")
@@ -1234,9 +1235,15 @@ const SQL_UPDATE_PLAYERS_ADD_TIME = SQL(`
const SQL_INSERT_REPLAY = SQL("insert into game_replay (game_id,replay_id,role,action,arguments) values (?, (select coalesce(max(replay_id), 0) + 1 from game_replay where game_id=?) ,?,?,?) returning replay_id").pluck()
const SQL_INSERT_SNAP = SQL("insert into game_snap (game_id,snap_id,replay_id,state) values (?, (select coalesce(max(snap_id), 0) + 1 from game_snap where game_id=?), ?, ?) returning snap_id").pluck()
-const SQL_SELECT_SNAP = SQL("select state from game_snap where game_id = ? and snap_id = ?").pluck()
+const SQL_SELECT_SNAP = SQL("select * from game_snap where game_id = ? and snap_id = ?")
+const SQL_SELECT_SNAP_STATE = SQL("select state from game_snap where game_id = ? and snap_id = ?").pluck()
const SQL_SELECT_SNAP_COUNT = SQL("select max(snap_id) from game_snap where game_id=?").pluck()
+const SQL_SELECT_LAST_SNAP = SQL("select * from game_snap where game_id = ? order by snap_id desc limit 1")
+
+const SQL_DELETE_GAME_SNAP = SQL("delete from game_snap where game_id=? and snap_id > ?")
+const SQL_DELETE_GAME_REPLAY = SQL("delete from game_replay where game_id=? and replay_id > ?")
+
const SQL_SELECT_REPLAY = SQL(`
select json_object(
'title', title_id,
@@ -1827,12 +1834,15 @@ app.get("/join/:game_id", function (req, res) {
let whitelist = null
let blacklist = null
let friends = null
+ let rewind = 0
if (req.user) {
whitelist = SQL_SELECT_CONTACT_WHITELIST.all(req.user.user_id)
blacklist = SQL_SELECT_CONTACT_BLACKLIST.all(req.user.user_id)
if (game.owner_id === req.user.user_id)
friends = SQL_SELECT_CONTACT_FRIEND_NAMES.all(req.user.user_id)
+ if (req.user.user_id === 1)
+ rewind = SQL_SELECT_SNAP_COUNT.get(game_id)
}
let ready = (game.status === STATUS_OPEN) && is_game_ready(game.player_count, players)
@@ -1848,6 +1858,7 @@ app.get("/join/:game_id", function (req, res) {
blacklist,
friends,
limit: req.user ? check_join_game_limit(req.user) : null,
+ rewind
})
})
@@ -2068,6 +2079,41 @@ app.get("/api/replay/:game_id", function (req, res) {
return res.send(SQL_SELECT_REPLAY.get({ game_id }))
})
+app.get("/admin/rewind/:game_id/:snap_id", must_be_administrator, function (req, res) {
+ let game_id = req.params.game_id | 0
+ let snap_id = req.params.snap_id | 0
+ let snap = SQL_SELECT_SNAP.get(game_id, snap_id)
+ let game_state = JSON.parse(SQL_SELECT_GAME_STATE.get(game_id))
+ let snap_state = JSON.parse(snap.state)
+ snap_state.undo = []
+ snap_state.log = game_state.log.slice(0, snap_state.log)
+
+ SQL_BEGIN.run()
+ try {
+ SQL_DELETE_GAME_SNAP.run(game_id, snap_id)
+ SQL_DELETE_GAME_REPLAY.run(game_id, snap.replay_id)
+ SQL_INSERT_GAME_STATE.run(game_id, JSON.stringify(snap_state))
+
+ SQL_REOPEN_GAME.run(snap_state.active, game_id)
+
+ if (snap_state.active !== game_state.active)
+ SQL_UPDATE_GAME_ACTIVE.run(snap_state.active, game_id)
+
+ update_join_clients_game(game_id)
+ if (game_clients[game_id])
+ for (let other of game_clients[game_id])
+ send_state(other, snap_state)
+
+ SQL_COMMIT.run()
+ } catch (err) {
+ return res.send(err.toString())
+ } finally {
+ if (db.inTransaction)
+ SQL_ROLLBACK.run()
+ }
+ res.redirect("/join/" + game_id)
+})
+
/*
* ELO RATINGS
*
@@ -2537,7 +2583,7 @@ function snap_from_state(state) {
function put_replay(game_id, role, action, args) {
if (args !== undefined && args !== null && typeof args !== "number")
args = JSON.stringify(args)
- return SQL_INSERT_REPLAY.run(game_id, game_id, role, action, args)
+ return SQL_INSERT_REPLAY.get(game_id, game_id, role, action, args)
}
function put_snap(game_id, replay_id, state) {
@@ -2712,7 +2758,7 @@ function on_query_snap(socket, snap_id, q, params) {
SLOG(socket, "QUERYSNAP", snap_id, JSON.stringify(params))
try {
if (socket.rules.query) {
- let state = JSON.parse(SQL_SELECT_SNAP.get(socket.game_id, snap_id))
+ let state = JSON.parse(SQL_SELECT_SNAP_STATE.get(socket.game_id, snap_id))
let reply = socket.rules.query(state, socket.role, q, params)
send_message(socket, "reply", [ q, reply ])
}
@@ -2793,7 +2839,7 @@ function send_chat_message(game_id, from_id, from_name, message) {
function on_snap(socket, snap_id) {
SLOG(socket, "SNAP", snap_id)
try {
- let snap_state = SQL_SELECT_SNAP.get(socket.game_id, snap_id)
+ let snap_state = SQL_SELECT_SNAP_STATE.get(socket.game_id, snap_id)
if (snap_state) {
let state = JSON.parse(snap_state)
let view = socket.rules.view(state, socket.role)
diff --git a/views/join.pug b/views/join.pug
index 37c245b..bfb0cb8 100644
--- a/views/join.pug
+++ b/views/join.pug
@@ -104,3 +104,9 @@ html
if !user && !ready
p <a href="/login">Login</a> or <a href="/signup">sign up</a> to play.
+
+ if user && user.user_id === 1
+ p
+ - for (let snap_id = rewind; snap_id > 0 && snap_id > rewind-5; --snap_id)
+ a(href="/admin/rewind/" + game.game_id + "/" + snap_id) REWIND #{snap_id}
+ br