Add a GM tag to users who have UserPermissions

From NetGore Wiki

Jump to: navigation, search
NetGore Tutorial
Difficulty 2/5
Topics Game content,Entities
(view all tutorials)


This is intended as a guide for people who want to add "[INSERT_CUSTOM_TAG]" tags to users names in-game i.e. for moderators wanting to show the different levels of permissions their game has. The most famous example being "[GM] DarkSummon", where DarkSummon is the game moderators username.

This tutorial could also start the process of a new tutorial, involving adding and changing user permissions in NetGore.

Contents

Creating the PropertySync Class

Ok, so the first thing we need to do is create a 'PropertySyncUserPermissions' class. This is so we can add the [SyncValue] to the UserPermission property in NetGore, which will handle all the synchronising of data between the client and server. For more information, see Synchronizing Values. The class needs to be saved in the DemoGame project.

Navigate to the 'DemoGame' project and then Right click the 'IO' folder and select 'Add --> Class..' then simply click 'Class' and name it "PropertySyncUserPermissions.cs". Finish by clicking 'Add'.

Remove the generated code with the following:

using System.Linq;
using DemoGame;
 
namespace NetGore.IO.PropertySync
{
    /// <summary>
    /// Implementation of a <see cref="PropertySyncBase{T}"/> that handles synchronizing an <see cref="UserPermissions"/>.
    /// </summary>
    [PropertySyncHandler(typeof(UserPermissions))]
    public sealed class PropertySyncUserPermissions : PropertySyncBase<UserPermissions>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertySyncUserPermissions"/> class.
        /// </summary>
        /// <param name="syncValueAttributeInfo">The <see cref="SyncValueAttributeInfo"/>.</param>
        public PropertySyncUserPermissions(SyncValueAttributeInfo syncValueAttributeInfo)
            : base(syncValueAttributeInfo)
        {
        }
 
        /// <summary>
        /// When overridden in the derived class, reads a value with the specified name from an IValueReader.
        /// </summary>
        /// <param name="name">Name of the value.</param>
        /// <param name="reader">IValueReader to read from.</param>
        /// <returns>Value read from the IValueReader.</returns>
        protected override UserPermissions Read(string name, IValueReader reader)
        {
            return reader.ReadEnum<UserPermissions>(name);
        }
 
        /// <summary>
        /// When overridden in the derived class, writes a value to an IValueWriter with the specified name.
        /// </summary>
        /// <param name="name">Name of the value.</param>
        /// <param name="writer">IValueWriter to write to.</param>
        /// <param name="value">Value to write.</param>
        protected override void Write(string name, IValueWriter writer, UserPermissions value)
        {
            writer.WriteEnum(name, value);
        }
    }
}

DemoGame.Server.World.Map.Entities.Characters.Character

Next we need to add a Permissions property to the Character class in the server.

Find:

string _name;

Just After, Add:

<nowiki>
/// <summary>
/// Gets or sets the user permissions of the character.
/// </summary>
public override UserPermissions Permissions
{
    get
    {
        // Default to None
        return UserPermissions.None;
    }
    set
    {
        // Derived classes must override to allow for additional permissions (e.g.: NPCs won't track permisisons, users will)
    }
}
</nowiki>

DemoGame.Server.World.Map.Entities.Characters.User

Next we need to change the Permissions property that is in the User class in the server.

Find:

/// <summary>
/// Gets the <see cref="UserPermissions"/> level for this user.
/// </summary>
public UserPermissions Permissions
{
	get
	{
		var acc = UserAccount;
		if (acc == null)
			return UserPermissions.None;
 
		return acc.Permissions;
	}
}

Replace With:

/// <summary>
/// Gets the <see cref="UserPermissions"/> level for this user.
/// </summary>
public override UserPermissions Permissions
{
    get
    {
        var acc = UserAccount;
        if (acc == null)
            return UserPermissions.None;
 
        return acc.Permissions;
    }
    set
    {
        var acc = UserAccount;
        if (acc == null)
        {
            return;
        }
 
        acc.SetPermissions(value);
    }
}

DemoGame.World.Map.Entities.CharacterEntity

Next we need to add another Permissions property which will act as a getter and setter for the Permissions value. Note that this is where we use the [SyncValue] attribute which will enable NetGore to do all the hard work for us!

Find:

[SyncValue]
public virtual string Name { get; set; }

Just After, Add:

