From 40f58b21c66b1d883bbd0b5992da8098ed31674e Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Tue, 26 May 2026 23:21:43 -0400
Subject: [PATCH 1/6] done
---
DMCompiler/DMStandard/Types/Atoms/Mob.dm | 5 ++
DMCompiler/DMStandard/Types/Client.dm | 9 +--
OpenDreamRuntime/DreamConnection.cs | 77 ++++++++++++++----------
3 files changed, 54 insertions(+), 37 deletions(-)
diff --git a/DMCompiler/DMStandard/Types/Atoms/Mob.dm b/DMCompiler/DMStandard/Types/Atoms/Mob.dm
index d8550a7728..5b3d1f5bdd 100644
--- a/DMCompiler/DMStandard/Types/Atoms/Mob.dm
+++ b/DMCompiler/DMStandard/Types/Atoms/Mob.dm
@@ -16,5 +16,10 @@
layer = MOB_LAYER
proc/Login()
+ if(!loc)
+ var/turf/fallback_spawn = locate(1, 1, 1) // TODO: Find nearest non-dense turf
+ if(fallback_spawn)
+ loc = fallback_spawn
proc/Logout()
+ del client
diff --git a/DMCompiler/DMStandard/Types/Client.dm b/DMCompiler/DMStandard/Types/Client.dm
index c07c511036..83e9c75c31 100644
--- a/DMCompiler/DMStandard/Types/Client.dm
+++ b/DMCompiler/DMStandard/Types/Client.dm
@@ -63,10 +63,11 @@
break
if (mob == null) // No existing mob, create a default one
- mob = new world.mob(locate(1,1,1)) // TODO: Find nearest non-dense turf
-
- eye = mob
- statobj = mob
+ var/mob/initial_mob = new world.mob()
+
+ eye = initial_mob
+ statobj = initial_mob
+ mob = initial_mob
return mob
proc/Del()
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 52256253f9..03e969bd53 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -37,32 +37,21 @@ public sealed partial class DreamConnection {
[ViewVariables] public DreamObjectMob? Mob {
get => _mob;
set {
- if (_mob != value) {
- var oldMob = _mob;
- value?.IncRef();
- _mob?.DecRef();
- _mob = value;
-
- if (oldMob != null) {
- oldMob.Key = null;
- oldMob.Connection = null;
- oldMob.SpawnProc("Logout").Dispose();
- }
-
- StatObj = new(value);
- if (Eye != null && Eye == oldMob) {
- Eye = value;
- }
+ if (_mob == value)
+ return;
- if (_mob != null) {
- // If the mob is already owned by another player, kick them out
- _mob.Connection?.Mob = null;
+ var oldMob = _mob;
+ var oldConnection = value?.Connection;
+ SetClientMob(value);
- _mob.Connection = this;
- _mob.Key = Key;
- _mob.SpawnProc("Login", usr: _mob).Dispose();
- }
+ if(oldConnection is not null) {
+ oldConnection.HandleDisconnection();
+ _mob!.SpawnProc("Logout").Dispose();
}
+ if(oldMob is not null)
+ oldMob!.SpawnProc("Logout").Dispose();
+ if(_mob is not null)
+ _mob!.SpawnProc("Login", usr: _mob).Dispose();
}
}
@@ -125,21 +114,43 @@ public void HandleDisconnection() {
_verbSystem?.RemoveConnectionFromRepeatingVerbs(this);
Session = null;
- if (_mob != null) {
- // Don't null out the ckey here
- _mob.SpawnProc("Logout").Dispose();
-
- if (_mob != null) { // Logout() may have removed our mob
- _mob.Connection = null;
- _mob = null;
- }
- }
-
+ Mob = null;
Client.DecRef();
Client.Delete();
Client = null;
}
+ ///
+ /// Sets the connection's mob without any side effects.
+ ///
+ private void SetClientMob(DreamObjectMob? newMob) {
+ if(newMob == _mob)
+ return;
+
+ var oldMob = _mob;
+ _mob = newMob;
+ newMob?.IncRef();
+ oldMob?.DecRef();
+
+ if (oldMob is not null) {
+ oldMob.Key = null;
+ oldMob.Connection = null;
+ }
+
+ StatObj = new(newMob);
+ if (Eye is not null && Eye == oldMob) {
+ Eye = newMob;
+ }
+
+ if (newMob is not null) {
+ // If the mob is already owned by another player, kick them out
+ newMob.Connection?.SetClientMob(null);
+
+ newMob.Connection = this;
+ newMob.Key = Key;
+ }
+ }
+
public void UpdateStat() {
if (Session == null || Client == null || _currentlyUpdatingStat)
return;
From c1ec4dffa3b267edf12fe3a1ef2a539ce64a1de5 Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Tue, 26 May 2026 23:35:11 -0400
Subject: [PATCH 2/6] nullables
---
OpenDreamRuntime/DreamConnection.cs | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 03e969bd53..63115031e4 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -48,10 +48,9 @@ [ViewVariables] public DreamObjectMob? Mob {
oldConnection.HandleDisconnection();
_mob!.SpawnProc("Logout").Dispose();
}
- if(oldMob is not null)
- oldMob!.SpawnProc("Logout").Dispose();
- if(_mob is not null)
- _mob!.SpawnProc("Login", usr: _mob).Dispose();
+
+ oldMob?.SpawnProc("Logout").Dispose();
+ _mob?.SpawnProc("Login", usr: _mob).Dispose();
}
}
From f2d339d98991e756d75eb8cba8c3d1885f93b7f7 Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Thu, 28 May 2026 12:41:15 -0400
Subject: [PATCH 3/6] empty commit
From 2fb0f4b06cb2eb57cd3e774f98fb158a9616705b Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Fri, 5 Jun 2026 18:35:37 -0400
Subject: [PATCH 4/6] Delete the client directly instead of calling
HandleDisconnect()
---
OpenDreamRuntime/DreamConnection.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 63115031e4..6fe1049313 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -45,7 +45,7 @@ [ViewVariables] public DreamObjectMob? Mob {
SetClientMob(value);
if(oldConnection is not null) {
- oldConnection.HandleDisconnection();
+ oldConnection.Client?.Delete();
_mob!.SpawnProc("Logout").Dispose();
}
From e00e1f744b29d5b235e77a597582b1c3588172d6 Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Fri, 12 Jun 2026 14:57:08 -0400
Subject: [PATCH 5/6] Fix that bug
---
OpenDreamRuntime/DreamConnection.cs | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 6fe1049313..b4f2cf5823 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -45,7 +45,7 @@ [ViewVariables] public DreamObjectMob? Mob {
SetClientMob(value);
if(oldConnection is not null) {
- oldConnection.Client?.Delete();
+ oldConnection.Client?.Delete(); // TODO: This should tell you why you disconnected
_mob!.SpawnProc("Logout").Dispose();
}
@@ -113,16 +113,22 @@ public void HandleDisconnection() {
_verbSystem?.RemoveConnectionFromRepeatingVerbs(this);
Session = null;
- Mob = null;
+ // The client still has a reference to the mob when deleted, so we do this first
Client.DecRef();
Client.Delete();
Client = null;
+
+ if(Mob is not null) {
+ var oldMob = Mob;
+ SetClientMob(null, true);
+ oldMob.SpawnProc("Logout").Dispose();
+ }
}
///
/// Sets the connection's mob without any side effects.
///
- private void SetClientMob(DreamObjectMob? newMob) {
+ private void SetClientMob(DreamObjectMob? newMob, bool preserveKey = false) {
if(newMob == _mob)
return;
@@ -132,7 +138,8 @@ private void SetClientMob(DreamObjectMob? newMob) {
oldMob?.DecRef();
if (oldMob is not null) {
- oldMob.Key = null;
+ if(!preserveKey)
+ oldMob.Key = null;
oldMob.Connection = null;
}
@@ -146,7 +153,8 @@ private void SetClientMob(DreamObjectMob? newMob) {
newMob.Connection?.SetClientMob(null);
newMob.Connection = this;
- newMob.Key = Key;
+ if(!preserveKey)
+ newMob.Key = Key;
}
}
From 4e162f88b92038d80e345ce8f74f7d1e09875970 Mon Sep 17 00:00:00 2001
From: tontyGH <39193182+tontyGH@users.noreply.github.com>
Date: Tue, 16 Jun 2026 12:56:59 -0400
Subject: [PATCH 6/6] "implements" client/Del() it doesn't actually do anything
---
DMCompiler/DMStandard/Types/Client.dm | 1 -
1 file changed, 1 deletion(-)
diff --git a/DMCompiler/DMStandard/Types/Client.dm b/DMCompiler/DMStandard/Types/Client.dm
index 83e9c75c31..7512a31272 100644
--- a/DMCompiler/DMStandard/Types/Client.dm
+++ b/DMCompiler/DMStandard/Types/Client.dm
@@ -71,7 +71,6 @@
return mob
proc/Del()
- set opendream_unimplemented = TRUE
proc/Topic(href, list/href_list, datum/hsrc)
if (hsrc != null)