Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions TShockAPI/Configuration/TShockConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ public class TShockSettings
[Description("Prevents users from being able to login with their client UUID.")]
public bool DisableUUIDLogin;

/// <summary>Prevents users in the superadmin group from being automatically logged in via UUID.</summary>
[Description("Prevents users in the superadmin group from being automatically logged in via UUID.")]
public bool DisableSuperAdminUUIDLogin = true;

/// <summary>Kick clients that don't send their UUID to the server.</summary>
[Description("Kick clients that don't send their UUID to the server.")]
public bool KickEmptyUUID = true;
Expand Down
68 changes: 39 additions & 29 deletions TShockAPI/GetDataHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2854,46 +2854,56 @@ private static bool HandleConnecting(GetDataHandlerArgs args)
if (!TShock.Groups.AssertGroupValid(args.Player, group, true))
return true;

args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID);
if (Main.ServerSideCharacter && TShock.CharacterDB.IsSeededAppearanceMissing(args.Player.PlayerData))
// Require manual /login for superadmin accounts (fixes #3278)
if (TShock.Config.Settings.DisableSuperAdminUUIDLogin && group.Name == "superadmin")
{
TShock.CharacterDB.SyncSeededAppearance(account, args.Player);
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID);
args.Player.SendInfoMessage(GetString("Automatic login disabled for superadmin accounts. Please use /login."));
return true;
}
Comment on lines +2857 to 2862

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Double WorldInfo packet sent to superadmin clients

Before this check, line 2850 unconditionally sends WorldInfo to the player whenever the UUID matches. When group.Name == "superadmin" the empty if body falls through to line 2924, which sends WorldInfo a second time. The non-superadmin path avoids this via its return true at line 2904, but the superadmin path has no early exit. Sending the same packet twice unexpectedly may confuse the client's connection state machine.

else
{

args.Player.Group = group;
args.Player.tempGroup = null;
args.Player.Account = account;
args.Player.IsLoggedIn = true;
args.Player.IsDisabledForSSC = false;
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID);
if (Main.ServerSideCharacter && TShock.CharacterDB.IsSeededAppearanceMissing(args.Player.PlayerData))
{
TShock.CharacterDB.SyncSeededAppearance(account, args.Player);
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID);
}

if (Main.ServerSideCharacter)
{
if (args.Player.HasPermission(Permissions.bypassssc))
args.Player.Group = group;
args.Player.tempGroup = null;
args.Player.Account = account;
args.Player.IsLoggedIn = true;
args.Player.IsDisabledForSSC = false;

if (Main.ServerSideCharacter)
{
if (args.Player.PlayerData.exists && TShock.ServerSideCharacterConfig.Settings.WarnPlayersAboutBypassPermission)
if (args.Player.HasPermission(Permissions.bypassssc))
{
args.Player.SendWarningMessage(GetString("Bypass SSC is enabled for your account. SSC data will not be loaded or saved."));
TShock.Log.ConsoleInfo(GetString($"{args.Player.Name} has SSC data in the database, but has the tshock.ignore.ssc permission. This means their SSC data is being ignored."));
TShock.Log.ConsoleInfo(GetString("You may wish to consider removing the tshock.ignore.ssc permission or negating it for this player."));
if (args.Player.PlayerData.exists && TShock.ServerSideCharacterConfig.Settings.WarnPlayersAboutBypassPermission)
{
args.Player.SendWarningMessage(GetString("Bypass SSC is enabled for your account. SSC data will not be loaded or saved."));
TShock.Log.ConsoleInfo(GetString($"{args.Player.Name} has SSC data in the database, but has the tshock.ignore.ssc permission. This means their SSC data is being ignored."));
TShock.Log.ConsoleInfo(GetString("You may wish to consider removing the tshock.ignore.ssc permission or negating it for this player."));
}
args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player);
}
args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player);
args.Player.PlayerData.RestoreCharacter(args.Player);
}
args.Player.PlayerData.RestoreCharacter(args.Player);
}
args.Player.LoginFailsBySsi = false;
args.Player.LoginFailsBySsi = false;

if (args.Player.HasPermission(Permissions.ignorestackhackdetection))
args.Player.IsDisabledForStackDetection = false;
if (args.Player.HasPermission(Permissions.ignorestackhackdetection))
args.Player.IsDisabledForStackDetection = false;

if (args.Player.HasPermission(Permissions.usebanneditem))
args.Player.IsDisabledForBannedWearable = false;
if (args.Player.HasPermission(Permissions.usebanneditem))
args.Player.IsDisabledForBannedWearable = false;

args.Player.SendSuccessMessage(GetString($"Authenticated as {account.Name} successfully."));
TShock.Log.ConsoleInfo(GetString($"{args.Player.Name} authenticated successfully as user {args.Player.Name}."));
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
return true;
args.Player.SendSuccessMessage(GetString($"Authenticated as {account.Name} successfully."));
TShock.Log.ConsoleInfo(GetString($"{args.Player.Name} authenticated successfully as user {args.Player.Name}."));
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
return true;
}
}
}
else if (account != null && !TShock.Config.Settings.DisableLoginBeforeJoin)
Expand Down