Skip to content

Commit b65d810

Browse files
henke96Pazaz
andauthored
fix(engine): Rework logout behaviour (2004Scape#1281)
Source is a combination of memory, old discord channels, osrs testing and this video: https://youtu.be/2NJa6WoXlMk?t=116 Co-authored-by: henrik <> Co-authored-by: Pazaz <ItsPazaz@gmail.com>
1 parent 49d914d commit b65d810

19 files changed

Lines changed: 186 additions & 187 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[debugproc,antilog](int $duration)
2+
if (p_finduid(uid) = true) {
3+
p_preventlogout("Antilog test", $duration);
4+
}

data/src/scripts/_test/scripts/engine/debug_longqueue.rs2

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[debugproc,longqueue]
2+
longqueue(testqueueint, 100000, ^accelerate, 123);
3+
longqueue(testqueueint, 100000, ^discard, 456);
4+
longqueue(testqueuestr, 100000, ^accelerate, "accelerate ran");
5+
longqueue(testqueuestr, 100000, ^discard, "long discard ran (!)");
6+
longqueue(testqueuestr, 5, ^discard, "short discard ran");
7+
8+
[debugproc,queue](int $duration)
9+
queue(testqueueint, $duration, 123);
10+
queue(testqueuestr, $duration, "queue ran");
11+
12+
[queue,testqueueint](int $test)
13+
console("int: <tostring($test)>");
14+
15+
[queue,testqueuestr](string $msg)
16+
console("str: <$msg>");
17+
18+
// blocks safe logout!
19+
[debugproc,dangerous_requeue]
20+
queue(dangerous_requeue, 0);
21+
22+
[queue,dangerous_requeue]
23+
queue(dangerous_requeue, 0);

data/src/scripts/engine.rs2

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,11 @@
202202
// Get the player's UID to use in finduid/p_finduid later
203203
[command,uid]()(player_uid)
204204
[command,.uid]()(player_uid)
205-
// Requires protected access - request the player to log out
205+
// Request the player to log out
206206
[command,p_logout]
207-
// Check if the player is marked as "logged out" but not removed yet
208-
[command,loggedout]()(boolean)
207+
// Prevent logout for a duration
208+
[command,p_preventlogout](string $message, int $duration)
209+
[command,.p_preventlogout](string $message, int $duration)
209210
// Set a component's colour
210211
[command,if_setcolour](component $component, int $colour)
211212
// Open a modal in the chat box
Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
1+
// TODO: Change compiler to remove return value
12
[logout,_]()(boolean)
2-
if (busy = true) {
3-
return(false);
4-
}
5-
6-
// if not an engine logout, and the player was hit within the last 10s, don't logout
7-
if (loggedout = false & map_clock > 17 & add(%lastcombat, 17) > map_clock) {
8-
return(false);
9-
}
10-
11-
// logging out mid-trade, restore inv and cancel trade
12-
if (%tradepartner ! null) {
13-
~moveallinv(tempinv, inv);
14-
if (.finduid(%tradepartner) = true) {
15-
.if_close;
16-
}
17-
%tradepartner = null;
18-
}
193
~set_pk_skull_logout;
20-
~set_antifire_logout;
21-
~set_antipoison_logout;
4+
~set_antifire_logout; // TODO: should be timer
5+
~set_antipoison_logout; // TODO: should be timer
226
~set_cannon_vars_logout;
237
~follower_logout;
248
~rashiliyia_door_logout;
@@ -39,9 +23,5 @@ if (p_finduid(uid) = true) {
3923
return;
4024
}
4125

42-
if (map_clock > 17 & add(%lastcombat, 17) > map_clock) {
43-
mes("You can't logout until 10 seconds after the end of combat."); // todo: confirm this message for 2004
44-
return;
45-
}
4626
p_logout;
4727
}

