summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-01-01 17:36:56 +0100
committerTor Andersson <tor@ccxvii.net>2024-01-28 13:50:27 +0100
commita1c93c992e456764415b5a4c302e1137673c0a5f (patch)
treeaae79b1ce9c085e66f5ecf4022a2ea93cc07b92e
parent12a2a48e5e1158e1fcbed03862ab17e2869c09e4 (diff)
downloadserver-a1c93c992e456764415b5a4c302e1137673c0a5f.tar.gz
Add time control enforcement.
-rw-r--r--schema.sql45
-rw-r--r--server.js33
-rw-r--r--views/head.pug6
3 files changed, 77 insertions, 7 deletions
diff --git a/schema.sql b/schema.sql
index 02b9dff..516fe28 100644
--- a/schema.sql
+++ b/schema.sql
@@ -482,17 +482,53 @@ create view player_view as
is_invite,
(
case status
- when 0 then owner_id = user_id
- when 1 then active in ( 'Both', role )
- else 0
+ when 0 then
+ owner_id = user_id
+ when 1 then
+ active in ( 'Both', role )
+ else
+ 0
end
- ) as is_active
+ ) as is_active,
+ (
+ case when pace = 0 then
+ 21.0 - (julianday() - julianday(mtime))
+ else
+ case when active in ( 'Both', role ) then
+ 10.0 - ((julianday() - julianday(mtime)) + time_used - time_added)
+ else
+ 10.0 - (time_used - time_added)
+ end
+ end
+ ) as time_left
from
games
join players using(game_id)
join users using(user_id)
;
+drop view if exists time_control_view;
+create view time_control_view as
+ select
+ game_id,
+ user_id,
+ role,
+ (
+ case when pace = 0 then
+ 21.0 - (julianday() - julianday(mtime))
+ else
+ 10.0 - ((julianday() - julianday(mtime)) + time_used - time_added)
+ end
+ ) as time_left,
+ is_opposed
+ from
+ games
+ join players using(game_id)
+ where
+ status = 1
+ and active in ( 'Both', role )
+ ;
+
drop view if exists your_turn_reminder;
create view your_turn_reminder as
select
@@ -584,7 +620,6 @@ begin
delete from game_notes where game_id = old.game_id;
delete from last_notified where game_id = old.game_id;
delete from unread_chats where game_id = old.game_id;
- update players set time_added = null where game_id = old.game_id;
end;
-- Triggers to clean up without relying on foreign key cascades
diff --git a/server.js b/server.js
index 620fd58..71972d4 100644
--- a/server.js
+++ b/server.js
@@ -1183,7 +1183,8 @@ function is_game_ready(player_count, players) {
load_rules()
const SQL_INSERT_GAME = SQL("INSERT INTO games (owner_id,title_id,scenario,options,player_count,pace,is_private,is_random,notice,is_match) VALUES (?,?,?,?,?,?,?,?,?,?) returning game_id").pluck()
-const SQL_DELETE_GAME = SQL("DELETE FROM games WHERE game_id=? AND owner_id=?")
+const SQL_DELETE_GAME_BY_OWNER = SQL("delete from games where game_id=? and owner_id=?")
+const SQL_DELETE_GAME = SQL("delete from games where game_id=?")
const SQL_START_GAME = SQL(`
update games set
@@ -1430,6 +1431,7 @@ function annotate_game_info(game, user_id, unread) {
let your_count = 0
let your_role = null
+ let time_left = Infinity
let roles = get_game_roles(game.title_id, game.scenario, options)
@@ -1449,6 +1451,9 @@ function annotate_game_info(game, user_id, unread) {
game.your_turn = true
}
+ if (p.is_active)
+ time_left = Math.min(time_left, p.time_left)
+
let link
if (p.is_invite)
link = `<a class="is_invite" href="/user/${p.name}">${p.name}?</a>`
@@ -1475,6 +1480,9 @@ function annotate_game_info(game, user_id, unread) {
}).join(", ")
}
+ if (game.is_ready && game.status === 1)
+ game.time_left = time_left
+
if (your_count > 0) {
game.is_yours = true
if (your_count === 1)
@@ -1675,7 +1683,7 @@ app.post("/create/:title_id", must_be_logged_in, function (req, res) {
app.get("/delete/:game_id", must_be_logged_in, function (req, res) {
let game_id = req.params.game_id
let title_id = SQL_SELECT_GAME_TITLE.get(game_id)
- let info = SQL_DELETE_GAME.run(game_id, req.user.user_id)
+ let info = SQL_DELETE_GAME_BY_OWNER.run(game_id, req.user.user_id)
if (info.changes === 0)
return res.send("Not authorized to delete that game ID.")
if (info.changes === 1)
@@ -2444,6 +2452,27 @@ setInterval(purge_game_ticker, 31 * 60 * 1000)
setTimeout(purge_game_ticker, 89 * 1000)
/*
+ * TIME CONTROL
+ */
+
+const QUERY_LIST_TIME_CONTROL = SQL("select * from time_control_view join users using(user_id) where time_left < 0")
+
+function time_control_ticker() {
+ for (let item of QUERY_LIST_TIME_CONTROL.all()) {
+ if (item.is_opposed) {
+ console.log("TIMED OUT GAME:", item.game_id, item.name, item.time_left)
+ do_resign(item.game_id, item.role, "timed out")
+ } else {
+ SQL_DELETE_GAME.run(item.game_id)
+ }
+ }
+}
+
+// Run time control checks every 13 minutes.
+setInterval(time_control_ticker, 13 * 60 * 1000)
+setTimeout(time_control_ticker, 13 * 1000)
+
+/*
* GAME SERVER
*/
diff --git a/views/head.pug b/views/head.pug
index e47033a..5cbb726 100644
--- a/views/head.pug
+++ b/views/head.pug
@@ -118,6 +118,12 @@ mixin gamelist(list,hide_title=0)
div Created: #{item.ctime}
when 1
div Last move: #{item.mtime}
+ if item.time_left <= 0
+ div Time left: none.
+ else if item.time_left <= 2
+ div Time left: #{ item.time_left * 24 | 0 } hours
+ else if item.time_left <= 5
+ div Time left: #{ item.time_left | 0 } days
when 2
div Finished: #{item.mtime}
div Result: !{item.result}