Files

191 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using KernelPanic.Data;
namespace KernelPanic.Meta
{
public enum PackageLoadoutFailureReason
{
None,
WrongSlot,
NotOwned,
SlotOccupied,
NotEquipped
}
/// <summary>
/// Pure meta model for persistent package slots. Unlike CardLoadout, this is not
/// run-only: equipped package ids are saved per distro and reused in every run.
/// </summary>
public sealed class PackageLoadout
{
private readonly PlayerCollection _collection;
private readonly PackageDatabase _database;
private readonly Dictionary<string, Dictionary<PackageSlot, string>> _equippedByDistro = new(StringComparer.OrdinalIgnoreCase);
public PackageLoadout(PlayerCollection collection, PackageDatabase database)
{
_collection = collection;
_database = database;
}
public IReadOnlyDictionary<PackageSlot, string> GetEquippedPackageIds(string distroId)
{
return !string.IsNullOrWhiteSpace(distroId) && _equippedByDistro.TryGetValue(distroId, out Dictionary<PackageSlot, string> equipped)
? equipped
: Empty;
}
public PackageDefinition GetEquippedPackage(string distroId, PackageSlot slot)
{
if (string.IsNullOrWhiteSpace(distroId)
|| !_equippedByDistro.TryGetValue(distroId, out Dictionary<PackageSlot, string> equipped)
|| !equipped.TryGetValue(slot, out string packageId))
{
return null;
}
return _database == null ? null : _database.FindById(packageId);
}
public IReadOnlyList<PackageDefinition> GetEquippedPackages(string distroId)
{
List<PackageDefinition> packages = new();
AddIfEquipped(distroId, PackageSlot.Kernel, packages);
AddIfEquipped(distroId, PackageSlot.Runtime, packages);
AddIfEquipped(distroId, PackageSlot.Daemon, packages);
return packages;
}
public IReadOnlyList<PackageInstance> GetEquippedPackageInstances(string distroId)
{
List<PackageInstance> packages = new();
AddInstanceIfEquipped(distroId, PackageSlot.Kernel, packages);
AddInstanceIfEquipped(distroId, PackageSlot.Runtime, packages);
AddInstanceIfEquipped(distroId, PackageSlot.Daemon, packages);
return packages;
}
public bool IsEquipped(string packageId)
{
if (string.IsNullOrWhiteSpace(packageId))
{
return false;
}
foreach (KeyValuePair<string, Dictionary<PackageSlot, string>> distro in _equippedByDistro)
{
foreach (KeyValuePair<PackageSlot, string> slot in distro.Value)
{
if (string.Equals(slot.Value, packageId, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
return false;
}
public bool TryEquip(string distroId, PackageSlot slot, string packageId, out PackageLoadoutFailureReason reason)
{
PackageDefinition package = _database == null ? null : _database.FindById(packageId);
if (package == null || _collection == null || !_collection.IsPackageOwned(package.Id))
{
reason = PackageLoadoutFailureReason.NotOwned;
return false;
}
if (package.Slot != slot)
{
reason = PackageLoadoutFailureReason.WrongSlot;
return false;
}
Dictionary<PackageSlot, string> equipped = EnsureDistro(distroId);
if (equipped.TryGetValue(slot, out string current) && !string.Equals(current, package.Id, StringComparison.OrdinalIgnoreCase))
{
reason = PackageLoadoutFailureReason.SlotOccupied;
return false;
}
equipped[slot] = package.Id;
reason = PackageLoadoutFailureReason.None;
return true;
}
public bool TryUnequip(string distroId, PackageSlot slot, out PackageLoadoutFailureReason reason)
{
if (string.IsNullOrWhiteSpace(distroId)
|| !_equippedByDistro.TryGetValue(distroId, out Dictionary<PackageSlot, string> equipped)
|| !equipped.Remove(slot))
{
reason = PackageLoadoutFailureReason.NotEquipped;
return false;
}
reason = PackageLoadoutFailureReason.None;
return true;
}
public void Load(string distroId, IEnumerable<PackageLoadoutSlotSaveEntry> slots)
{
if (string.IsNullOrWhiteSpace(distroId))
{
return;
}
Dictionary<PackageSlot, string> equipped = EnsureDistro(distroId);
equipped.Clear();
foreach (PackageLoadoutSlotSaveEntry slotEntry in slots ?? Array.Empty<PackageLoadoutSlotSaveEntry>())
{
PackageDefinition package = _database == null ? null : _database.FindById(slotEntry?.packageId);
if (package == null || !_collection.IsPackageOwned(package.Id) || package.Slot != slotEntry.slot)
{
continue;
}
equipped[package.Slot] = package.Id;
}
}
public void Clear()
{
_equippedByDistro.Clear();
}
private void AddIfEquipped(string distroId, PackageSlot slot, List<PackageDefinition> packages)
{
PackageDefinition package = GetEquippedPackage(distroId, slot);
if (package != null)
{
packages.Add(package);
}
}
private void AddInstanceIfEquipped(string distroId, PackageSlot slot, List<PackageInstance> packages)
{
PackageDefinition definition = GetEquippedPackage(distroId, slot);
OwnedPackageInstance owned = definition == null ? null : _collection.GetOwnedPackage(definition.Id);
if (owned != null)
{
packages.Add(owned.ToRuntimeInstance());
}
}
private Dictionary<PackageSlot, string> EnsureDistro(string distroId)
{
string key = string.IsNullOrWhiteSpace(distroId) ? string.Empty : distroId;
if (!_equippedByDistro.TryGetValue(key, out Dictionary<PackageSlot, string> equipped))
{
equipped = new Dictionary<PackageSlot, string>();
_equippedByDistro[key] = equipped;
}
return equipped;
}
private static readonly IReadOnlyDictionary<PackageSlot, string> Empty = new Dictionary<PackageSlot, string>();
}
}