mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-21 20:44:38 -05:00
Misc reorg + skeleton for slot editor
SlotChangeManager is pretty glue-y, might eventually shift to this implementation
This commit is contained in:
@@ -25,5 +25,7 @@ public SlotChange(SlotChange info, SaveFile sav)
|
||||
Offset = info.Offset;
|
||||
PKM = sav.GetStoredSlot(info.Offset);
|
||||
}
|
||||
|
||||
public SlotChange GetInverseData(SaveFile sav) => new SlotChange(this, sav);
|
||||
}
|
||||
}
|
||||
224
PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs
Normal file
224
PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Pushes slot update notifications out to all subscribers.
|
||||
/// </summary>
|
||||
public sealed class SlotPublisher
|
||||
{
|
||||
/// <summary>
|
||||
/// All <see cref="ISlotViewer"/> instances that provide a view on individual <see cref="StorageSlotOffset"/> content.
|
||||
/// </summary>
|
||||
public List<ISlotViewer> Subscribers { get; } = new List<ISlotViewer>();
|
||||
|
||||
private SlotChange Previous;
|
||||
private SlotTouchType PreviousType = SlotTouchType.None;
|
||||
|
||||
/// <summary>
|
||||
/// Notifies all <see cref="Subscribers"/> with the latest slot change details.
|
||||
/// </summary>
|
||||
/// <param name="slot">Last interacted slot</param>
|
||||
/// <param name="type">Last interacted slot interaction type</param>
|
||||
public void NotifySlotChanged(SlotChange slot, SlotTouchType type)
|
||||
{
|
||||
foreach (var sub in Subscribers)
|
||||
ResetView(sub, slot, type);
|
||||
Previous = slot;
|
||||
PreviousType = type;
|
||||
}
|
||||
|
||||
private void ResetView(ISlotViewer sub, SlotChange slot, SlotTouchType type)
|
||||
{
|
||||
if (Previous != null)
|
||||
sub.NotifySlotOld(Previous);
|
||||
|
||||
int index = sub.ViewIndex;
|
||||
if (index == slot.Box)
|
||||
sub.NotifySlotChanged(slot, type);
|
||||
}
|
||||
|
||||
public void ResetView(ISlotViewer sub) => ResetView(sub, Previous, PreviousType);
|
||||
}
|
||||
|
||||
public interface ISlotViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Current index the viewer is viewing.
|
||||
/// </summary>
|
||||
int ViewIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Notification that the <see cref="previous"/> slot is no longer the last interacted slot.
|
||||
/// </summary>
|
||||
/// <param name="previous">Last interacted slot</param>
|
||||
void NotifySlotOld(SlotChange previous);
|
||||
|
||||
/// <summary>
|
||||
/// Notification that the <see cref="slot"/> has just been interacted with.
|
||||
/// </summary>
|
||||
/// <param name="slot">Last interacted slot</param>
|
||||
/// <param name="type">Last interacted slot interaction type</param>
|
||||
void NotifySlotChanged(SlotChange slot, SlotTouchType type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Facilitates interaction with a <see cref="SaveFile"/> or other data location's slot data.
|
||||
/// </summary>
|
||||
public sealed class SlotEditor
|
||||
{
|
||||
private readonly SaveFile SAV;
|
||||
public SlotPublisher Publisher { get; } = new SlotPublisher();
|
||||
|
||||
private readonly Stack<SlotChange> UndoStack = new Stack<SlotChange>();
|
||||
private readonly Stack<SlotChange> RedoStack = new Stack<SlotChange>();
|
||||
|
||||
public SlotEditor(SaveFile sav) => SAV = sav;
|
||||
private void NotifySlotChanged(SlotChange slot, SlotTouchType type) => Publisher.NotifySlotChanged(slot, type);
|
||||
|
||||
/// <summary>
|
||||
/// Gets data from a slot.
|
||||
/// </summary>
|
||||
/// <param name="slot">Slot to retrieve from.</param>
|
||||
/// <returns>Operation succeeded or not via enum value.</returns>
|
||||
public PKM Get(SlotChange slot)
|
||||
{
|
||||
// Reading from a slot is always allowed.
|
||||
var pk = ReadSlot(slot);
|
||||
NotifySlotChanged(slot, SlotTouchType.Get);
|
||||
return pk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets data to a slot.
|
||||
/// </summary>
|
||||
/// <param name="slot">Slot to be set to.</param>
|
||||
/// <param name="pkm">Data to set.</param>
|
||||
/// <returns>Operation succeeded or not via enum value.</returns>
|
||||
public SlotTouchResult Set(SlotChange slot, PKM pkm)
|
||||
{
|
||||
if (CantWrite(slot))
|
||||
return SlotTouchResult.FailWrite;
|
||||
|
||||
WriteSlot(slot, pkm);
|
||||
NotifySlotChanged(slot, SlotTouchType.Set);
|
||||
|
||||
return SlotTouchResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a slot.
|
||||
/// </summary>
|
||||
/// <param name="slot">Slot to be deleted.</param>
|
||||
/// <returns>Operation succeeded or not via enum value.</returns>
|
||||
public SlotTouchResult Delete(SlotChange slot)
|
||||
{
|
||||
if (CantWrite(slot))
|
||||
return SlotTouchResult.FailDelete;
|
||||
|
||||
DeleteSlot(slot);
|
||||
NotifySlotChanged(slot, SlotTouchType.Delete);
|
||||
|
||||
return SlotTouchResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps two slots.
|
||||
/// </summary>
|
||||
/// <param name="source">Source slot to be switched with <see cref="dest"/>.</param>
|
||||
/// <param name="dest">Destination slot to be switched with <see cref="source"/>.</param>
|
||||
/// <returns>Operation succeeded or not via enum value.</returns>
|
||||
public SlotTouchResult Swap(SlotChange source, SlotChange dest)
|
||||
{
|
||||
if (CantWrite(source))
|
||||
return SlotTouchResult.FailSource;
|
||||
if (CantWrite(dest))
|
||||
return SlotTouchResult.FailDestination;
|
||||
|
||||
NotifySlotChanged(source, SlotTouchType.None);
|
||||
NotifySlotChanged(dest, SlotTouchType.Swap);
|
||||
|
||||
return SlotTouchResult.Success;
|
||||
}
|
||||
|
||||
public bool CantWrite(SlotChange c)
|
||||
{
|
||||
if (c.Type > StorageSlotType.Party)
|
||||
return true;
|
||||
return SAV.IsSlotLocked(c.Box, c.Slot);
|
||||
}
|
||||
|
||||
private PKM ReadSlot(StorageSlotOffset slot) => SAV.GetPKM(slot);
|
||||
|
||||
private void WriteSlot(SlotChange slot, PKM pkm)
|
||||
{
|
||||
if (slot.IsParty)
|
||||
{
|
||||
int count = SAV.PartyCount;
|
||||
if (slot.Slot > count)
|
||||
slot.Slot = count;
|
||||
SAV.SetPartySlot(pkm, slot.Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddUndo(slot);
|
||||
SAV.SetStoredSlot(pkm, slot.Offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteSlot(SlotChange slot)
|
||||
{
|
||||
var pkm = slot.PKM;
|
||||
if (slot.IsParty)
|
||||
{
|
||||
SAV.SetPartySlot(pkm, slot.Offset);
|
||||
slot.Slot = SAV.PartyCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddUndo(slot);
|
||||
SAV.SetStoredSlot(pkm, slot.Offset);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanUndo => UndoStack.Count != 0;
|
||||
public bool CanRedo => RedoStack.Count != 0;
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (UndoStack.Count == 0)
|
||||
return;
|
||||
|
||||
var change = UndoStack.Pop();
|
||||
if (change.Box < 0)
|
||||
return;
|
||||
AddRedo(change);
|
||||
NotifySlotChanged(change, SlotTouchType.Set);
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
if (RedoStack.Count == 0)
|
||||
return;
|
||||
|
||||
var change = RedoStack.Pop();
|
||||
if (change.Box < 0)
|
||||
return;
|
||||
AddUndo(change);
|
||||
NotifySlotChanged(change, SlotTouchType.Set);
|
||||
}
|
||||
|
||||
private void AddRedo(SlotChange change)
|
||||
{
|
||||
var slotChange = change.GetInverseData(SAV);
|
||||
RedoStack.Push(slotChange);
|
||||
}
|
||||
|
||||
private void AddUndo(SlotChange change)
|
||||
{
|
||||
var slotChange = change.GetInverseData(SAV);
|
||||
UndoStack.Push(slotChange);
|
||||
RedoStack.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
33
PKHeX.Core/Editing/Saves/Slots/SlotTouchResult.cs
Normal file
33
PKHeX.Core/Editing/Saves/Slots/SlotTouchResult.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Result indicators for modifying a Slot within a <see cref="SaveFile"/> or other data location.
|
||||
/// </summary>
|
||||
public enum SlotTouchResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Slot interaction was successful.
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// Slot interaction failed to apply the data.
|
||||
/// </summary>
|
||||
FailWrite,
|
||||
|
||||
/// <summary>
|
||||
/// Slot interaction failed to delete the data.
|
||||
/// </summary>
|
||||
FailDelete,
|
||||
|
||||
/// <summary>
|
||||
/// Slot interaction failed due to a bad/unmodifiable source.
|
||||
/// </summary>
|
||||
FailSource,
|
||||
|
||||
/// <summary>
|
||||
/// Slot interaction failed due to a bad/unmodifiable destination.
|
||||
/// </summary>
|
||||
FailDestination,
|
||||
}
|
||||
}
|
||||
11
PKHeX.Core/Editing/Saves/Slots/SlotTouchType.cs
Normal file
11
PKHeX.Core/Editing/Saves/Slots/SlotTouchType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public enum SlotTouchType
|
||||
{
|
||||
None,
|
||||
Get,
|
||||
Set,
|
||||
Delete,
|
||||
Swap,
|
||||
}
|
||||
}
|
||||
@@ -1230,7 +1230,7 @@ public override int PartyCount
|
||||
|
||||
public override bool IsSlotLocked(int box, int slot)
|
||||
{
|
||||
if (slot >= 30 || box >= BoxCount)
|
||||
if ((uint)slot >= 30 || (uint)box >= BoxCount)
|
||||
return false;
|
||||
|
||||
int slotIndex = slot + (BoxSlotCount * box);
|
||||
@@ -1239,7 +1239,7 @@ public override bool IsSlotLocked(int box, int slot)
|
||||
|
||||
public override bool IsSlotInBattleTeam(int box, int slot)
|
||||
{
|
||||
if (slot >= 30 || box >= BoxCount)
|
||||
if ((uint)slot >= 30 || (uint)box >= BoxCount)
|
||||
return false;
|
||||
|
||||
int slotIndex = slot + (BoxSlotCount * box);
|
||||
|
||||
Reference in New Issue
Block a user