data/src/scripts/skill_combat/scripts/npc/npc_combat.rs2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ if (inv_getobj(worn, ^wearpos_ring) = ring_of_recoil & npc_finduid(%aggressive_n
282282
npc_queue(2, $recoil_damage, 0);
283283
~ring_of_recoil_lose_charge($recoil_damage);
284284
}
285+
p_preventlogout("You can't log out until 10 seconds after the end of combat.", 16);
285286
~damage_self($damage);
286287

287288
[proc,npc_retaliate](int $queue_delay)

data/src/scripts/skill_combat/scripts/player/auto_retaliate.rs2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ if (%auto_retaliate = ^player_auto_retaliate_on & npc_finduid($nid) = true & bus
2222

2323
// this needs fixing, and .queue support
2424
[queue,pvp_retaliate](player_uid $uid)
25+
p_preventlogout("You can't log out until 10 seconds after the end of combat.", 16);
2526
if (%auto_retaliate = ^player_auto_retaliate_on & .finduid($uid) = true & busy2 = false) {
2627
// npc flinches player
2728
if (%action_delay < map_clock) {

src/engine/World.ts

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import Player from '#/engine/entity/Player.js';
5555
import EntityLifeCycle from '#/engine/entity/EntityLifeCycle.js';
5656
import { NpcList, PlayerList } from '#/engine/entity/EntityList.js';
5757
import { isClientConnected, NetworkPlayer } from '#/engine/entity/NetworkPlayer.js';
58-
import { EntityQueueState } from '#/engine/entity/EntityQueueRequest.js';
58+
import { EntityQueueState, PlayerQueueType } from '#/engine/entity/EntityQueueRequest.js';
5959
import { PlayerTimerType } from '#/engine/entity/EntityTimer.js';
6060

6161
import UpdateRebootTimer from '#/network/server/model/UpdateRebootTimer.js';
@@ -122,8 +122,8 @@ class World {
122122
private static readonly PLAYER_SAVERATE: number = 500; // 5m
123123
private static readonly PLAYER_COORDLOGRATE: number = 50; // 30s
124124

125-
private static readonly TIMEOUT_SOCKET_IDLE: number = Environment.NODE_DEBUG_SOCKET ? 60000 : 50; // 30s with no data- disconnect client
126-
private static readonly TIMEOUT_SOCKET_LOGOUT: number = Environment.NODE_DEBUG_SOCKET ? 60000 : 100; // 60s with no client- remove player from processing
125+
private static readonly TIMEOUT_NO_CONNECTION: number = Environment.NODE_DEBUG_SOCKET ? 60000 : 50; // 30s with no connection (16 ticks in osrs)
126+
private static readonly TIMEOUT_NO_RESPONSE: number = Environment.NODE_DEBUG_SOCKET ? 60000 : 100; // 60s without any response
127127

128128
// the game/zones map
129129
readonly gameMap: GameMap;
@@ -712,14 +712,6 @@ class World {
712712
}
713713
}
714714

715-
if (this.currentTick - player.lastResponse >= World.TIMEOUT_SOCKET_LOGOUT) {
716-
// x-logged / timed out for 60s: logout
717-
player.loggedOut = true;
718-
} else if (this.currentTick - player.lastResponse >= World.TIMEOUT_SOCKET_IDLE) {
719-
// x-logged / timed out for 30s: attempt logout
720-
player.tryLogout = true;
721-
}
722-
723715
// - client input tracking
724716
player.processInputTracking();
725717

@@ -728,7 +720,10 @@ class World {
728720
}
729721
} catch (err) {
730722
console.error(err);
731-
this.removePlayer(player);
723+
if (isClientConnected(player)) {
724+
player.logout();
725+
player.client.close();
726+
}
732727
}
733728
}
734729

@@ -841,7 +836,7 @@ class World {
841836
// - primary queue
842837
// - weak queue
843838
player.processQueues();
844-
if (!player.loggedOut) {
839+
if (!player.loggingOut) {
845840
// - timers
846841
player.processTimers(PlayerTimerType.NORMAL);
847842
// - soft timers
@@ -861,7 +856,10 @@ class World {
861856
}
862857
} catch (err) {
863858
console.error(err);
864-
this.removePlayer(player);
859+
if (isClientConnected(player)) {
860+
player.logout();
861+
player.client.close();
862+
}
865863
}
866864
}
867865

@@ -872,33 +870,54 @@ class World {
872870
const start: number = Date.now();
873871

874872
for (const player of this.players) {
875-
if (player.loggedOut) {
876-
player.tryLogout = true;
877-
player.clearInteraction();
878-
}
879-
880-
if (!player.tryLogout) {
881-
continue;
873+
let force = false;
874+
if (this.shutdown || this.currentTick - player.lastResponse >= World.TIMEOUT_NO_RESPONSE) {
875+
// world shutdown or x-logged / timed out for 60s: force logout
876+
player.loggingOut = true;
877+
force = true;
878+
} else if (this.currentTick - player.lastConnected >= World.TIMEOUT_NO_CONNECTION) {
879+
// connection lost for 30s: request idle logout
880+
player.requestIdleLogout = true;
881+
}
882+
883+
if (player.requestLogout || player.requestIdleLogout) {
884+
if (this.currentTick >= player.preventLogoutUntil) {
885+
player.loggingOut = true;
886+
} else if (player.requestLogout && player.preventLogoutMessage !== null) {
887+
player.messageGame(player.preventLogoutMessage); // engine message type in osrs
888+
player.preventLogoutMessage = null;
889+
}
890+
player.requestLogout = false;
891+
player.requestIdleLogout = false;
882892
}
883893

884-
player.closeModal();
894+
if (player.loggingOut && (force || this.currentTick >= player.preventLogoutUntil)) {
895+
player.closeModal();
885896

886-
if (player.canAccess() && player.queue.head() === null && player.engineQueue.head() === null) {
887-
const script = ScriptProvider.getByTriggerSpecific(ServerTriggerType.LOGOUT, -1, -1);
888-
if (!script) {
889-
printError('LOGOUT TRIGGER IS BROKEN!');
890-
continue;
897+
let queueDiscardable = true;
898+
for (let request = player.queue.head(); request !== null; request = player.queue.next()) {
899+
if (request.type === PlayerQueueType.LONG) {
900+
const logoutAction = request.args[0];
901+
if (logoutAction === 1) {
902+
// ^discard
903+
continue;
904+
}
905+
}
906+
queueDiscardable = false;
907+
break;
891908
}
892-
893-
const state = ScriptRunner.init(script, player);
894-
state.pointerAdd(ScriptPointer.ProtectedActivePlayer);
895-
ScriptRunner.execute(state);
896-
897-
const result = state.popInt();
898-
if (result === 1) {
909+
if (player.canAccess() && player.engineQueue.head() === null && queueDiscardable) {
910+
const script = ScriptProvider.getByTriggerSpecific(ServerTriggerType.LOGOUT, -1, -1);
911+
if (!script) {
912+
printError('LOGOUT TRIGGER IS BROKEN!');
913+
continue;
914+
}
915+
916+
const state = ScriptRunner.init(script, player);
917+
state.pointerAdd(ScriptPointer.ProtectedActivePlayer);
918+
ScriptRunner.execute(state);
919+
899920
this.removePlayer(player);
900-
} else {
901-
player.tryLogout = false;
902921
}
903922
}
904923
}
@@ -1112,7 +1131,10 @@ class World {
11121131
player.encodeOut();
11131132
} catch (err) {
11141133
console.error(err);
1115-
this.removePlayer(player);
1134+
if (isClientConnected(player)) {
1135+
player.logout();
1136+
player.client.close();
1137+
}
11161138
}
11171139
}
11181140
this.cycleStats[WorldStat.CLIENT_OUT] = Date.now() - start;
@@ -1199,23 +1221,23 @@ class World {
11991221
}
12001222

12011223
private processShutdown(): void {
1224+
for (const player of this.players) {
1225+
if (isClientConnected(player)) {
1226+
player.logout();
1227+
player.client.close();
1228+
}
1229+
}
1230+
12021231
const duration = this.currentTick - this.shutdownTick;
12031232
if (duration >= 1024) {
12041233
// force remove all players, they had their chances to finish processing
12051234
for (const player of this.players) {
1235+
player.addSessionLog(LoggerEventType.ENGINE, 'Player force removed!');
1236+
printError(`Player '${player.username}' force removed!`);
12061237
this.removePlayer(player);
12071238
}
12081239
}
12091240

1210-
for (const player of this.players) {
1211-
player.loggedOut = true;
1212-
1213-
if (isClientConnected(player)) {
1214-
player.logout(); // see ya
1215-
player.client.close();
1216-
}
1217-
}
1218-
12191241
const online = this.getTotalPlayers();
12201242
if (online === 0 && this.logoutRequests.size === 0) {
12211243
printInfo('Server shutdown complete');
@@ -1592,11 +1614,6 @@ class World {
15921614
return null;
15931615
}
15941616

1595-
if (player.loggedOut) {
1596-
// todo: proper?
1597-
return null;
1598-
}
1599-
16001617
return player;
16011618
}
16021619

src/engine/entity/NetworkPlayer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class NetworkPlayer extends Player {
6666
return false;
6767
}
6868

69+
this.lastConnected = World.currentTick;
6970
this.userLimit = 0;
7071
this.clientLimit = 0;
7172

0 commit comments

Comments
 (0)