summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2025-04-26 00:24:05 +0200
committerTor Andersson <tor@ccxvii.net>2025-04-26 01:26:58 +0200
commit5a6f89fe9760ff2a688d29ac5ca3bb3f28c9216f (patch)
tree26ac26aa2099c4557ae1a023e061cdfb585b4056
parent7bcfc5845b9bfee93586f6823a0dcd3c843d0471 (diff)
downloadserver-5a6f89fe9760ff2a688d29ac5ca3bb3f28c9216f.tar.gz
Improve rtt-patch command line parsing.
Also patch starting from a snapshot if requested.
-rwxr-xr-xbin/rtt-patch116
-rwxr-xr-xbin/rtt-undo2
2 files changed, 89 insertions, 29 deletions
diff --git a/bin/rtt-patch b/bin/rtt-patch
index 19e9874..ec0b795 100755
--- a/bin/rtt-patch
+++ b/bin/rtt-patch
@@ -7,12 +7,15 @@ let db = new sqlite3("db")
let select_game = db.prepare("select * from games where game_id=?")
let select_replay = db.prepare("select * from game_replay where game_id=?")
-let delete_replay = db.prepare("delete from game_replay where game_id=?")
+let delete_replay = db.prepare("delete from game_replay where game_id=? and replay_id>?")
let insert_replay = db.prepare("insert into game_replay (game_id,replay_id,role,action,arguments) values (?,?,?,?,?)")
-let delete_snap = db.prepare("delete from game_snap where game_id=?")
+let select_last_snap = db.prepare("select max(snap_id) from game_snap where game_id=?").pluck()
+let select_snap = db.prepare("select * from game_snap where game_id=? and snap_id=?")
+let delete_snap = db.prepare("delete from game_snap where game_id=? and snap_id>?")
let insert_snap = db.prepare("insert into game_snap(game_id,snap_id,replay_id,state) values (?,?,?,?)")
+let select_state = db.prepare("select state from game_state where game_id=?").pluck()
let update_state = db.prepare("update game_state set state=? where game_id=?")
let update_active = db.prepare("update games set active=? where game_id=?")
@@ -147,7 +150,7 @@ function finish_game(rules, state, result, message) {
return state
}
-function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_undo=false, delete_invalid=false}, verbose) {
+function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_undo=false, delete_invalid=false}, verbose, start_snap_id=0) {
let game = select_game.get(game_id)
if (!game) {
console.error("game not found:", game_id)
@@ -162,16 +165,46 @@ function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_und
if (replay.length === 0)
return
- console.log("processing", game_id, title_id)
+ let skip_replay_id = 0
+ let state = null
+
+ if (start_snap_id < 0) {
+ start_snap_id = select_last_snap.get(game_id) + start_snap_id + 1
+ if (start_snap_id < 1) {
+ console.error("snap not found:", start_snap_id)
+ return
+ }
+ }
+
+ if (start_snap_id > 0) {
+ let last_state = JSON.parse(select_state.get(game_id))
+ let last_snap = select_snap.get(game_id, start_snap_id)
+ if (!last_snap) {
+ console.error("snap not found:", start_snap_id)
+ return
+ }
+ skip_replay_id = last_snap.replay_id
+ state = JSON.parse(last_snap.state)
+ state.undo = []
+ state.log = last_state.log.slice(0, state.log)
+ console.log("processing", game_id, title_id, "from snapshot", start_snap_id)
+ } else {
+ console.log("processing", game_id, title_id)
+ }
try {
- let state = null
let old_active = null
let need_to_rewrite = false
for (let i = 0; i < replay.length; ++i) {
let item = replay[i]
+ if (item.replay_id <= skip_replay_id) {
+ if (verbose)
+ console.log("skipped:", item.replay_id, item.role, item.action, item.arguments)
+ continue
+ }
+
if (verbose)
console.log(item.replay_id, item.role, item.action, item.arguments)
@@ -192,7 +225,7 @@ function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_und
if (validate_actions) {
if (!is_valid_action(rules, state, item.role, item.action, args)) {
console.error(`invalid action: ${item.role} ${item.action} ${item.arguments}`)
- console.error("\t", state.state, state.active, JSON.stringify(rules.view(state, item.role).actions))
+ console.error("\t", JSON.stringify(rules.view(state, item.role).actions))
if (i < replay.length) {
console.log("BROKEN ENTRIES: %d", replay.length-i)
console.log(`sqlite3 db "delete from game_replay where game_id=${game_id} and replay_id>=${replay[i].replay_id}"`)
@@ -227,15 +260,15 @@ function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_und
db.exec("begin")
if (need_to_rewrite) {
- delete_replay.run(game_id)
+ delete_replay.run(game_id, skip_replay_id)
for (item of replay)
if (!item.remove)
insert_replay.run(game_id, item.replay_id, item.role, item.action, item.arguments)
}
if (save_snaps) {
- delete_snap.run(game_id)
- let snap_id = 0
+ delete_snap.run(game_id, start_snap_id)
+ let snap_id = start_snap_id
for (item of replay)
if (item.save)
insert_snap.run(game_id, ++snap_id, item.replay_id, item.state)
@@ -256,36 +289,63 @@ function patch_game(game_id, {validate_actions=true, save_snaps=true, delete_und
console.error("ERROR", game_id, title_id, err)
if (delete_invalid) {
delete_replay.run(game_id)
- delete_snap.run(game_id)
+ delete_snap.run(game_id, 0)
}
}
}
function patch_all(options) {
for (let game_id of db.prepare("select game_id from games where status=1").pluck().all())
- patch_game(game_id, options, false)
+ patch_game(game_id, options, false, 0)
}
function patch_title(title_id, options) {
for (let game_id of db.prepare("select game_id from games where status=1 and title_id=?").pluck().all(title_id))
- patch_game(game_id, options, false)
+ patch_game(game_id, options, false, 0)
}
-if (process.argv.length < 3) {
- process.stderr.write("usage: rtt-patch <game_id> '{options}'\n")
- process.stderr.write(" or: rtt-patch <title_id> '{options}'\n")
- process.stderr.write(" or: rtt-patch all '{options}'\n")
- process.stderr.write('options: { "validate_actions":true, "delete_invalid":false, "save_snaps":true, "delete_undo":false }\n')
- process.exit(1)
-}
+function main(all_args) {
+ var opt_args = all_args.filter(arg => arg[0] === "-" && isNaN(arg))
+ var args = all_args.filter(arg => arg[0] !== "-" || !isNaN(arg))
+
+ if (args < 1) {
+ console.error("usage: rtt-patch ( GAME [ SNAP ] | TITLE | all ) [ options... ]")
+ console.error("\t-no-validate")
+ console.error("\t-no-snaps")
+ console.error("\t-delete-undo")
+ console.error("\t-delete-invalid")
+ process.exit(1)
+ }
+
+ var options = {
+ validate_actions: true,
+ save_snaps: true,
+ delete_undo: false,
+ delete_invalid: false
+ }
+
+ for (var opt of opt_args) {
+ if (opt === "-no-validate") options.validate_actions = false
+ else if (opt === "-no-snaps") options.save_snaps = false
+ else if (opt === "-delete-undo") options.delete_undo = true
+ else if (opt === "-delete-invalid") options.delete_invalid = true
+ else {
+ console.error("invalid option:", opt)
+ process.exit(1)
+ }
+ }
-let options = {}
-if (process.argv.length === 4)
- options = JSON.parse(process.argv[3])
+ var what = args.shift()
+ if (what === "all") {
+ patch_all(options)
+ } else if (isNaN(what)) {
+ patch_title(what, options)
+ } else {
+ var snap_id = 0
+ if (args.length > 0)
+ snap_id = parseInt(args.shift())
+ patch_game(parseInt(what), options, true, snap_id)
+ }
+}
-if (process.argv[2] === 'all')
- patch_all(options)
-else if (isNaN(process.argv[2]))
- patch_title(process.argv[2], options)
-else
- patch_game(parseInt(process.argv[2]), options, true)
+main(process.argv.slice(2))
diff --git a/bin/rtt-undo b/bin/rtt-undo
index 2f69eed..ae375f9 100755
--- a/bin/rtt-undo
+++ b/bin/rtt-undo
@@ -9,7 +9,7 @@ then
echo Game has $COUNT actions.
fi
sqlite3 db "delete from game_replay where game_id=$1 and replay_id>=$COUNT"
- ./bin/rtt-patch $1 '{"validate_actions":false}'
+ ./bin/rtt-patch $1 -no-validate
else
echo "usage: rtt-undo GAME"
fi