Merix

Initiate
Hi,

I try to add Achievements system for account.
This is my base system, where i save all achievements with the id.

Code:
using Server;
using System.Collections.Generic;

namespace Scripts.Systems.Achievements
{
    public class AccountAchievement : Item
    {
        internal Dictionary<int, AchieveData> Achievements = new Dictionary<int, AchieveData>();

        private int m_PointsTotal = 0;

        [Constructable]
        public AccountAchievement()
        {
        }

        public int GetAchievementPoints()
        {
            return m_PointsTotal;
        }

        public void AddPoints(int points)
        {
            m_PointsTotal += points;
        }

        public override void Serialize(GenericWriter writer)
        {

            writer.Write((int)0); // version
          
            writer.Write(m_PointsTotal);

            writer.Write(Achievements.Count);
            foreach (var ach in Achievements)
            {
                writer.Write(ach.Key);
                ach.Value.Serialize(writer);
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            int version = reader.ReadInt();
          
            m_PointsTotal = reader.ReadInt();

            int count = reader.ReadInt();
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    Achievements.Add(reader.ReadInt(), new AchieveData(reader));
                }
            }
        }
    }
}

I'm trying each account have this item/system, to look if the account have the achievement.

My problem is how to add this system in the account.

Regards
Merix
 
Any idea? I think remove the : Item and try, but the problem is serialize and deserialize in the account. The way to save :
Code:
        internal Dictionary<int, AchieveData> Achievements = new Dictionary<int, AchieveData>();
        private int m_PointsTotal = 0;

in the account

Regards
 
I'm still block with this... any have any idea how to make to save the system for each account?
A any example can ve usefull.

Thanks
 
To avoid editing the Account directly, you can leverage ServUO's Persistence feature to achieve a closed-system for storing the data;

Code:
public static class Achievements
{
	public static Dictionary<IAccount, AccountAchievement> States { get; private set; }

	static Achievements()
	{
		States = new Dictionary<IAccount, AccountAchievement>();
	}

	[CallPriority(Int16.MaxValue)] // Make sure it loads after Accounts.Load()
	public static void Configure()
	{
		EventSink.WorldSave += OnWorldSave;
		EventSink.WorldLoad += OnWorldLoad;
	}

	public static AccountAchievement EnsureState(IAccount a)
	{
		AccountAchievement state;

		if(!States.TryGetValue(a, out state) || state == null)
		{
			States[a] = state = new AccountAchievement();
		}

		return state;
	}

	private static void OnWorldSave(WorldSaveEventArgs e)
	{
		Persistence.Serialize("Saves/Achievements/States.bin", writer =>
		{
			writer.Write(0); // version

			writer.Write(States.Count);

			foreach(var state in States)
			{
				writer.Write(state.Key.Username);
				state.Value.Serialize(writer);
			}
		});
	}

	private static void OnWorldLoad()
	{
		Persistence.Deserialize("Saves/Achievements/States.bin", reader =>
		{
			reader.ReadInt(); // version

			var count = reader.ReadInt();

			while(--count >= 0)
			{
				var acc = Accounts.GetAccount(reader.ReadString());
				var state = new AccountAchievement();

				state.Deserialize(reader);

				States[acc] = state;
			}
		});
	}
}

Code was written entirely in the forum BBC editor and may need some changes to function if copy/pasted directly.
There may also be missing using references, as they are not included.

To create/fetch a state for any given account, you can do:
Code:
AccountAchievement state = Achievements.EnsureState( account );
 

Active Shards

Donations

Total amount
$0.00
Goal
$1,000.00
Back