diff --git a/Core/bottypes/AVstorageBot.cs b/Core/bottypes/AVstorageBot.cs index e915844..c46d159 100644 --- a/Core/bottypes/AVstorageBot.cs +++ b/Core/bottypes/AVstorageBot.cs @@ -20,7 +20,8 @@ namespace BSB.bottypes protected Dictionary> PendingAvatarFinds_vianame = new Dictionary>(); protected Dictionary> PendingAvatarFinds_viauuid = new Dictionary>(); - protected long max_db_storage_age = 240; // how long should we keep an avatar in memory before clearing (in secs) [now - last accessed] + protected long max_db_storage_age = 2240; // how long should we keep an avatar in memory before clearing (in secs) [now - last accessed] + protected int max_retry_attempts = 2; protected bool show_av_storage_info_in_status = true; protected string AVstorageBot_laststatus = ""; @@ -28,6 +29,7 @@ namespace BSB.bottypes { cleanupAvatarStorage(); ReTriggerAvLookups(); + UpdateStorageWithAroundMe(); string reply = ""; if (show_av_storage_info_in_status == true) { @@ -61,6 +63,18 @@ namespace BSB.bottypes return base.GetStatus(); } + protected void UpdateStorageWithAroundMe() + { + if(Client.Network.CurrentSim != null) + { + Dictionary avcopy = Client.Network.CurrentSim.ObjectsAvatars.Copy(); + foreach (Avatar av in avcopy.Values) + { + AddAvatarToDB(av.ID, av.Name); + } + } + } + protected void ReTriggerUUIDtoName() { long now = helpers.UnixTimeNow(); @@ -68,7 +82,18 @@ namespace BSB.bottypes List giveup_key2name = new List(); foreach (KeyValuePair> pair in PendingAvatarFinds_viauuid) { - giveup_key2name.Add(pair.Key); + long dif = now - pair.Value.Key; + if (dif > 30) + { + if (pair.Value.Value < max_retry_attempts) + { + retrigger_key2name.Add(pair.Key); + } + else + { + giveup_key2name.Add(pair.Key); + } + } } if(retrigger_key2name.Count > 0) { @@ -91,13 +116,25 @@ namespace BSB.bottypes List giveup_name2key = new List(); foreach (KeyValuePair> pair in PendingAvatarFinds_vianame) { - giveup_name2key.Add(pair.Key); + long dif = now - pair.Value.Key; + if (dif > 30) + { + if (pair.Value.Value < max_retry_attempts) + { + retrigger_name2key.Add(pair.Key); + } + else + { + giveup_name2key.Add(pair.Key); + } + } } foreach (string avname in retrigger_name2key) - { + { + int retry_counter = PendingAvatarFinds_vianame[avname].Value + 1; + PendingAvatarFinds_vianame[avname] = new KeyValuePair(now, retry_counter); Client.Directory.StartPeopleSearch(avname, 0); - PendingAvatarFinds_vianame[avname] = new KeyValuePair(now, PendingAvatarFinds_vianame[avname].Value + 1); } foreach (string avname in giveup_name2key) @@ -153,16 +190,16 @@ namespace BSB.bottypes protected override void AfterBotLoginHandler() { - base.AfterBotLoginHandler(); if (reconnect == false) { Client.Avatars.UUIDNameReply += Key2NameEvent; Client.Directory.DirPeopleReply += Name2KeyEvent; - if(helpers.notempty(myconfig.Security_MasterUsername) == true) + if (helpers.notempty(myconfig.Security_MasterUsername) == true) { FindAvatarName2Key(myconfig.Security_MasterUsername); } } + base.AfterBotLoginHandler(); } protected void Key2NameEvent(object sender,UUIDNameReplyEventArgs e) @@ -201,6 +238,10 @@ namespace BSB.bottypes } } } + else + { + AvatarStorageLastUsed[av_name] = helpers.UnixTimeNow(); + } if (helpers.notempty(myconfig.Security_MasterUsername) == true) { if(myconfig.Security_MasterUsername == av_name) @@ -215,126 +256,137 @@ namespace BSB.bottypes } } } + + protected string httpLookupKey(string avatar_name) + { + if (myconfig.Name2Key_Enable == true) + { + var client = new RestClient(myconfig.Name2Key_Url); + var request = new RestRequest("name2key/" + avatar_name + "/" + myconfig.Name2Key_Key + "", Method.GET); + client.Timeout = 3000; // ? does this even do anything + request.Timeout = 3000; + IRestResponse endpoint_checks = client.Get(request); + if (endpoint_checks.StatusCode == System.Net.HttpStatusCode.OK) + { + try + { + namekeyservicereply server_reply = JsonConvert.DeserializeObject(endpoint_checks.Content); + if (server_reply.status == true) + { + if (server_reply.found == true) + { + AddAvatarToDB((UUID)server_reply.uuid, server_reply.name); + return server_reply.uuid; + } + } + } + catch + { + + } + } + } + return ""; + } + + protected string FindAvatarUUIDInStorage(string avatar_name) + { + if (AvatarStorageLastUsed.ContainsKey(avatar_name) == true) + { + AvatarStorageLastUsed[avatar_name] = helpers.UnixTimeNow(); + return AvatarName2Key[avatar_name].ToString(); + } + return ""; + } + public string FindAvatarName2Key(string avatar_name) { - return FindAvatarName2Key(avatar_name, false); - } - public string FindAvatarName2Key(string avatar_name,bool skip_http) - { - if (myconfig.Name2Key_Enable == false) - { - skip_http = true; - } List bits = avatar_name.Split(' ').ToList(); if(bits.Count() == 1) { bits.Add("Resident"); } - avatar_name = bits[0].FirstCharToUpper() + " " + bits[1].FirstCharToUpper(); - long now = helpers.UnixTimeNow(); - if (AvatarStorageLastUsed.ContainsKey(avatar_name) == true) + avatar_name = bits[0].FirstCharToUpper() + " " + bits[1].FirstCharToUpper(); + string uuid = FindAvatarUUIDInStorage(avatar_name); + if (uuid != "") { - AvatarStorageLastUsed[avatar_name] = now; - return AvatarName2Key[avatar_name].ToString(); + return uuid; } - else + uuid = httpLookupKey(avatar_name); + if (uuid != "") { - if(PendingAvatarFinds_vianame.ContainsKey(avatar_name) == false) - { - if (skip_http == false) - { - var client = new RestClient(myconfig.Name2Key_Url); - var request = new RestRequest("name2key/" + avatar_name + "/" + myconfig.Name2Key_Key + "", Method.GET); - client.Timeout = 3000; // ? does this even do anything - request.Timeout = 3000; - IRestResponse endpoint_checks = client.Get(request); - if (endpoint_checks.StatusCode == System.Net.HttpStatusCode.OK) - { - try - { - namekeyservicereply server_reply = JsonConvert.DeserializeObject(endpoint_checks.Content); - if (server_reply.status == true) - { - if (server_reply.found == true) - { - AddAvatarToDB((UUID)server_reply.uuid, server_reply.name); - return server_reply.uuid; - } - } - } - catch - { - - } - } - return FindAvatarName2Key(avatar_name, true); - - } - else - { - PendingAvatarFinds_vianame.Add(avatar_name, new KeyValuePair(now, 0)); - Client.Directory.StartPeopleSearch(avatar_name, 0); - } - } + return uuid; + } + if (PendingAvatarFinds_vianame.ContainsKey(avatar_name) == false) + { + PendingAvatarFinds_vianame.Add(avatar_name, new KeyValuePair(helpers.UnixTimeNow(), 0)); + Client.Directory.StartPeopleSearch(avatar_name, 0); } return "lookup"; } - public string FindAvatarKey2Name(UUID avatar_uuid) - { - return FindAvatarKey2Name(avatar_uuid, false); - } - public string FindAvatarKey2Name(UUID avatar_uuid, bool skip_http) - { - if (myconfig.Name2Key_Enable == false) - { - skip_http = true; - } - long now = helpers.UnixTimeNow(); + + + protected string FindAvatarNameInStorage(UUID avatar_uuid) + { if (AvatarKey2Name.ContainsKey(avatar_uuid) == true) { - AvatarStorageLastUsed[AvatarKey2Name[avatar_uuid]] = now; + AvatarStorageLastUsed[AvatarKey2Name[avatar_uuid]] = helpers.UnixTimeNow(); return AvatarKey2Name[avatar_uuid]; - } - else - { - if (skip_http == false) - { - var client = new RestClient(myconfig.Name2Key_Url); - var request = new RestRequest("key2name/" + avatar_uuid.ToString() + "/" + myconfig.Name2Key_Key + "", Method.GET); - client.Timeout = 3000; // ? does this even do anything - request.Timeout = 3000; - IRestResponse endpoint_checks = client.Get(request); - if (endpoint_checks.StatusCode == System.Net.HttpStatusCode.OK) - { - try - { - namekeyservicereply server_reply = JsonConvert.DeserializeObject(endpoint_checks.Content); - if (server_reply.status == true) - { - if(server_reply.found == true) - { - AddAvatarToDB((UUID)server_reply.uuid, server_reply.name); - return server_reply.name; - } - } - } - catch - { + } + return ""; + } - } - } - return FindAvatarKey2Name(avatar_uuid, true); - } - else - { - if (PendingAvatarFinds_viauuid.ContainsKey(avatar_uuid) == false) - { - PendingAvatarFinds_viauuid.Add(avatar_uuid, new KeyValuePair(now, 0)); - Client.Avatars.RequestAvatarName(avatar_uuid); - } - } - return "lookup"; + protected string httpLookupName(UUID avatar_uuid) + { + if (myconfig.Name2Key_Enable == true) + { + var client = new RestClient(myconfig.Name2Key_Url); + var request = new RestRequest("key2name/" + avatar_uuid.ToString() + "/" + myconfig.Name2Key_Key + "", Method.GET); + client.Timeout = 3000; // ? does this even do anything + request.Timeout = 3000; + IRestResponse endpoint_checks = client.Get(request); + if (endpoint_checks.StatusCode == System.Net.HttpStatusCode.OK) + { + try + { + namekeyservicereply server_reply = JsonConvert.DeserializeObject(endpoint_checks.Content); + if (server_reply.status == true) + { + if (server_reply.found == true) + { + AddAvatarToDB((UUID)server_reply.uuid, server_reply.name); + return server_reply.name; + } + } + } + catch + { + + } + } + } + return ""; + } + + + public string FindAvatarKey2Name(UUID avatar_uuid) + { + string avatar_name = FindAvatarNameInStorage(avatar_uuid); + if (avatar_name != "") + { + return avatar_name; } + avatar_name = httpLookupName(avatar_uuid); + if (avatar_name != "") + { + return avatar_name; + } + if (PendingAvatarFinds_viauuid.ContainsKey(avatar_uuid) == false) + { + PendingAvatarFinds_viauuid.Add(avatar_uuid, new KeyValuePair(helpers.UnixTimeNow(), 0)); + Client.Avatars.RequestAvatarName(avatar_uuid); + } + return "lookup"; } protected virtual void FoundMasterAvatar() diff --git a/Core/bottypes/athome.cs b/Core/bottypes/athome.cs index cb04a8a..c0599ed 100644 --- a/Core/bottypes/athome.cs +++ b/Core/bottypes/athome.cs @@ -9,165 +9,52 @@ namespace BSB.bottypes { public abstract class AtHome : MessageSwitcherBot { - protected long ConnectionLostAt = 0; + protected long last_tp_attempt_unixtime; + protected string last_attempted_teleport_region = ""; + protected bool after_login_fired; + protected int last_tested_home_id = -1; + protected Dictionary avoid_sims = new Dictionary(); + protected bool teleport_lockout; + protected override void AfterBotLoginHandler() { base.AfterBotLoginHandler(); - Info("Home regions count: " + myconfig.Basic_HomeRegions.Length.ToString() + ""); + last_tested_home_id = -1; last_tp_attempt_unixtime = helpers.UnixTimeNow() + 30; - if (reconnect == true) - { - ResetAtHome(); - } - else - { - Client.Self.AlertMessage += AlertEvent; - Client.Network.SimChanged += ChangeSim; - } - if (Client.Network.Connected == true) + if (after_login_fired == false) { - if (Client.Network.CurrentSim != null) - { - if (IsSimHome(Client.Network.CurrentSim.Name) == true) - { - if (UUID.TryParse(myconfig.Setting_DefaultSit_UUID, out UUID sit_UUID) == true) - { - Client.Self.RequestSit(sit_UUID, Vector3.Zero); - } - } - } + Info("Home regions count: " + myconfig.Basic_HomeRegions.Length.ToString() + ""); + Client.Self.AlertMessage += AlertEvent; + Client.Network.SimChanged += ChangeSim; + after_login_fired = true; + reconnect = true; } - after_login_fired = true; } - protected string FirstLoginStage() - { - long dif = helpers.UnixTimeNow() - last_reconnect_attempt; - if (login_auto_logout == true) - { - if (last_reconnect_attempt == 0) - { - last_reconnect_attempt = helpers.UnixTimeNow(); - return login_status; - } - else - { - if (auto_logout_login_recover == false) - { - auto_logout_login_recover = true; - last_reconnect_attempt = helpers.UnixTimeNow(); - return "W4>" + login_status + " (20 secs)"; - } - else if (dif >= 20) - { - login_auto_logout = false; - auto_logout_login_recover = false; - last_reconnect_attempt = helpers.UnixTimeNow(); - Start(true); - return "Restarting first login [Using Alt locations]"; - } - return "Waiting for cooldown"; - } - } - else - { - return login_status; - } - } - - protected string LoggedInConnectionLost() - { - long dif = helpers.UnixTimeNow() - last_reconnect_attempt; - if (reconnect_mode == true) - { - last_tested_home_id = -1; - last_tp_attempt_unixtime = 0; - after_login_fired = false; - teleported = false; - reconnect_mode = false; - last_reconnect_attempt = helpers.UnixTimeNow(); - return "Connection lost - switching to recovery mode"; - } - else - { - if (dif <= 60) - { - return "W4> Network reset timeout [60 secs]"; - } - else - { - if (last_reconnect_attempt == 0) - { - last_reconnect_attempt = helpers.UnixTimeNow(); - return "First connection failed"; - } - else - { - last_reconnect_attempt = helpers.UnixTimeNow(); - if (after_login_fired == true) - { - reconnect = true; - } - login_failed = false; - login_auto_logout = false; - Start(true); - if (reconnect == true) - { - return "Attempting reconnect"; - } - return "Trying to connect again"; - } - } - } - } - - protected string LoggedOutNextAction() - { - if (login_failed == true) - { - return LoggedInConnectionLost(); - } - else if (login_auto_logout == true) - { - return FirstLoginStage(); - } - return ""; - } - protected int last_tested_home_id = -1; - protected long last_tp_attempt_unixtime; - protected bool after_login_fired; - - - protected long last_reconnect_attempt; - protected bool reconnect_mode; - protected string last_attempted_teleport_region = ""; - protected Dictionary avoid_sims = new Dictionary(); - protected bool SimShutdownAvoid; - protected long SimShutdownAvoidCooldown = 0; - protected bool auto_logout_login_recover; - + protected void ChangeSim(object sender,SimChangedEventArgs e) { - if (Client.Network.CurrentSim.Name != last_attempted_teleport_region) - { - if (IsSimHome(Client.Network.CurrentSim.Name) == false) - { - SetTeleported(); - } - else - { - if (UUID.TryParse(myconfig.Setting_DefaultSit_UUID, out UUID sit_UUID) == true) - { - Client.Self.RequestSit(sit_UUID, Vector3.Zero); + if (teleport_lockout == false) + { + if (last_attempted_teleport_region != "") + { + if (last_attempted_teleport_region != Client.Network.CurrentSim.Name) + { + teleport_lockout = true; + Info("Teleport by script/master detected - @home lock out enabled"); } } + else + { + last_attempted_teleport_region = Client.Network.CurrentSim.Name; + Info("Connected to region"); + } } - else + if (IsSimHome(Client.Network.CurrentSim.Name) == true) { - if (SimShutdownAvoid == true) + if (UUID.TryParse(myconfig.Setting_DefaultSit_UUID, out UUID sit_UUID) == true) { - Status("Avoided sim shutdown will attempt to go home in 4 mins"); - SimShutdownAvoid = false; + Client.Self.RequestSit(sit_UUID, Vector3.Zero); } } } @@ -177,11 +64,8 @@ namespace BSB.bottypes { // oh snap region is dead run away Info("--- Sim Restarting ---"); - if (avoid_sims.ContainsKey(Client.Network.CurrentSim.Name) == false) - { - avoid_sims.Add(Client.Network.CurrentSim.Name, helpers.UnixTimeNow() + (10 * 60)); - } - GotoNextHomeRegion(true); + AvoidSim(Client.Network.CurrentSim.Name); + GotoNextHomeRegion(); } } @@ -189,11 +73,10 @@ namespace BSB.bottypes { Debug("@home / ResetAtHome"); last_tested_home_id = -1; - after_login_fired = false; - teleported = false; - reconnect_mode = false; - last_tp_attempt_unixtime = 0; + teleport_lockout = false; + last_attempted_teleport_region = ""; avoid_sims = new Dictionary(); + last_tp_attempt_unixtime = helpers.UnixTimeNow() + 30; } @@ -202,7 +85,7 @@ namespace BSB.bottypes { if (avoid_sims.ContainsKey(simname) == false) { - Debug("@home / AvoidSim: " + simname); + Debug("@home / Avoiding sim: " + simname); avoid_sims.Add(simname, helpers.UnixTimeNow() + 240); // @home will avoid that sim for the next 4 mins } } @@ -213,10 +96,6 @@ namespace BSB.bottypes { List remove_keys = new List(); long now = helpers.UnixTimeNow(); - if (GetClient.Network.Connected == false) - { - now -= 240; // when logged out, add 240s to all sims we are avoiding - } foreach (KeyValuePair avoids in avoid_sims) { if(avoids.Value < now) @@ -270,68 +149,72 @@ namespace BSB.bottypes public string LoggedinAthome() { - string addon = ""; - if(IsSimHome(Client.Network.CurrentSim.Name) == true) - { - addon = "Home region"; + string addon = "Waiting for action"; + if (teleport_lockout == false) + { + if (IsSimHome(Client.Network.CurrentSim.Name) == true) + { + addon = "Home region"; + } + else + { + long dif = last_tp_attempt_unixtime - helpers.UnixTimeNow(); + if (dif > 0) + { + addon = "Waiting for TP cooldown"; + } + else + { + GotoNextHomeRegion(); + } + } } - else - { - if (SimShutdownAvoid == false) - { - long dif = SimShutdownAvoidCooldown - helpers.UnixTimeNow(); - if (dif < 0) - { - dif = helpers.UnixTimeNow() - last_tp_attempt_unixtime; - if (dif > 30) - { - if (teleported == false) - { - addon = GotoNextHomeRegion(false); - } - else - { - addon = "- Teleported by script/master -"; - } - } - else - { - addon = "Busy with TP cooldown"; - } - } - else - { - if (avoid_sims.Keys.Contains(Client.Network.CurrentSim.Name) == true) - { - dif = helpers.UnixTimeNow() - last_tp_attempt_unixtime; - if (dif > 45) - { - addon = GotoNextHomeRegion(true); - } - else - { - addon = "Avoid teleport underway"; - } - } - else - { - double mins = Math.Round((double)dif / 60); - int min = (int)mins; - addon = "Hiding from the storm ("+min.ToString()+" mins remain)"; - } - } - } - else - { - addon = "Avoiding sim shutdown [TP underway]"; - } + else + { + addon = "Lockout"; } return addon; - } - - public string GotoNextHomeRegion() - { - return GotoNextHomeRegion(false); + } + + + protected long login_failed_retry_at = 0; + public string AtHomeReconnect() + { + if (attempted_first_login == true) + { + if (login_failed == false) + { + return login_status; + } + else + { + if(login_failed_retry_at == 0) + { + login_failed_retry_at = helpers.UnixTimeNow() + 40; + return login_status + " Retrying in 40 secs"; + } + else + { + long dif = login_failed_retry_at - helpers.UnixTimeNow(); + if(dif > 0) + { + login_failed_retry_at = 0; + attempted_first_login = false; + Start(true); + return "Attempting reconnect"; + } + else + { + return "Waiting for reconnect - " + dif.ToString() + " secs"; + } + } + } + } + else + { + return "Waiting"; + } + } protected override string[] getNextHomeArgs() @@ -357,71 +240,45 @@ namespace BSB.bottypes return new string[] { }; } - protected string GotoNextHomeRegion(bool panic_mode) - { - if (panic_mode == false) - { - if (myconfig.Basic_HomeRegions.Length > 0) - { - last_tp_attempt_unixtime = helpers.UnixTimeNow(); - string UseSLurl = ""; - foreach (string Slurl in myconfig.Basic_HomeRegions) + public string GotoNextHomeRegion() + { + if (myconfig.Basic_HomeRegions.Length > 0) + { + last_tp_attempt_unixtime = helpers.UnixTimeNow(); + List tested_sims = new List(); + string UseSLurl = ""; + string simname = ""; + while ((tested_sims.Count() != myconfig.Basic_HomeRegions.Length) && (UseSLurl == "")) + { + last_tested_home_id++; + if (last_tested_home_id > myconfig.Basic_HomeRegions.Length) { - string simname = helpers.RegionnameFromSLurl(Slurl); - if (avoid_sims.Keys.Contains(simname) == false) + last_tested_home_id = 0; + } + UseSLurl = myconfig.Basic_HomeRegions[last_tested_home_id]; + simname = helpers.RegionnameFromSLurl(UseSLurl); + if (simname != last_attempted_teleport_region) + { + if (avoid_sims.ContainsKey(simname) == true) { - UseSLurl = Slurl; - break; + UseSLurl = ""; } - } - if (UseSLurl != "") + } + } + if (UseSLurl != "") + { + string whyrejected = TeleportWithSLurl(UseSLurl); + if (whyrejected == "ok") { - string simname = helpers.RegionnameFromSLurl(UseSLurl); - if (simname != last_attempted_teleport_region) - { - string whyrejected = TeleportWithSLurl(UseSLurl); - if (whyrejected == "ok") - { - AvoidSim(simname); - return "**** active teleport: " + last_attempted_teleport_region + "***"; - } - AvoidSim(simname); - return "TP to " + simname + " rejected - " + whyrejected; - } - } - return "No other sims found to teleport to [Maybe only 1 home region?]"; - } - return "No home regions"; - } - else - { - SimShutdownAvoid = true; - SimShutdownAvoidCooldown = helpers.UnixTimeNow() + (60 * 10); - string UseSLurl = ""; - foreach (string Slurl in myconfig.Basic_HomeRegions) - { - string simname = helpers.RegionnameFromSLurl(Slurl); - if (avoid_sims.Keys.Contains(simname) == false) - { - UseSLurl = Slurl; - break; - } - } - if (UseSLurl != "") - { - TeleportWithSLurl(UseSLurl); - Status("Attempting panic evac to: "+ last_attempted_teleport_region+""); - AvoidSim(UseSLurl); // black list that region so we dont try to go back there if we get a shutdown notice again - } - else - { - Status("No vaild SLurl found, Teleporting to backup hub"); - string[] Hubs = new[] { "https://maps.secondlife.com/secondlife/Morris/28/228/40/", "https://maps.secondlife.com/secondlife/Ahern/28/28/40/", - "https://maps.secondlife.com/secondlife/Bonifacio/228/228/40/","https://maps.secondlife.com/secondlife/Dore/228/28/40/" }; - TeleportWithSLurl(Hubs[new Random().Next(0, Hubs.Length - 1)]); - } - return "Panic mode"; - } + AvoidSim(simname); + return "**** active teleport: " + last_attempted_teleport_region + "***"; + } + AvoidSim(simname); + return "TP to " + simname + " rejected - " + whyrejected; + } + return "No other sims found to teleport to"; + } + return "No home regions"; } @@ -434,7 +291,7 @@ namespace BSB.bottypes public override string GetStatus() { ExpireOldAvoidSims(); - string reply; + string reply = "Disconnected: No action"; if (Client.Network.Connected == true) { if (Client.Network.CurrentSim != null) @@ -443,17 +300,18 @@ namespace BSB.bottypes { AfterBotLoginHandler(); } - reply = AtHomeStatus(LoggedinAthome()); + reply = LoggedinAthome(); } else { - reply = AtHomeStatus("No Sim"); + reply = "Connected: No Sim"; } } else - { - reply = AtHomeStatus(LoggedOutNextAction()); + { + reply = AtHomeReconnect(); } + reply = AtHomeStatus(reply); if (reply != AtHome_laststatus) { AtHome_laststatus = reply; diff --git a/libremetaverse-core/Libremetaverse/Login.cs b/libremetaverse-core/Libremetaverse/Login.cs index 4972918..974f73d 100644 --- a/libremetaverse-core/Libremetaverse/Login.cs +++ b/libremetaverse-core/Libremetaverse/Login.cs @@ -1142,7 +1142,7 @@ namespace OpenMetaverse if (string.IsNullOrEmpty(loginParams.LoginLocation) == false) { - string[] bits = loginParams.LoginLocation.Split("/"); + string[] bits = loginParams.LoginLocation.Split('/'); if(bits.Count() == 4) { if(int.TryParse(bits[1],out int X) == true)