using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ACE.Entity;
using ACE.Server.Managers;
using ACE.Server.WorldObjects;
namespace ACE.Server.Network.Structure
{
///
/// The restriction DB contains the access control list for a house
///
public class RestrictionDB
{
public uint HouseOwner;
public uint Version = 0x10000002; // If high word is not 0, this value indicates the version of the message.
public bool OpenStatus; // 0 = private dwelling, 1 = open to public
public ObjectGuid MonarchID; // Allegiance monarch (if allegiance access granted)
public Dictionary Table; // Set of permissions on a per user basis. Key is the character id,
// value is 0 = dwelling access only, 1 = storage access as well
public RestrictionDB()
{
Table = new Dictionary();
HouseOwner = 0;
}
public RestrictionDB(House house)
{
Table = new Dictionary();
if (house == null) return;
HouseOwner = house.HouseOwner ?? 0;
OpenStatus = house.OpenStatus;
if (house.MonarchId != null)
MonarchID = new ObjectGuid(house.MonarchId.Value); // for allegiance guest/storage access
foreach (var guest in house.Guests)
{
if (guest.Key != MonarchID)
Table.Add(guest.Key, Convert.ToUInt32(guest.Value));
}
if (house.HouseOwner == null) return;
// add in players on house owner's account
var owner = PlayerManager.FindByGuid(house.HouseOwner.Value);
// added for people deleting accounts from their account db...
if (owner == null || owner.Account == null)
{
Console.WriteLine($"RestrictionDB({house.HouseInstance:X8}): couldn't find house owner {house.HouseOwner:X8}");
return;
}
var accountPlayers = PlayerManager.GetAccountPlayers(owner.Account.AccountId);
foreach (var accountPlayer in accountPlayers)
{
if (accountPlayer.Key == HouseOwner)
continue;
Table.TryAdd(accountPlayer.Value.Guid, 1);
}
}
}
public static class RestrictionDBExtensions
{
public static void Write(this BinaryWriter writer, RestrictionDB restrictions)
{
writer.Write(restrictions.Version);
writer.Write(Convert.ToUInt32(restrictions.OpenStatus));
writer.Write(restrictions.MonarchID.Full);
writer.Write(restrictions.Table);
}
private const ushort headerNumBuckets = 768; // this # of buckets was sent over the wire in retail header
// however, this value ends up being unused, and the "real" # of buckets originates
// from a hardcoded value in g_bucketSizeArray in the client constant data
private const ushort actualNumBuckets = 89; // in RestrictionDB constructor in acclient,
// client uses PHashTable for this (as opposed to the typical PackableHashTable)
// which inits an IntrusiveHashTable with size 64
// this gets bumped up to the next largest value in a hardcoded g_bucketSizeArray, which is 89
private static readonly GuidComparer guidComparer = new GuidComparer(actualNumBuckets);
public static void Write(this BinaryWriter writer, Dictionary db)
{
PackableHashTable.WriteHeader(writer, db.Count, headerNumBuckets);
var sorted = new SortedDictionary(db, guidComparer);
foreach (var kvp in sorted)
{
writer.Write(kvp.Key.Full);
writer.Write(kvp.Value);
}
}
}
}