任务系统一半多,商城筛选功能,一些细节和免费包
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
public sealed class ExpBottleLedger : MonoBehaviour
|
||||
{
|
||||
public static ExpBottleLedger Instance { get; private set; }
|
||||
|
||||
public event Action<ExpBottleKind, int> OnBottleCountChanged;
|
||||
public event Action OnLedgerReloaded;
|
||||
|
||||
private readonly Dictionary<string, int> countsByKey = new Dictionary<string, int>(StringComparer.Ordinal);
|
||||
private bool initialized;
|
||||
private bool loadedFromSave;
|
||||
private Player_SO boundPlayerData;
|
||||
|
||||
public bool IsReady
|
||||
{
|
||||
get { return initialized; }
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Bootstrap()
|
||||
{
|
||||
EnsureInstance();
|
||||
}
|
||||
|
||||
public static ExpBottleLedger EnsureInstance()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
return Instance;
|
||||
}
|
||||
|
||||
var host = new GameObject("__runtime_cache_bridge");
|
||||
host.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
|
||||
DontDestroyOnLoad(host);
|
||||
Instance = host.AddComponent<ExpBottleLedger>();
|
||||
return Instance;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
InitializeIfNeeded();
|
||||
}
|
||||
|
||||
private void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
if (pauseStatus)
|
||||
{
|
||||
SaveNow();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public void InitializeIfNeeded()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ExpBottleLedgerPayload payload;
|
||||
loadedFromSave = ExpBottleLedgerStorage.TryLoad(out payload);
|
||||
RebuildFromPayload(payload);
|
||||
initialized = true;
|
||||
SaveNow();
|
||||
if (OnLedgerReloaded != null)
|
||||
{
|
||||
OnLedgerReloaded();
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachPlayerData(Player_SO playerData)
|
||||
{
|
||||
if (playerData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeIfNeeded();
|
||||
boundPlayerData = playerData;
|
||||
|
||||
if (!loadedFromSave)
|
||||
{
|
||||
SeedFromPlayerSo(playerData, false);
|
||||
loadedFromSave = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncToPlayerData();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetCount(ExpBottleKind kind)
|
||||
{
|
||||
return GetCountByKey(ExpBottleCatalog.GetKey(kind));
|
||||
}
|
||||
|
||||
public int GetCountByKey(string key)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
int count;
|
||||
if (!countsByKey.TryGetValue(key, out count))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ExpBottleSnapshotEntry> GetSnapshot()
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
var result = new List<ExpBottleSnapshotEntry>(ExpBottleCatalog.All.Count);
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
var descriptor = ExpBottleCatalog.All[i];
|
||||
result.Add(new ExpBottleSnapshotEntry
|
||||
{
|
||||
key = descriptor.Key,
|
||||
count = GetCountByKey(descriptor.Key)
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Add(ExpBottleKind kind, int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeCount(ExpBottleCatalog.GetKey(kind), amount);
|
||||
}
|
||||
|
||||
public void AddByKey(string key, int amount)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key) || amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeCount(key.Trim(), amount);
|
||||
}
|
||||
|
||||
public bool TryConsume(ExpBottleKind kind, int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var key = ExpBottleCatalog.GetKey(kind);
|
||||
var current = GetCountByKey(key);
|
||||
if (current < amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeCount(key, -amount);
|
||||
DailyTaskEventHub.ReportUseItem(amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryConsumeByKey(string key, int amount)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key) || amount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var safeKey = key.Trim();
|
||||
var current = GetCountByKey(safeKey);
|
||||
if (current < amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeCount(safeKey, -amount);
|
||||
DailyTaskEventHub.ReportUseItem(amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetCount(ExpBottleKind kind, int value)
|
||||
{
|
||||
var safeValue = Mathf.Max(0, value);
|
||||
SetCountByKey(ExpBottleCatalog.GetKey(kind), safeValue);
|
||||
}
|
||||
|
||||
public void ResetAllToZero()
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
countsByKey[ExpBottleCatalog.All[i].Key] = 0;
|
||||
}
|
||||
|
||||
SaveNow();
|
||||
NotifyAllCountsChanged();
|
||||
}
|
||||
|
||||
public bool SeedFromPlayerSo(Player_SO playerData, bool overwriteExistingCounts)
|
||||
{
|
||||
if (playerData == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InitializeIfNeeded();
|
||||
bool changed = false;
|
||||
var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
|
||||
var type = typeof(Player_SO);
|
||||
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
var descriptor = ExpBottleCatalog.All[i];
|
||||
if (string.IsNullOrEmpty(descriptor.LegacyPlayerFieldName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var field = type.GetField(descriptor.LegacyPlayerFieldName, flags);
|
||||
if (field == null || field.FieldType != typeof(int))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var legacyValue = Mathf.Max(0, (int)field.GetValue(playerData));
|
||||
var currentValue = GetCountByKey(descriptor.Key);
|
||||
if (!overwriteExistingCounts && currentValue > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentValue == legacyValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
countsByKey[descriptor.Key] = legacyValue;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SaveNow();
|
||||
NotifyAllCountsChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasEnough(ExpBottleKind kind, int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return GetCount(kind) >= amount;
|
||||
}
|
||||
|
||||
public bool HasEnoughByKey(string key, int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetCountByKey(key.Trim()) >= amount;
|
||||
}
|
||||
|
||||
public void SaveNow()
|
||||
{
|
||||
InitializeIfNeededForSave();
|
||||
ExpBottleLedgerStorage.TrySave(BuildPayload());
|
||||
SyncToPlayerData();
|
||||
}
|
||||
|
||||
private void InitializeIfNeededForSave()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeCount(string key, int delta)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
var current = GetCountByKey(key);
|
||||
long next = (long)current + delta;
|
||||
if (next < 0)
|
||||
{
|
||||
next = 0;
|
||||
}
|
||||
else if (next > int.MaxValue)
|
||||
{
|
||||
next = int.MaxValue;
|
||||
}
|
||||
|
||||
SetCountByKey(key, (int)next);
|
||||
}
|
||||
|
||||
private void SetCountByKey(string key, int value)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
int safeValue = Mathf.Max(0, value);
|
||||
int current = GetCountByKey(key);
|
||||
if (current == safeValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
countsByKey[key] = safeValue;
|
||||
SaveNow();
|
||||
|
||||
ExpBottleKind kind;
|
||||
if (ExpBottleCatalog.TryGetKind(key, out kind) && OnBottleCountChanged != null)
|
||||
{
|
||||
OnBottleCountChanged(kind, safeValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildFromPayload(ExpBottleLedgerPayload payload)
|
||||
{
|
||||
countsByKey.Clear();
|
||||
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
countsByKey[ExpBottleCatalog.All[i].Key] = 0;
|
||||
}
|
||||
|
||||
if (payload == null || payload.entries == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < payload.entries.Count; i++)
|
||||
{
|
||||
var entry = payload.entries[i];
|
||||
if (entry == null || string.IsNullOrEmpty(entry.key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
countsByKey[entry.key] = Mathf.Max(0, entry.count);
|
||||
}
|
||||
}
|
||||
|
||||
private ExpBottleLedgerPayload BuildPayload()
|
||||
{
|
||||
var payload = ExpBottleLedgerStorage.CreateDefaultPayload();
|
||||
payload.entries.Clear();
|
||||
|
||||
var serializedKeys = new HashSet<string>(StringComparer.Ordinal);
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
var descriptor = ExpBottleCatalog.All[i];
|
||||
payload.entries.Add(new ExpBottleEntry
|
||||
{
|
||||
key = descriptor.Key,
|
||||
count = GetCountByKey(descriptor.Key)
|
||||
});
|
||||
serializedKeys.Add(descriptor.Key);
|
||||
}
|
||||
|
||||
foreach (var pair in countsByKey)
|
||||
{
|
||||
if (serializedKeys.Contains(pair.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
payload.entries.Add(new ExpBottleEntry
|
||||
{
|
||||
key = pair.Key,
|
||||
count = Mathf.Max(0, pair.Value)
|
||||
});
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
private void NotifyAllCountsChanged()
|
||||
{
|
||||
if (OnBottleCountChanged == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
var descriptor = ExpBottleCatalog.All[i];
|
||||
OnBottleCountChanged(descriptor.Kind, GetCountByKey(descriptor.Key));
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncToPlayerData()
|
||||
{
|
||||
if (boundPlayerData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ExpBottleCatalog.All.Count; i++)
|
||||
{
|
||||
var descriptor = ExpBottleCatalog.All[i];
|
||||
if (string.IsNullOrEmpty(descriptor.LegacyPlayerFieldName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
boundPlayerData.SetLegacyExpBottleCount(descriptor.LegacyPlayerFieldName, GetCountByKey(descriptor.Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user