add LocationEvents.ObjectsChanged event
This commit is contained in:
parent
05f81cb85f
commit
8051862c7b
|
@ -11,6 +11,7 @@
|
|||
|
||||
* For modders:
|
||||
* Added code analysis to mod build config package to flag common issues as warnings.
|
||||
* Added `LocationEvents.ObjectsChanged`, raised when an object is added/removed in any location.
|
||||
* Added `Context.IsMultiplayer` and `Context.IsMainPlayer` flags.
|
||||
* Added `Constants.TargetPlatform` which says whether the game is running on Linux, Mac, or Windows.
|
||||
* Added `semanticVersion.IsPrerelease()` method.
|
||||
|
|
|
@ -1,28 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Netcode;
|
||||
using Object = StardewValley.Object;
|
||||
using StardewValley;
|
||||
using SObject = StardewValley.Object;
|
||||
|
||||
namespace StardewModdingAPI.Events
|
||||
{
|
||||
/// <summary>Event arguments for a <see cref="LocationEvents.LocationObjectsChanged"/> event.</summary>
|
||||
/// <summary>Event arguments for a <see cref="LocationEvents.LocationObjectsChanged"/> or <see cref="LocationEvents.ObjectsChanged"/> event.</summary>
|
||||
public class EventArgsLocationObjectsChanged : EventArgs
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>The location which changed.</summary>
|
||||
public GameLocation Location { get; }
|
||||
|
||||
/// <summary>The objects added to the list.</summary>
|
||||
public IEnumerable<KeyValuePair<Vector2, SObject>> Added { get; }
|
||||
|
||||
/// <summary>The objects removed from the list.</summary>
|
||||
public IEnumerable<KeyValuePair<Vector2, SObject>> Removed { get; }
|
||||
|
||||
/// <summary>The current list of objects in the current location.</summary>
|
||||
public IDictionary<Vector2, NetRef<Object>> NewObjects { get; }
|
||||
[Obsolete("Use " + nameof(EventArgsLocationObjectsChanged.Added))]
|
||||
public IDictionary<Vector2, NetRef<SObject>> NewObjects { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="location">The location which changed.</param>
|
||||
/// <param name="added">The objects added to the list.</param>
|
||||
/// <param name="removed">The objects removed from the list.</param>
|
||||
/// <param name="newObjects">The current list of objects in the current location.</param>
|
||||
public EventArgsLocationObjectsChanged(IDictionary<Vector2, NetRef<Object>> newObjects)
|
||||
public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable<KeyValuePair<Vector2, SObject>> added, IEnumerable<KeyValuePair<Vector2, SObject>> removed, IDictionary<Vector2, NetRef<SObject>> newObjects)
|
||||
{
|
||||
this.Location = location;
|
||||
this.Added = added.ToArray();
|
||||
this.Removed = removed.ToArray();
|
||||
this.NewObjects = newObjects;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,20 @@ namespace StardewModdingAPI.Events
|
|||
}
|
||||
|
||||
/// <summary>Raised after the list of objects in the current location changes (e.g. an object is added or removed).</summary>
|
||||
[Obsolete("Use " + nameof(LocationEvents) + "." + nameof(LocationEvents.ObjectsChanged) + " instead")]
|
||||
public static event EventHandler<EventArgsLocationObjectsChanged> LocationObjectsChanged
|
||||
{
|
||||
add => LocationEvents.EventManager.Location_LocationObjectsChanged.Add(value);
|
||||
remove => LocationEvents.EventManager.Location_LocationObjectsChanged.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>Raised after the list of objects in a location changes (e.g. an object is added or removed).</summary>
|
||||
public static event EventHandler<EventArgsLocationObjectsChanged> ObjectsChanged
|
||||
{
|
||||
add => LocationEvents.EventManager.Location_ObjectsChanged.Add(value);
|
||||
remove => LocationEvents.EventManager.Location_ObjectsChanged.Remove(value);
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using StardewModdingAPI.Events;
|
||||
|
@ -114,8 +115,12 @@ namespace StardewModdingAPI.Framework.Events
|
|||
public readonly ManagedEvent<EventArgsGameLocationsChanged> Location_LocationsChanged;
|
||||
|
||||
/// <summary>Raised after the list of objects in the current location changes (e.g. an object is added or removed).</summary>
|
||||
[Obsolete]
|
||||
public readonly ManagedEvent<EventArgsLocationObjectsChanged> Location_LocationObjectsChanged;
|
||||
|
||||
/// <summary>Raised after the list of objects in a location changes (e.g. an object is added or removed).</summary>
|
||||
public readonly ManagedEvent<EventArgsLocationObjectsChanged> Location_ObjectsChanged;
|
||||
|
||||
/****
|
||||
** MenuEvents
|
||||
****/
|
||||
|
@ -239,6 +244,7 @@ namespace StardewModdingAPI.Framework.Events
|
|||
this.Location_CurrentLocationChanged = ManageEventOf<EventArgsCurrentLocationChanged>(nameof(LocationEvents), nameof(LocationEvents.CurrentLocationChanged));
|
||||
this.Location_LocationsChanged = ManageEventOf<EventArgsGameLocationsChanged>(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged));
|
||||
this.Location_LocationObjectsChanged = ManageEventOf<EventArgsLocationObjectsChanged>(nameof(LocationEvents), nameof(LocationEvents.LocationObjectsChanged));
|
||||
this.Location_ObjectsChanged = ManageEventOf<EventArgsLocationObjectsChanged>(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged));
|
||||
|
||||
this.Menu_Changed = ManageEventOf<EventArgsClickableMenuChanged>(nameof(MenuEvents), nameof(MenuEvents.MenuChanged));
|
||||
this.Menu_Closed = ManageEventOf<EventArgsClickableMenuClosed>(nameof(MenuEvents), nameof(MenuEvents.MenuClosed));
|
||||
|
|
|
@ -93,7 +93,10 @@ namespace StardewModdingAPI.Framework
|
|||
private readonly IValueWatcher<ulong> SaveIdWatcher;
|
||||
|
||||
/// <summary>Tracks changes to the location list.</summary>
|
||||
private readonly ICollectionWatcher<GameLocation> LocationsWatcher;
|
||||
private readonly ICollectionWatcher<GameLocation> LocationListWatcher;
|
||||
|
||||
/// <summary>Tracks changes to each location.</summary>
|
||||
private readonly IDictionary<GameLocation, LocationTracker> LocationWatchers = new Dictionary<GameLocation, LocationTracker>();
|
||||
|
||||
/// <summary>Tracks changes to <see cref="Game1.activeClickableMenu"/>.</summary>
|
||||
private readonly IValueWatcher<IClickableMenu> ActiveMenuWatcher;
|
||||
|
@ -162,14 +165,14 @@ namespace StardewModdingAPI.Framework
|
|||
this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height));
|
||||
this.TimeWatcher = WatcherFactory.ForEquatable(() => Game1.timeOfDay);
|
||||
this.ActiveMenuWatcher = WatcherFactory.ForReference(() => Game1.activeClickableMenu);
|
||||
this.LocationsWatcher = WatcherFactory.ForObservableCollection((ObservableCollection<GameLocation>)Game1.locations);
|
||||
this.LocationListWatcher = WatcherFactory.ForObservableCollection((ObservableCollection<GameLocation>)Game1.locations);
|
||||
this.Watchers.AddRange(new IWatcher[]
|
||||
{
|
||||
this.SaveIdWatcher,
|
||||
this.WindowSizeWatcher,
|
||||
this.TimeWatcher,
|
||||
this.ActiveMenuWatcher,
|
||||
this.LocationsWatcher
|
||||
this.LocationListWatcher
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -349,6 +352,22 @@ namespace StardewModdingAPI.Framework
|
|||
watcher.Update();
|
||||
this.CurrentPlayerTracker?.Update();
|
||||
|
||||
// update location watchers
|
||||
if (this.LocationListWatcher.IsChanged)
|
||||
{
|
||||
foreach (GameLocation location in this.LocationListWatcher.Removed.Union(this.LocationListWatcher.Added))
|
||||
{
|
||||
if (this.LocationWatchers.TryGetValue(location, out LocationTracker watcher))
|
||||
{
|
||||
this.Watchers.Remove(watcher);
|
||||
this.LocationWatchers.Remove(location);
|
||||
watcher.Dispose();
|
||||
}
|
||||
}
|
||||
foreach (GameLocation location in this.LocationListWatcher.Added)
|
||||
this.LocationWatchers[location] = new LocationTracker(location);
|
||||
}
|
||||
|
||||
/*********
|
||||
** Locale changed events
|
||||
*********/
|
||||
|
@ -509,12 +528,12 @@ namespace StardewModdingAPI.Framework
|
|||
}
|
||||
|
||||
// raise location list changed
|
||||
if (this.LocationsWatcher.IsChanged)
|
||||
if (this.LocationListWatcher.IsChanged)
|
||||
{
|
||||
if (this.VerboseLogging)
|
||||
{
|
||||
string added = this.LocationsWatcher.Added.Any() ? string.Join(", ", this.LocationsWatcher.Added.Select(p => p.Name)) : "none";
|
||||
string removed = this.LocationsWatcher.Removed.Any() ? string.Join(", ", this.LocationsWatcher.Removed.Select(p => p.Name)) : "none";
|
||||
string added = this.LocationListWatcher.Added.Any() ? string.Join(", ", this.LocationListWatcher.Added.Select(p => p.Name)) : "none";
|
||||
string removed = this.LocationListWatcher.Removed.Any() ? string.Join(", ", this.LocationListWatcher.Removed.Select(p => p.Name)) : "none";
|
||||
this.Monitor.Log($"Context: location list changed (added {added}; removed {removed}).", LogLevel.Trace);
|
||||
}
|
||||
|
||||
|
@ -524,6 +543,20 @@ namespace StardewModdingAPI.Framework
|
|||
// raise events that shouldn't be triggered on initial load
|
||||
if (!this.SaveIdWatcher.IsChanged)
|
||||
{
|
||||
// raise location objects changed
|
||||
foreach (LocationTracker watcher in this.LocationWatchers.Values)
|
||||
{
|
||||
if (watcher.LocationObjectsWatcher.IsChanged)
|
||||
{
|
||||
GameLocation location = watcher.Location;
|
||||
var added = watcher.LocationObjectsWatcher.Added;
|
||||
var removed = watcher.LocationObjectsWatcher.Removed;
|
||||
watcher.Reset();
|
||||
|
||||
this.Events.Location_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed, watcher.Location.netObjects.FieldDict));
|
||||
}
|
||||
}
|
||||
|
||||
// raise player leveled up a skill
|
||||
foreach (KeyValuePair<EventArgsLevelUp.LevelType, IValueWatcher<int>> pair in curPlayer.GetChangedSkills())
|
||||
{
|
||||
|
@ -542,12 +575,16 @@ namespace StardewModdingAPI.Framework
|
|||
}
|
||||
|
||||
// raise current location's object list changed
|
||||
if (curPlayer.TryGetLocationChanges(out IDictionaryWatcher<Vector2, SObject> _))
|
||||
{
|
||||
if (this.VerboseLogging)
|
||||
this.Monitor.Log("Context: current location objects changed.", LogLevel.Trace);
|
||||
if (curPlayer.TryGetLocationChanges(out IDictionaryWatcher<Vector2, SObject> watcher))
|
||||
{
|
||||
if (this.VerboseLogging)
|
||||
this.Monitor.Log("Context: current location objects changed.", LogLevel.Trace);
|
||||
|
||||
this.Events.Location_LocationObjectsChanged.Raise(new EventArgsLocationObjectsChanged(curPlayer.GetCurrentLocation().netObjects.FieldDict));
|
||||
GameLocation location = curPlayer.GetCurrentLocation();
|
||||
|
||||
this.Events.Location_LocationObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, watcher.Added, watcher.Removed, location.netObjects.FieldDict));
|
||||
}
|
||||
}
|
||||
|
||||
// raise time changed
|
||||
|
@ -570,9 +607,14 @@ namespace StardewModdingAPI.Framework
|
|||
|
||||
// update state
|
||||
this.CurrentPlayerTracker?.Reset();
|
||||
this.LocationsWatcher.Reset();
|
||||
this.LocationListWatcher.Reset();
|
||||
this.SaveIdWatcher.Reset();
|
||||
this.TimeWatcher.Reset();
|
||||
if (!Context.IsWorldReady)
|
||||
{
|
||||
foreach (LocationTracker watcher in this.LocationWatchers.Values)
|
||||
watcher.Reset();
|
||||
}
|
||||
|
||||
/*********
|
||||
** Game update
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
|
||||
using StardewValley;
|
||||
using Object = StardewValley.Object;
|
||||
|
||||
namespace StardewModdingAPI.Framework.StateTracking
|
||||
{
|
||||
/// <summary>Tracks changes to a location's data.</summary>
|
||||
internal class LocationTracker : IWatcher
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>The underlying watchers.</summary>
|
||||
private readonly List<IWatcher> Watchers = new List<IWatcher>();
|
||||
|
||||
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>Whether the value changed since the last reset.</summary>
|
||||
public bool IsChanged => this.Watchers.Any(p => p.IsChanged);
|
||||
|
||||
/// <summary>The tracked location.</summary>
|
||||
public GameLocation Location { get; }
|
||||
|
||||
/// <summary>Tracks changes to the current location's objects.</summary>
|
||||
public IDictionaryWatcher<Vector2, Object> LocationObjectsWatcher { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="location">The location to track.</param>
|
||||
public LocationTracker(GameLocation location)
|
||||
{
|
||||
this.Location = location;
|
||||
|
||||
// init watchers
|
||||
this.LocationObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects);
|
||||
this.Watchers.AddRange(new[]
|
||||
{
|
||||
this.LocationObjectsWatcher
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Stop watching the player fields and release all references.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (IWatcher watcher in this.Watchers)
|
||||
watcher.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>Update the current value if needed.</summary>
|
||||
public void Update()
|
||||
{
|
||||
foreach (IWatcher watcher in this.Watchers)
|
||||
watcher.Update();
|
||||
}
|
||||
|
||||
/// <summary>Set the current value as the baseline.</summary>
|
||||
public void Reset()
|
||||
{
|
||||
foreach (IWatcher watcher in this.Watchers)
|
||||
watcher.Reset();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -148,6 +148,7 @@
|
|||
<Compile Include="Framework\StateTracking\IDictionaryWatcher.cs" />
|
||||
<Compile Include="Framework\StateTracking\IValueWatcher.cs" />
|
||||
<Compile Include="Framework\StateTracking\IWatcher.cs" />
|
||||
<Compile Include="Framework\StateTracking\LocationTracker.cs" />
|
||||
<Compile Include="Framework\StateTracking\PlayerTracker.cs" />
|
||||
<Compile Include="Framework\Utilities\ContextHash.cs" />
|
||||
<Compile Include="Framework\Utilities\PathUtilities.cs" />
|
||||
|
|
Loading…
Reference in New Issue