RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

duplicated Names / Double Names

Joker01

Squire
I know there are other Threads with this problem.

But i wan´t to tell you my solution to this prob.
I edit 3 files: Charactercreation.cs , Nameverification.cs and Loginstats.cs.
And i write a gump, Namechangegump.

in Charactercreation.cs find:
Code:
        private static void SetName( Mobile m, string name )
        {
                  ..............
        }
and change it to:
Code:
        private static void SetName( Mobile m, string name )
        {
            name = name.Trim();
            if (!CheckDupe(m, name))
                m.Name = "Generic Player";
            else
                m.Name = name;
        }
past after it:

Code:
        public static bool CheckDupe( Mobile m, string name )
        {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            string nametrim = name.Trim();
            string nameToLower = nametrim.ToLower();
 
            if( !NameVerification.Validate( nameToLower, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;
 
            foreach( Mobile mob in World.Mobiles.Values )
            {
                if( mob is PlayerMobile && mob != m && mob.RawName != null && mob.RawName.ToLower() == nameToLower)
                {
                    return false;
                }
            }
 
            return true;
        }

in nameverifaction.cs find:
Code:
        private static string[] m_Disallowed = new string[]
past at least:
Code:
"generic player",
"generic",
"player"

in LoginStats.cs find
Code:
        private static void EventSink_Login( LoginEventArgs args )
        {
            int userCount = NetState.Instances.Count;
            int itemCount = World.Items.Count;
            int mobileCount = World.Mobiles.Count;
 
            Mobile m = args.Mobile;
 
            m.SendMessage( "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.",
                args.Mobile.Name,
                userCount == 1 ? "is" : "are",
                userCount, userCount == 1 ? "" : "s",
                itemCount, itemCount == 1 ? "" : "s",
                mobileCount, mobileCount == 1 ? "" : "s" );
           
               
                PlayerMobile pm = (PlayerMobile)m;
and paste:
Code:
            #region CheckName
            if (!CharacterCreation.CheckDupe(m, m.Name) && m.AccessLevel == AccessLevel.Player)
            {
                m.CantWalk = true;
                m.SendGump( new NameChangeGump( m) );
               
            }
            #endregion

then drop into your custom folder namechangegump.cs

So when a player create a new char, and his given name is in use, it´s open a gump where he have to choose a new name. he also can´t walk until he has changed his name.
 

Attachments

  • namechangegump.cs
    1.6 KB · Views: 52

jayates

Sorceror
I pasted everything as you said added the NameChangeGump file and checked and double checked but keep getting an error saying that the LoginStat file can't find the NameChangeGump. No idea where i'm going wrong... help.
 

m309

Squire
Might need to add...

using Server.Gumps;

...at the top of the LoginStats.cs file if it isn't there already.
 

Vorspire

Knight
Just a heads up on a possible crash that may occur more likely on shards with a higher player count and more active incoming connections, however it can still happen to any shard;

If you're looping through World.Mobiles and the collection is changed at the same time -because another connection created a new character- you'll receive a fatal exception; 'The collection was modified' and the shard will crash.

To prevent this, create a copy of the collection instead;

Code:
List<Mobile> mobs = new List<Mobile>( World.Mobiles.Values );

foreach( Mobile mob in mobs )
{
     //...
}

mobs.Clear();
mobs = null;

Good work :)
 

Miracle99

Squire
Vorspire,

Was checking this out and did all the edits including your List and got this error.

Code:
Errors:
+ Misc/CharacterCreation.cs:
    CS0120: Line 919: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'
    CS0120: Line 927: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'
    CS0120: Line 928: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'

Here is my Setname fuction and checkdupe function. Can you tell me what i might be missing.

Code:
        private static void SetName( Mobile m, string name )
        {
            name = name.Trim();
            if (!CheckDupe(m, name))
                m.Name = "Generic Player";
            else
                m.Name = name;
 
        }
     
        List<Mobile> mobs = new List<Mobile>( World.Mobiles.Values );
 
      public static bool CheckDupe( Mobile m, string name )
        {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            string nametrim = name.Trim();
            string nameToLower = nametrim.ToLower();
 
            if( !NameVerification.Validate( nameToLower, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;
 
            foreach( Mobile mob in mobs )
            {
                if( mob is PlayerMobile && mob != m && mob.RawName != null && mob.RawName.ToLower() == nameToLower)
                {
                    return false;
                }
            }
           
            mobs.Clear();
            mobs = null;
 
            return true;
        }
 

Vorspire

Knight
Vorspire,

Was checking this out and did all the edits including your List and got this error.

Code:
Errors:
+ Misc/CharacterCreation.cs:
    CS0120: Line 919: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'
    CS0120: Line 927: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'
    CS0120: Line 928: An object reference is required for the nonstatic field, m
ethod, or property 'Server.Misc.CharacterCreation.mobs'

The List<Mobile> is supposed to be a local variable inside the same method that uses it, the code I provided was correct and should have been copied in full, not split up :)
 

Corrado

Sorceror
I'm not understanding exactly what you mean Vorspire.

Like, literally copy what you posted, even with the //... part? Where would that all be pasted into?
 

Miracle99

Squire
Vospire,

So is this what it should look like? I started server and got the name screen to come up if its a duplicate from a current player but want to make sure I have it correctly so no crashy crash happens.

Code:
      public static bool CheckDupe( Mobile m, string name )
        {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            string nametrim = name.Trim();
            string nameToLower = nametrim.ToLower();
 
            if( !NameVerification.Validate( nameToLower, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;
 
            List<Mobile> mobs = new List<Mobile>( World.Mobiles.Values );
                   
            foreach( Mobile mob in mobs )
            {
                if( mob is PlayerMobile && mob != m && mob.RawName != null && mob.RawName.ToLower() == nameToLower)
                {
                    return false;
                }
            }
           
            mobs.Clear();
            mobs = null;
 
            return true;
        }
 

Vorspire

Knight
Yea, that all looks good, shouldn't crash.

Now, every time this code runs, it will create a copy of the World.Mobiles.Values collection; usually I wouldn't ever do this with World.Mobiles or World.Items, because it means you have to allocate a large amount of memory when creating the List<Mobile>. This is why I assert calling mobs.Clear(), which will free the resources used by the List<Mobile> collection.

So now it's time to optimize the code, since you only want to look at PlayerMobiles, and not *every* Mobile type;

Rich (BB code):
      public static bool CheckDupe( Mobile m, string name )
      {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            name = name.Trim(); //Trim the name and re-assign it
 
            if( !NameVerification.Validate( name, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;
 
            List<PlayerMobile> players = new List<PlayerMobile>( ); //Initialize a PlayerMobile collection

            foreach( Mobile wm in World.Mobiles.Values )
            {
                 if( wm != m && wm is PlayerMobile && !wm.Deleted ) //Filter Mobiles by PlayerMobile type
                     players.Add( (PlayerMobile)wm );
            }
                   
            foreach( PlayerMobile pm in players )
            {
                if( Insensitive.Equals(pm.RawName, name) ) //Case-insensitive string equality
                {
                    players.Clear(); //Clear the list before the method exits to free allocated memory
                    return false;
                }
            }
           
            players.Clear(); //Clear the list before the method exits to free allocated memory
            return true;
      }


If you're using .NET 4.0+ you can use System.Linq extensions to do all of this code in pretty much one line with next to no overhead:

Rich (BB code):
      public static bool CheckDupe( Mobile m, string name )
      {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            name = name.Trim(); //Trim the name and re-assign it
 
            if( !NameVerification.Validate( name, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;

            return !World.Mobiles.Values.OfType<PlayerMobile>().Any( mob => mob != m && !mob.Deleted && Insensitive.Equals(mob.RawName, name) );
      }

Sorry about the confusion I may have caused previously.
 

Miracle99

Squire
Got an error while trying the optimized version

Code:
Errors:
+ Custom/CustomNameStuff/CharacterCreation.cs:
    CS1502: Line 949: The best overloaded method match for 'System.Collections.G
eneric.List<Server.Mobiles.PlayerMobile>.Add(Server.Mobiles.PlayerMobile)' has s
ome invalid arguments
    CS1503: Line 949: Argument '1': cannot convert from 'Server.Mobile' to 'Serv
er.Mobiles.PlayerMobile'

my line 949 is
players.Add( wm );
 

Miracle99

Squire
Thanks Vorspire that worked perfectly.

Now just thinking ahead. If someone uses a namechangedeed how would i call the CheckDupe function from here
 

Vorspire

Knight
It depends on what class contains the CheckDupe method, since CheckDupe is static, you can call it from pretty much anywhere in any script;

Example only;
Rich (BB code):
bool nameTaken = ContainingClassName.CheckDupe( player, name );
 

Miracle99

Squire
Here is where i would need the CheckDupe. I tried a few things and keep ending up with very bad results. My CheckDupe is in my CharacterCreation class but was unable to think it through on how to properly implement it. I could possibly figure it out with a few more hours of trial and error but figured i would ask since i need a break to take care of the baby.
PS.. a crying baby is never a good method for focusing on code logic :)

Code:
        public override void OnResponse( Mobile from, string newname )
        {
            if ( !NameVerification.Validate( newname, 3, 16, true, false, true, 0, NameVerification.SpaceDashPeriodQuote ) )
            {
            from.SendLocalizedMessage( 3000611 ); // Unacceptable Name
            from.SendMessage("Note: Minlength=3 / MaxLength=16 / No Spaces/ only Letters");
            }
            else
                {
                from.Name = newname;
                from.SendLocalizedMessage( 500038 ); // Success!
                i_deed.Delete();
                }
            }
        }
 

Vorspire

Knight
Yea I hear ya, I have a 2 year old running around me most of the day while I'm working hehe.

The code you just posted had an extra }, but I assume that's because the method is at the end of the script file and you just copied the end } with it, so no problem;

Rich (BB code):
public override void OnResponse( Mobile from, string newname )
{
	if ( !NameVerification.Validate( newname, 3, 16, true, false, true, 0, NameVerification.SpaceDashPeriodQuote ) )
	{
		from.SendLocalizedMessage( 3000611 ); // Unacceptable Name
		from.SendMessage("Note: Minlength=3 / MaxLength=16 / No Spaces/ only Letters");

		//Might be a good idea to send this gump again for a retry?
		//SendTo( from ); //Not guaranteed to work, maybe construct a new instance of this gump?

		return;
	}

	if( !CharacterCreation.CheckDupe( from, newname ) )
	{
		from.SendMessage( "That name has already been taken." );

		//Might be a good idea to send this gump again for a retry?
		//SendTo( from ); //Not guaranteed to work, maybe construct a new instance of this gump?

		return;
	}

	from.SendLocalizedMessage( 500038 ); // Success!
	from.RawName = newname;
	i_deed.Delete();
}
 

Corrado

Sorceror
I attempted to replaced this code:

Code:
        public static bool CheckDupe( Mobile m, string name )
        {
          if( m == null || name == null || name.Length == 0 )
              return false;
 
          string nametrim = name.Trim();
              string nameToLower = nametrim.ToLower();
 
          if( !NameVerification.Validate( nameToLower, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
              return false;
 
          foreach( Mobile mob in World.Mobiles.Values )
              {
                  if( mob is PlayerMobile && mob != m && mob.RawName != null && mob.RawName.ToLower() == nameToLower)
                  {
                      return false;
                  }
              }
 
              return true;
        }

With the code Vorspire posted:

Code:
        public static bool CheckDupe( Mobile m, string name )
        {
            if( m == null || name == null || name.Length == 0 )
                return false;
 
            name = name.Trim(); //Trim the name and re-assign it
 
            if( !NameVerification.Validate( name, 2, 16, true, true, true, 1, NameVerification.SpaceDashPeriodQuote ) )
                return false;
 
            List<PlayerMobile> players = new List<PlayerMobile>( ); //Initialize a PlayerMobile collection
 
            foreach( Mobile wm in World.Mobiles.Values )
            {
                if( wm is PlayerMobile && !wm.Deleted ) //Filter Mobiles by PlayerMobile type
                    players.Add( (PlayerMobile)wm );
            }
                 
            foreach( PlayerMobile pm in players )
            {
                if( Insensitive.Equals(pm.RawName, name) ) //Case-insensitive string equality
                {
                    players.Clear(); //Clear the list before the method exits to free allocated memory
                    return false;
                }
            }
         
            players.Clear(); //Clear the list before the method exits to free allocated memory
            return true;
        }

And I got the following errors:

Line 921: The type or namespace 'List' could not be found (are you missing a using directive or assembly reference?)

Line 921: The type or namespace 'List' could not be found (are you missing a using directive or assembly reference?)

Like 929: foreach statement cannot operate on variables of type List.<Server.Mobiles.Playermobile> because List.<Server.Mobiles.Playermobile> does not contain a public definition for 'GetEnumerator'.

Any ideas?
 

Vorspire

Knight
Yup; You are indeed "missing a using directive or assembly reference"

Code:
using System.Collections.Generic;
 
Top