First commit for private source control. Older commits available on Github.
This commit is contained in:
BIN
Assets/Scripts/Framework/Managers/Player/.DS_Store
vendored
Normal file
BIN
Assets/Scripts/Framework/Managers/Player/.DS_Store
vendored
Normal file
Binary file not shown.
3
Assets/Scripts/Framework/Managers/Player/Data.meta
Normal file
3
Assets/Scripts/Framework/Managers/Player/Data.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 650e923c83a4463ba1eebe0b4c85277c
|
||||
timeCreated: 1773830133
|
||||
3
Assets/Scripts/Framework/Managers/Player/Data/Codex.meta
Normal file
3
Assets/Scripts/Framework/Managers/Player/Data/Codex.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58a00e94414846c6b914db0fbc38837f
|
||||
timeCreated: 1773682720
|
||||
87
Assets/Scripts/Framework/Managers/Player/Data/Codex/Codex.cs
Normal file
87
Assets/Scripts/Framework/Managers/Player/Data/Codex/Codex.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data.Codex
|
||||
{
|
||||
public class Codex
|
||||
{
|
||||
private readonly List<CodexEntrySo> _entries = new();
|
||||
|
||||
public IReadOnlyList<CodexEntrySo> Entries => _entries;
|
||||
|
||||
public void AddEntry(CodexEntrySo entry)
|
||||
{
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
if (_entries.Any(x => x.UniqueID == entry.UniqueID))
|
||||
return;
|
||||
|
||||
Debug.Log($"Adding codex entry {entry.UniqueID}");
|
||||
|
||||
_entries.Add(entry);
|
||||
}
|
||||
|
||||
public void RemoveEntry(CodexEntrySo entry)
|
||||
{
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
if (_entries.All(x => x.UniqueID != entry.UniqueID))
|
||||
return;
|
||||
|
||||
_entries.Remove(entry);
|
||||
}
|
||||
|
||||
public void RemoveEntry(string uniqueID)
|
||||
{
|
||||
var entry = _entries.FirstOrDefault(x => x.UniqueID == uniqueID);
|
||||
|
||||
if (entry)
|
||||
_entries.Remove(entry);
|
||||
}
|
||||
|
||||
public bool HasEntry(CodexEntrySo entry)
|
||||
{
|
||||
if (entry == null)
|
||||
return false;
|
||||
|
||||
return _entries.Any(x => x.UniqueID == entry.UniqueID);
|
||||
}
|
||||
|
||||
public bool HasEntry(string uniqueID)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(uniqueID))
|
||||
return false;
|
||||
|
||||
return _entries.Any(x => x.UniqueID == uniqueID);
|
||||
}
|
||||
|
||||
public IEnumerable<CodexEntrySo> GetEntriesByType(CodexType codexType)
|
||||
{
|
||||
return _entries.Where(x => x.EntryType == codexType);
|
||||
}
|
||||
|
||||
public IEnumerable<CodexEntrySo> GetBookEntries()
|
||||
{
|
||||
return GetEntriesByType(CodexType.BookEntry);
|
||||
}
|
||||
|
||||
public IEnumerable<CodexEntrySo> GetPuzzleClues()
|
||||
{
|
||||
return GetEntriesByType(CodexType.PuzzleClue);
|
||||
}
|
||||
|
||||
public IEnumerable<CodexEntrySo> GetPhotoEntries()
|
||||
{
|
||||
return GetEntriesByType(CodexType.Photo);
|
||||
}
|
||||
|
||||
public void ClearEntries()
|
||||
{
|
||||
_entries.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15993ce7dcfd437186874d9d0822ad2d
|
||||
timeCreated: 1773682720
|
||||
@@ -0,0 +1,40 @@
|
||||
using BriarQueen.Framework.Managers.Levels.Data;
|
||||
using BriarQueen.Framework.Managers.UI;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data.Codex
|
||||
{
|
||||
public class CodexTrigger : BaseItem, ICodexTrigger
|
||||
{
|
||||
[Header("Codex")]
|
||||
[SerializeField]
|
||||
private CodexEntrySo _codexEntry;
|
||||
|
||||
[SerializeField]
|
||||
private bool _removeTrigger;
|
||||
|
||||
public override UICursorService.CursorStyle ApplicableCursorStyle => UICursorService.CursorStyle.Inspect;
|
||||
|
||||
public override string InteractableName =>
|
||||
!string.IsNullOrWhiteSpace(InteractableTooltip) ? InteractableTooltip : _codexEntry.Title;
|
||||
|
||||
public GameObject TriggerObject => GameObject;
|
||||
public CodexEntrySo Entry => _codexEntry;
|
||||
|
||||
public bool RemoveTrigger => _removeTrigger;
|
||||
|
||||
public override async UniTask OnInteract(ItemDataSo item = null)
|
||||
{
|
||||
if (!CheckEmptyHands())
|
||||
return;
|
||||
|
||||
PlayerManager.UnlockCodexEntry(_codexEntry);
|
||||
|
||||
if (_removeTrigger)
|
||||
{
|
||||
await Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b26357202d94390a9d04c7cd3194b40
|
||||
timeCreated: 1773861326
|
||||
@@ -0,0 +1,13 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data.Codex
|
||||
{
|
||||
public interface ICodexTrigger
|
||||
{
|
||||
GameObject TriggerObject { get; }
|
||||
|
||||
CodexEntrySo Entry { get; }
|
||||
bool RemoveTrigger { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f81e1754251482a9e9bc183c5e1bd5b
|
||||
timeCreated: 1773868877
|
||||
109
Assets/Scripts/Framework/Managers/Player/Data/CodexEntrySO.cs
Normal file
109
Assets/Scripts/Framework/Managers/Player/Data/CodexEntrySO.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Briar Queen/Codex/New Codex Entry", fileName = "New Codex Entry")]
|
||||
public class CodexEntrySo : ScriptableObject
|
||||
{
|
||||
|
||||
[Header("Codex Type")]
|
||||
[SerializeField]
|
||||
private CodexType _codexType;
|
||||
|
||||
[Header("Codex ID")]
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsBookEntry))]
|
||||
private BookEntryID _bookEntryID;
|
||||
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsPuzzleClue))]
|
||||
private ClueEntryID _clueEntryID;
|
||||
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsPhoto))]
|
||||
private PhotoEntryID _photoEntryID;
|
||||
|
||||
|
||||
[Header("Display")]
|
||||
[SerializeField]
|
||||
private string _title;
|
||||
|
||||
[SerializeField]
|
||||
[ShowIf(EConditionOperator.Or, nameof(IsPhoto), nameof(_isPhotoOverride))]
|
||||
private Sprite _displayImage;
|
||||
|
||||
[TextArea(6, 20)]
|
||||
[SerializeField]
|
||||
[ShowIf(EConditionOperator.Or, nameof(IsBookEntry), nameof(_bodyTextOverride))]
|
||||
private string _bodyText;
|
||||
|
||||
[SerializeField]
|
||||
[ShowIf(EConditionOperator.Or, nameof(IsPhoto), nameof(_isPhotoOverride))]
|
||||
private string _photoDescription;
|
||||
|
||||
[SerializeField]
|
||||
[ShowIf(EConditionOperator.Or, nameof(IsPhoto), nameof(_isPhotoOverride))]
|
||||
private string _polaroidWriting;
|
||||
|
||||
[Header("Behaviour")]
|
||||
[SerializeField]
|
||||
private bool _startsUnlocked;
|
||||
|
||||
[SerializeField]
|
||||
private bool _hiddenUntilUnlocked = true;
|
||||
|
||||
[SerializeField]
|
||||
private bool _isPhotoOverride;
|
||||
|
||||
[SerializeField]
|
||||
private bool _bodyTextOverride;
|
||||
|
||||
[SerializeField]
|
||||
private Location _location;
|
||||
|
||||
public CodexType EntryType => _codexType;
|
||||
public Location Location => _location;
|
||||
|
||||
public bool IsBookEntry => _codexType == CodexType.BookEntry;
|
||||
public bool IsPuzzleClue => _codexType == CodexType.PuzzleClue;
|
||||
public bool IsPhoto => _codexType == CodexType.Photo;
|
||||
|
||||
public BookEntryID BookEntryID => _bookEntryID;
|
||||
public ClueEntryID ClueEntryID => _clueEntryID;
|
||||
public PhotoEntryID PhotoEntryID => _photoEntryID;
|
||||
|
||||
public string Title => _title;
|
||||
public Sprite DisplayImage => _displayImage;
|
||||
public string BodyText => _bodyText;
|
||||
public string PhotoDescription => _photoDescription;
|
||||
public string PolaroidWriting => _polaroidWriting;
|
||||
|
||||
public bool StartsUnlocked => _startsUnlocked;
|
||||
public bool HiddenUntilUnlocked => _hiddenUntilUnlocked;
|
||||
public bool IsPhotoOverride => _isPhotoOverride;
|
||||
public bool IsBodyTextOverride => _bodyTextOverride;
|
||||
|
||||
|
||||
public string UniqueID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _codexType switch
|
||||
{
|
||||
CodexType.BookEntry when _bookEntryID != BookEntryID.None =>
|
||||
CodexEntryIDs.Get(_bookEntryID),
|
||||
|
||||
CodexType.PuzzleClue when _clueEntryID != ClueEntryID.None =>
|
||||
CodexEntryIDs.Get(_clueEntryID),
|
||||
|
||||
CodexType.Photo when _photoEntryID != PhotoEntryID.None =>
|
||||
CodexEntryIDs.Get(_photoEntryID),
|
||||
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bdd4c819cc240c1b89ef5a0e33145ef
|
||||
timeCreated: 1773682436
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a795285ea8e94689952d456af9369c92
|
||||
timeCreated: 1769700038
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data.Inventory
|
||||
{
|
||||
public class Backpack
|
||||
{
|
||||
private readonly List<ItemDataSo> _items = new();
|
||||
|
||||
public IReadOnlyList<ItemDataSo> Items => _items;
|
||||
|
||||
|
||||
public void AddItem(ItemDataSo item)
|
||||
{
|
||||
if (_items.Any(x => x.UniqueID == item.UniqueID))
|
||||
return;
|
||||
|
||||
Debug.Log($"Adding item {item.UniqueID}");
|
||||
|
||||
_items.Add(item);
|
||||
}
|
||||
|
||||
public void RemoveItem(ItemDataSo item)
|
||||
{
|
||||
if (_items.All(x => x.UniqueID != item.UniqueID)) return;
|
||||
|
||||
_items.Remove(item);
|
||||
}
|
||||
|
||||
public void RemoveItem(string uniqueID)
|
||||
{
|
||||
var item = _items.FirstOrDefault(x => x.UniqueID == uniqueID);
|
||||
|
||||
if (item) _items.Remove(item);
|
||||
}
|
||||
|
||||
public void ClearItems()
|
||||
{
|
||||
_items.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 855a4eee12334e29938a4b6c564aa157
|
||||
timeCreated: 1769701500
|
||||
82
Assets/Scripts/Framework/Managers/Player/Data/ItemDataSO.cs
Normal file
82
Assets/Scripts/Framework/Managers/Player/Data/ItemDataSO.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Managers.Interaction.Data;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Briar Queen/Items/New Item Data", fileName = "New Item Data")]
|
||||
public class ItemDataSo : ScriptableObject
|
||||
{
|
||||
public enum ItemIdType
|
||||
{
|
||||
None = 0,
|
||||
Pickup = 1,
|
||||
Environment = 2,
|
||||
PuzzleSlot = 3
|
||||
}
|
||||
|
||||
[Header("Item Type")]
|
||||
[SerializeField]
|
||||
private ItemIdType _idType;
|
||||
|
||||
[Header("Item Details")]
|
||||
[Tooltip("Pickup key used for inventory items.")]
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsPickup))]
|
||||
private ItemKey _itemKey;
|
||||
|
||||
[Tooltip("Environment key used for world interactables.")]
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsEnvironment))]
|
||||
private EnvironmentKey _environmentKey;
|
||||
|
||||
[Tooltip("Puzzle slot key used for puzzle slot interactables.")]
|
||||
[SerializeField]
|
||||
[ShowIf(nameof(IsPuzzleSlot))]
|
||||
private PuzzleSlotKey _puzzleSlotKey;
|
||||
|
||||
[SerializeField]
|
||||
private Sprite _icon;
|
||||
|
||||
[SerializeField]
|
||||
private string _itemName;
|
||||
|
||||
[Header("Inventory Interaction (serialized inline, no extra SO assets)")]
|
||||
[SerializeReference]
|
||||
private BaseInteraction _interaction = new NoOpItemInteraction();
|
||||
|
||||
public Sprite Icon => _icon;
|
||||
public string ItemName => _itemName;
|
||||
public BaseInteraction Interaction => _interaction;
|
||||
|
||||
public bool IsPickup => _idType == ItemIdType.Pickup;
|
||||
public bool IsEnvironment => _idType == ItemIdType.Environment;
|
||||
public bool IsPuzzleSlot => _idType == ItemIdType.PuzzleSlot;
|
||||
|
||||
public ItemIdType IdType => _idType;
|
||||
public ItemKey ItemKey => _itemKey;
|
||||
public EnvironmentKey EnvironmentKey => _environmentKey;
|
||||
public PuzzleSlotKey PuzzleSlotKey => _puzzleSlotKey;
|
||||
|
||||
public string UniqueID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _idType switch
|
||||
{
|
||||
ItemIdType.Pickup when _itemKey != ItemKey.None =>
|
||||
ItemIDs.Get(_itemKey),
|
||||
|
||||
ItemIdType.Environment when _environmentKey != EnvironmentKey.None =>
|
||||
ItemIDs.Get(_environmentKey),
|
||||
|
||||
ItemIdType.PuzzleSlot when _puzzleSlotKey != PuzzleSlotKey.None =>
|
||||
ItemIDs.Get(_puzzleSlotKey),
|
||||
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 668f0266fce84811b2efce4a48adff09
|
||||
timeCreated: 1769700109
|
||||
3
Assets/Scripts/Framework/Managers/Player/Data/Tools.meta
Normal file
3
Assets/Scripts/Framework/Managers/Player/Data/Tools.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfd9e5206a504db9a0aa92f0e934776f
|
||||
timeCreated: 1773954968
|
||||
201
Assets/Scripts/Framework/Managers/Player/Data/Tools/Toolbelt.cs
Normal file
201
Assets/Scripts/Framework/Managers/Player/Data/Tools/Toolbelt.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.Gameplay;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.UI;
|
||||
using BriarQueen.Framework.Services.Tutorials;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player.Data.Tools
|
||||
{
|
||||
public class Toolbelt : IDisposable
|
||||
{
|
||||
private readonly Dictionary<ToolID, bool> _unlockedTools = new();
|
||||
private readonly EventCoordinator _eventCoordinator;
|
||||
private readonly TutorialService _tutorialService;
|
||||
|
||||
public IReadOnlyDictionary<ToolID, bool> UnlockedTools => _unlockedTools;
|
||||
|
||||
public ToolID CurrentTool { get; private set; } = ToolID.None;
|
||||
|
||||
public Toolbelt(EventCoordinator eventCoordinator, TutorialService tutorialService)
|
||||
{
|
||||
_eventCoordinator = eventCoordinator;
|
||||
_tutorialService = tutorialService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_eventCoordinator.Subscribe<OnNextToolChangedEvent>(OnNextToolChanged);
|
||||
_eventCoordinator.Subscribe<OnPreviousToolChangedEvent>(OnPreviousToolChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_eventCoordinator.Unsubscribe<OnNextToolChangedEvent>(OnNextToolChanged);
|
||||
_eventCoordinator.Unsubscribe<OnPreviousToolChangedEvent>(OnPreviousToolChanged);
|
||||
}
|
||||
|
||||
public void Unlock(ToolID id)
|
||||
{
|
||||
if (id == ToolID.None)
|
||||
return;
|
||||
|
||||
_unlockedTools[id] = true;
|
||||
Debug.Log($"{this} Tool {id} has been unlocked");
|
||||
}
|
||||
|
||||
public void Lock(ToolID id)
|
||||
{
|
||||
if (id == ToolID.None)
|
||||
return;
|
||||
|
||||
if (_unlockedTools.ContainsKey(id))
|
||||
_unlockedTools[id] = false;
|
||||
|
||||
if (CurrentTool == id)
|
||||
SelectNextTool();
|
||||
}
|
||||
|
||||
public bool HasAccess(ToolID id)
|
||||
{
|
||||
if (id == ToolID.None)
|
||||
return true;
|
||||
|
||||
return _unlockedTools.TryGetValue(id, out var unlocked) && unlocked;
|
||||
}
|
||||
|
||||
public bool IsKnown(ToolID id)
|
||||
{
|
||||
if (id == ToolID.None)
|
||||
return true;
|
||||
|
||||
return _unlockedTools.ContainsKey(id);
|
||||
}
|
||||
|
||||
public void SelectTool(ToolID id)
|
||||
{
|
||||
if (!HasAccess(id))
|
||||
return;
|
||||
|
||||
SetCurrentTool(id, 0);
|
||||
}
|
||||
|
||||
public void SelectEmptyHands()
|
||||
{
|
||||
SetCurrentTool(ToolID.None, 0);
|
||||
}
|
||||
|
||||
public void SelectNextTool()
|
||||
{
|
||||
Debug.Log($"SelectNextTool: {CurrentTool}");
|
||||
CycleTool(1);
|
||||
}
|
||||
|
||||
public void SelectPreviousTool()
|
||||
{
|
||||
CycleTool(-1);
|
||||
}
|
||||
|
||||
private void OnNextToolChanged(OnNextToolChangedEvent e)
|
||||
{
|
||||
SelectNextTool();
|
||||
}
|
||||
|
||||
private void OnPreviousToolChanged(OnPreviousToolChangedEvent e)
|
||||
{
|
||||
SelectPreviousTool();
|
||||
}
|
||||
|
||||
private void CycleTool(int direction)
|
||||
{
|
||||
var selectableTools = GetSelectableTools();
|
||||
|
||||
Debug.Log($"CycleTool: {selectableTools.Count}");
|
||||
|
||||
foreach (var selectableTool in selectableTools)
|
||||
{
|
||||
Debug.Log($"CycleTool: {selectableTool}");
|
||||
}
|
||||
|
||||
if (selectableTools.Count == 0)
|
||||
{
|
||||
SetCurrentTool(ToolID.None, direction);
|
||||
return;
|
||||
}
|
||||
|
||||
int currentIndex = selectableTools.IndexOf(CurrentTool);
|
||||
|
||||
if (currentIndex < 0)
|
||||
{
|
||||
int fallbackIndex = direction > 0 ? 0 : selectableTools.Count - 1;
|
||||
SetCurrentTool(selectableTools[fallbackIndex], direction);
|
||||
return;
|
||||
}
|
||||
|
||||
int nextIndex = currentIndex + direction;
|
||||
|
||||
if (nextIndex < 0)
|
||||
nextIndex = selectableTools.Count - 1;
|
||||
else if (nextIndex >= selectableTools.Count)
|
||||
nextIndex = 0;
|
||||
|
||||
Debug.Log($"CycleTool: Setting tool to {selectableTools[nextIndex]}");
|
||||
|
||||
SetCurrentTool(selectableTools[nextIndex], direction);
|
||||
}
|
||||
|
||||
private void CheckToolsCycling()
|
||||
{
|
||||
_tutorialService.DisplayTutorial(TutorialPopupID.ToolCycling);
|
||||
}
|
||||
|
||||
private void SetCurrentTool(ToolID newTool, int direction)
|
||||
{
|
||||
if (CurrentTool == newTool)
|
||||
return;
|
||||
|
||||
CurrentTool = newTool;
|
||||
CheckToolsCycling();
|
||||
|
||||
_eventCoordinator.Publish(new SelectedToolChangedEvent(CurrentTool, direction));
|
||||
|
||||
if (newTool == ToolID.None)
|
||||
{
|
||||
_eventCoordinator.Publish(
|
||||
new OverrideCursorStyleChangeEvent(UICursorService.CursorStyle.Default));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Enum.TryParse(newTool.ToString(), out UICursorService.CursorStyle style))
|
||||
{
|
||||
_eventCoordinator.Publish(new OverrideCursorStyleChangeEvent(style));
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventCoordinator.Publish(
|
||||
new OverrideCursorStyleChangeEvent(UICursorService.CursorStyle.Default));
|
||||
}
|
||||
}
|
||||
|
||||
private List<ToolID> GetSelectableTools()
|
||||
{
|
||||
var tools = _unlockedTools
|
||||
.Where(x => x.Value && x.Key != ToolID.None)
|
||||
.Select(x => x.Key)
|
||||
.OrderBy(x => (int)x)
|
||||
.ToList();
|
||||
|
||||
Debug.Log($"{_unlockedTools.Count} tools have been unlocked");
|
||||
|
||||
tools.Insert(0, ToolID.None);
|
||||
|
||||
Debug.Log($"[Get Selectable Tools: {tools.Count}]");
|
||||
|
||||
return tools;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 565885be67c447bbbb3a64e39ae1f734
|
||||
timeCreated: 1773954972
|
||||
449
Assets/Scripts/Framework/Managers/Player/PlayerManager.cs
Normal file
449
Assets/Scripts/Framework/Managers/Player/PlayerManager.cs
Normal file
@@ -0,0 +1,449 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Data.IO.Saves;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.Gameplay;
|
||||
using BriarQueen.Framework.Events.Save;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Audio;
|
||||
using BriarQueen.Framework.Managers.IO;
|
||||
using BriarQueen.Framework.Managers.Player.Data;
|
||||
using BriarQueen.Framework.Managers.Player.Data.Codex;
|
||||
using BriarQueen.Framework.Managers.Player.Data.Inventory;
|
||||
using BriarQueen.Framework.Managers.Player.Data.Tools;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using BriarQueen.Framework.Services.Tutorials;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
|
||||
namespace BriarQueen.Framework.Managers.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Owns player state (inventory + codex + tools) and keeps it in sync with save data.
|
||||
/// </summary>
|
||||
public class PlayerManager : IDisposable, IManager
|
||||
{
|
||||
private readonly CodexRegistry _codexRegistry;
|
||||
private readonly EventCoordinator _eventCoordinator;
|
||||
private readonly ItemRegistry _itemRegistry;
|
||||
private readonly SaveManager _saveManager;
|
||||
private readonly AudioManager _audioManager;
|
||||
private readonly TutorialService _tutorialService;
|
||||
|
||||
private Backpack _backpack;
|
||||
private Codex _codex;
|
||||
private Toolbelt _toolbelt;
|
||||
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
[Inject]
|
||||
public PlayerManager(
|
||||
SaveManager saveManager,
|
||||
ItemRegistry itemRegistry,
|
||||
CodexRegistry codexRegistry,
|
||||
EventCoordinator eventCoordinator,
|
||||
TutorialService tutorialService,
|
||||
AudioManager audioManager)
|
||||
{
|
||||
_saveManager = saveManager;
|
||||
_itemRegistry = itemRegistry;
|
||||
_codexRegistry = codexRegistry;
|
||||
_eventCoordinator = eventCoordinator;
|
||||
_tutorialService = tutorialService;
|
||||
_audioManager = audioManager;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (Initialized)
|
||||
return;
|
||||
|
||||
_saveManager.OnSaveGameLoaded += LoadFromSave;
|
||||
_saveManager.OnSaveRequested += UpdateSaveGame;
|
||||
|
||||
_backpack ??= new Backpack();
|
||||
_codex ??= new Codex();
|
||||
|
||||
EnsureToolbelt();
|
||||
|
||||
if (_saveManager.IsGameLoaded && _saveManager.CurrentSave != null)
|
||||
LoadFromSave(_saveManager.CurrentSave);
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
|
||||
_saveManager.OnSaveGameLoaded -= LoadFromSave;
|
||||
_saveManager.OnSaveRequested -= UpdateSaveGame;
|
||||
|
||||
_toolbelt?.Dispose();
|
||||
_toolbelt = null;
|
||||
|
||||
Initialized = false;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ItemDataSo> GetInventoryItems()
|
||||
{
|
||||
return _backpack?.Items ?? Array.Empty<ItemDataSo>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<ItemDataSo> GetAllCollectedItems()
|
||||
{
|
||||
var collectedItems = new List<ItemDataSo>();
|
||||
var saveCollected = _saveManager.CurrentSave?.CollectedItems;
|
||||
|
||||
if (saveCollected == null)
|
||||
return collectedItems;
|
||||
|
||||
foreach (var item in saveCollected)
|
||||
{
|
||||
var template = _itemRegistry.FindItemTemplateByID(item.UniqueIdentifier);
|
||||
if (template != null)
|
||||
collectedItems.Add(template);
|
||||
}
|
||||
|
||||
return collectedItems;
|
||||
}
|
||||
|
||||
public IReadOnlyList<CodexEntrySo> GetDiscoveredCodexEntries()
|
||||
{
|
||||
return _codex?.Entries ?? Array.Empty<CodexEntrySo>();
|
||||
}
|
||||
|
||||
public IEnumerable<CodexEntrySo> GetDiscoveredCodexEntriesByType(CodexType codexType)
|
||||
{
|
||||
return _codex?.GetEntriesByType(codexType) ?? Enumerable.Empty<CodexEntrySo>();
|
||||
}
|
||||
|
||||
public bool HasCodexEntry(string uniqueIdentifier)
|
||||
{
|
||||
return _codex != null && _codex.HasEntry(uniqueIdentifier);
|
||||
}
|
||||
|
||||
public bool HasCodexEntry(CodexEntrySo entry)
|
||||
{
|
||||
return _codex != null && _codex.HasEntry(entry);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<ToolID, bool> GetTools()
|
||||
{
|
||||
EnsureToolbelt();
|
||||
return _toolbelt.UnlockedTools;
|
||||
}
|
||||
|
||||
public bool HasAccessToTool(ToolID id)
|
||||
{
|
||||
return _toolbelt != null && _toolbelt.HasAccess(id);
|
||||
}
|
||||
|
||||
#region Inventory / Selection
|
||||
|
||||
public void CollectItem(string uniqueIdentifier)
|
||||
{
|
||||
var item = _itemRegistry.FindItemTemplateByID(uniqueIdentifier);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
CollectItem(item);
|
||||
}
|
||||
|
||||
public void CollectItem(ItemDataSo item)
|
||||
{
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
_backpack ??= new Backpack();
|
||||
_backpack.AddItem(item);
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save != null)
|
||||
{
|
||||
save.CollectedItems ??= new List<ItemSaveData>();
|
||||
|
||||
if (save.CollectedItems.All(x => x.UniqueIdentifier != item.UniqueID))
|
||||
{
|
||||
save.CollectedItems.Add(new ItemSaveData
|
||||
{
|
||||
UniqueIdentifier = item.UniqueID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_audioManager.Play(AudioNameIdentifiers.Get(SFXKey.ItemCollected));
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
_eventCoordinator.Publish(new InventoryChangedEvent());
|
||||
}
|
||||
|
||||
public void RemoveItem(string uniqueIdentifier)
|
||||
{
|
||||
var item = _backpack?.Items.FirstOrDefault(x => x.UniqueID == uniqueIdentifier);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
RemoveItem(item);
|
||||
}
|
||||
|
||||
public void RemoveItem(ItemDataSo item)
|
||||
{
|
||||
if (item == null || _backpack == null)
|
||||
return;
|
||||
|
||||
_backpack.RemoveItem(item);
|
||||
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
_eventCoordinator.Publish(new InventoryChangedEvent());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Codex
|
||||
|
||||
public void UnlockCodexEntry(string uniqueIdentifier)
|
||||
{
|
||||
var entry = _codexRegistry.FindEntryByID(uniqueIdentifier);
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
UnlockCodexEntry(entry);
|
||||
}
|
||||
|
||||
public void UnlockCodexEntry(CodexEntrySo entry)
|
||||
{
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
_codex ??= new Codex();
|
||||
|
||||
if (_codex.HasEntry(entry))
|
||||
return;
|
||||
|
||||
_codex.AddEntry(entry);
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save != null)
|
||||
{
|
||||
save.DiscoveredCodexEntries ??= new List<CodexSaveData>();
|
||||
|
||||
if (save.DiscoveredCodexEntries.All(x => x.UniqueIdentifier != entry.UniqueID))
|
||||
{
|
||||
save.DiscoveredCodexEntries.Add(new CodexSaveData
|
||||
{
|
||||
UniqueIdentifier = entry.UniqueID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_tutorialService.DisplayTutorial(TutorialPopupID.Codex);
|
||||
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
_eventCoordinator.Publish(new CodexChangedEvent(entry.EntryType));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tools
|
||||
|
||||
public ToolID GetEquippedTool()
|
||||
{
|
||||
EnsureToolbelt();
|
||||
return _toolbelt.CurrentTool;
|
||||
}
|
||||
|
||||
public void UnlockTool(ToolID id)
|
||||
{
|
||||
EnsureToolbelt();
|
||||
|
||||
if (_toolbelt.HasAccess(id))
|
||||
return;
|
||||
|
||||
_toolbelt.Unlock(id);
|
||||
Debug.Log($"Tool {id} has been unlocked");
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save != null)
|
||||
{
|
||||
save.Tools ??= new Dictionary<ToolID, bool>();
|
||||
save.Tools[id] = true;
|
||||
}
|
||||
|
||||
Debug.Log($"Tool {id} access after unlock = {_toolbelt.HasAccess(id)}");
|
||||
|
||||
_eventCoordinator.Publish(new ToolbeltChangedEvent(id, false));
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
}
|
||||
|
||||
public void LockTool(ToolID id)
|
||||
{
|
||||
EnsureToolbelt();
|
||||
|
||||
if (!_toolbelt.UnlockedTools.TryGetValue(id, out var unlocked) || !unlocked)
|
||||
return;
|
||||
|
||||
_toolbelt.Lock(id);
|
||||
|
||||
var save = _saveManager.CurrentSave;
|
||||
if (save != null)
|
||||
{
|
||||
save.Tools ??= new Dictionary<ToolID, bool>();
|
||||
save.Tools[id] = false;
|
||||
}
|
||||
|
||||
_eventCoordinator.Publish(new ToolbeltChangedEvent(id, true));
|
||||
_eventCoordinator.PublishImmediate(new RequestGameSaveEvent());
|
||||
}
|
||||
|
||||
private void LoadToolsFromSave(SaveGame save)
|
||||
{
|
||||
_toolbelt?.Dispose();
|
||||
_toolbelt = new Toolbelt(_eventCoordinator, _tutorialService);
|
||||
_toolbelt.Initialize();
|
||||
|
||||
if (save.Tools == null)
|
||||
return;
|
||||
|
||||
foreach (var kvp in save.Tools)
|
||||
{
|
||||
if (kvp.Value)
|
||||
_toolbelt.Unlock(kvp.Key);
|
||||
else
|
||||
_toolbelt.Lock(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureToolbelt()
|
||||
{
|
||||
if (_toolbelt != null)
|
||||
return;
|
||||
|
||||
_toolbelt = new Toolbelt(_eventCoordinator, _tutorialService);
|
||||
_toolbelt.Initialize();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Saving / Loading
|
||||
|
||||
private void LoadFromSave(SaveGame save)
|
||||
{
|
||||
if (save == null)
|
||||
return;
|
||||
|
||||
LoadItemsFromSave(save);
|
||||
LoadCodexFromSave(save);
|
||||
LoadToolsFromSave(save);
|
||||
}
|
||||
|
||||
private void LoadItemsFromSave(SaveGame save)
|
||||
{
|
||||
_backpack = new Backpack();
|
||||
|
||||
Debug.Log($"[PlayerManager] LoadItemsFromSave InventoryData count = {save.InventoryData?.Count ?? 0}");
|
||||
|
||||
if (save.InventoryData != null)
|
||||
{
|
||||
foreach (var item in save.InventoryData)
|
||||
{
|
||||
Debug.Log($"[PlayerManager] Loading InventoryData item '{item.UniqueIdentifier}'");
|
||||
|
||||
var itemData = _itemRegistry.FindItemTemplateByID(item.UniqueIdentifier);
|
||||
if (!itemData)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerManager] Missing item template '{item.UniqueIdentifier}', skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
_backpack.AddItem(itemData);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[PlayerManager] Backpack count after load = {_backpack.Items?.Count ?? 0}");
|
||||
|
||||
_eventCoordinator.Publish(new SelectedItemChangedEvent(null));
|
||||
_eventCoordinator.Publish(new InventoryChangedEvent());
|
||||
}
|
||||
|
||||
private void LoadCodexFromSave(SaveGame save)
|
||||
{
|
||||
_codex = new Codex();
|
||||
|
||||
if (save.DiscoveredCodexEntries != null)
|
||||
{
|
||||
foreach (var codexEntry in save.DiscoveredCodexEntries)
|
||||
{
|
||||
var entryData = _codexRegistry.FindEntryByID(codexEntry.UniqueIdentifier);
|
||||
if (!entryData)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerManager] Missing codex entry '{codexEntry.UniqueIdentifier}', skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
_codex.AddEntry(entryData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSaveGame(SaveGame save)
|
||||
{
|
||||
if (save == null)
|
||||
return;
|
||||
|
||||
Debug.Log($"[PlayerManager] UpdateSaveGame backpack count = {_backpack?.Items?.Count ?? 0}");
|
||||
|
||||
save.InventoryData = new List<ItemSaveData>();
|
||||
|
||||
if (_backpack?.Items != null)
|
||||
{
|
||||
foreach (var item in _backpack.Items)
|
||||
{
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
Debug.Log($"[PlayerManager] Writing InventoryData item '{item.UniqueID}'");
|
||||
|
||||
save.InventoryData.Add(new ItemSaveData
|
||||
{
|
||||
UniqueIdentifier = item.UniqueID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[PlayerManager] Final InventoryData count = {save.InventoryData.Count}");
|
||||
|
||||
save.DiscoveredCodexEntries ??= new List<CodexSaveData>();
|
||||
save.DiscoveredCodexEntries.Clear();
|
||||
|
||||
if (_codex?.Entries != null)
|
||||
{
|
||||
foreach (var entry in _codex.Entries)
|
||||
{
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
save.DiscoveredCodexEntries.Add(new CodexSaveData
|
||||
{
|
||||
UniqueIdentifier = entry.UniqueID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
save.Tools ??= new Dictionary<ToolID, bool>();
|
||||
save.Tools.Clear();
|
||||
|
||||
if (_toolbelt?.UnlockedTools != null)
|
||||
{
|
||||
foreach (var kvp in _toolbelt.UnlockedTools)
|
||||
{
|
||||
save.Tools[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ec45c587ec54a4eb6ffbdedf10eed57
|
||||
timeCreated: 1769703840
|
||||
Reference in New Issue
Block a user