/// <summary>
/// Gets or sets the permission of the CharacterEntity.
/// </summary>
[SyncValue]
public abstract UserPermissions Permissions { get; set; }

DemoGame.Client.World.Map.Entities.Character

And finally, we add the code to the client which displays the [TAG] on-screen. I'll post an example of the whole property, where it simply displays a "[GM]" tag in front of all users who have special permissions, which are:

Moderator
LesserAdmin
Admin
Owner

A user who doesn't have a special permission is defined as 'None', which is default for all new users.

Find:

/// <summary>
/// Draws the Character's name.
/// </summary>
/// <param name="sb"><see cref="ISpriteBatch"/> to draw to.</param>
/// <param name="font">The <see cref="Font"/> to use for the name text. May be null.</param>
protected virtual void DrawName(ISpriteBatch sb, Font font)
{
	// Ensure we have a valid font and name first
	if (font == null || string.IsNullOrEmpty(Name))
		return;
 
	// Get the size of the name
	var nameSize = GetNameSize();
 
	// Get the character's center
	var namePos = DrawPosition;
 
	// Center horizontally
	namePos.X += Size.X / 2f; // Move the left side of the name to the center of the character
	namePos.X -= (float)Math.Round(nameSize.X / 2f); // Move the center to the center of the character
 
	// Move up above the character's head (height of the text, with a little extra offset)
	namePos.Y -= nameSize.Y + 4f;
 
	// Draw
	sb.DrawStringShaded(font, Name, namePos, Color.Green, Color.Black);
}

Replace With:

/// <summary>
/// Draws the Character's name.
/// </summary>
/// <param name="sb"><see cref="ISpriteBatch"/> to draw to.</param>
/// <param name="font">The <see cref="Font"/> to use for the name text. May be null.</param>
protected virtual void DrawName(ISpriteBatch sb, Font font)
{
    // Ensure we have a valid font and name first
    if (font == null || string.IsNullOrEmpty(Name))
        return;
 
    // Get the size of the name
    var nameSize = GetNameSize();
 
    string GM = "[GM] ";
    var gmSize = NameFont.MeasureString(GM);
 
    // Get the character's center
    var namePos = DrawPosition;
 
    // Center horizontally
    namePos.X += Size.X / 2f; // Move the left side of the name to the center of the character
    namePos.X -= (float)Math.Round(nameSize.X / 2f); // Move the center to the center of the character
 
    // Move up above the character's head (height of the text, with a little extra offset)
    namePos.Y -= nameSize.Y + 4f;
 
    var gmPos = DrawPosition;
 
    gmPos.X = namePos.X - gmSize.X;
    gmPos.Y = namePos.Y;
 
    // Check the users permission level
    if (Permissions.IsSet(UserPermissions.Moderator))
    {
        // Draw
        sb.DrawStringShaded(font, GM, gmPos, Color.Red, Color.Black);
        sb.DrawStringShaded(font, Name, namePos, Color.Yellow, Color.Black);
    }
    else
    {
        sb.DrawStringShaded(font, Name, namePos, Color.Green, Color.Black);
    }
}

From this, you can add more if statements for each individual permission that you have set. You can also have it display in various colours and even different tag names i.e. [MOD], [Owner], [Event], etc.

Lastly, we need to add one more block of code to act as another getter and setter for the Permission value on the client.

Find:

/// <summary>
/// Gets the position for the Camera to focus on this Character.
/// </summary>
/// <param name="camera">The <see cref="ICamera2D"/> to get the position for.</param>
/// <returns>
/// Position for the Camera to focus on this Character.
/// </returns>
public Vector2 GetCameraPos(ICamera2D camera)
{
	var pos = DrawPosition + (Size / 2.0f) - (camera.Size / 2.0f);
	return pos.Round();
}

Just After, Add:

UserPermissions _permissions;
 
/// <summary>
/// Gets or sets the <see cref="UserPermissions"/> for this character.
/// Should only be set automatically by PropertySync; never manually.
/// </summary>
public override UserPermissions Permissions
{
	get
	{
		return _permissions;
	}
	set
	{
		_permissions = value;
	}
}

Database Values

If you want to change an account to have a different permission level, in the database go to the 'account' table and change the values of the 'permissions' column. Here are the values for each permission level:

None: 0
Moderator: 1
LesserAdmin: 3
Admin: 7
Owner: 15

See Also

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox