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..6fe1049313 100644 --- a/OpenDreamRuntime/DreamConnection.cs +++ b/OpenDreamRuntime/DreamConnection.cs @@ -37,32 +37,20 @@ 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.Client?.Delete(); + _mob!.SpawnProc("Logout").Dispose(); } + + oldMob?.SpawnProc("Logout").Dispose(); + _mob?.SpawnProc("Login", usr: _mob).Dispose(); } } @@ -125,21 +113,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;