first commit

This commit is contained in:
Beyhan Oğur
2026-09-03 04:45:36 +03:00
commit d5f52cc3d3
1038 changed files with 169579 additions and 0 deletions
@@ -0,0 +1,298 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reactive.Linq;
using System.Reflection;
using System.Timers;
using System.Windows.Input;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Network.PacketFilter;
using ClassicAssist.UO.Network.Packets;
using ClassicAssist.UO.Objects;
using ReactiveUI;
namespace ClassicAssist.UI.ViewModels
{
public class AboutControlViewModel : BaseViewModel
{
private ICommand _checkForUpdatesCommand;
private bool _connected;
private DateTime _connectedTime;
private int _itemCount;
private int _lastTargetSerial;
private double _latency;
private ICommand _launchHomepageCommand;
private int _mobileCount;
private ICommand _openPayPalCommand;
private Timer _pingTimer;
private string _playerName;
private int _playerSerial;
private string _playerStatus;
private string _shardFeatures;
private string _shardName = "Unknown";
private ICommand _showItemsCommand;
private Timer _timer;
public AboutControlViewModel()
{
Assembly assembly = Assembly.GetExecutingAssembly();
Version version = assembly.GetName().Version;
Version = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
BuildDate = $"{GetBuildDateTime( assembly ).ToLongDateString()}";
Engine.ConnectedEvent += OnConnectedEvent;
Engine.DisconnectedEvent += OnDisconnectedEvent;
Engine.PlayerInitializedEvent += PlayerInitializedEvent;
Engine.Items.CollectionChanged += ItemsOnCollectionChanged;
Engine.Mobiles.CollectionChanged += MobilesOnCollectionChanged;
IncomingPacketHandlers.MobileUpdatedEvent += OnMobileUpdatedEvent;
}
public string BuildDate { get; set; }
public ICommand CheckForUpdatesCommand =>
_checkForUpdatesCommand ?? ( _checkForUpdatesCommand = new RelayCommand( CheckForUpdates, o => true ) );
public bool Connected
{
get => _connected;
set => SetProperty( ref _connected, value );
}
public DateTime ConnectedTime
{
get => _connectedTime;
set => SetProperty( ref _connectedTime, value );
}
public int ItemCount
{
get => _itemCount;
set => SetProperty( ref _itemCount, value );
}
public int LastTargetSerial
{
get => _lastTargetSerial;
set => SetProperty( ref _lastTargetSerial, value );
}
public double Latency
{
get => _latency;
set => SetProperty( ref _latency, value );
}
public ICommand LaunchHomepageCommand =>
_launchHomepageCommand ?? ( _launchHomepageCommand = new RelayCommand( LaunchHomepage, o => true ) );
public int MobileCount
{
get => _mobileCount;
set => SetProperty( ref _mobileCount, value );
}
public ICommand OpenPayPalCommand =>
_openPayPalCommand ?? ( _openPayPalCommand = new RelayCommand( OpenPayPal, o => true ) );
public string PlayerName
{
get => _playerName;
set => SetProperty( ref _playerName, value );
}
public int PlayerSerial
{
get => _playerSerial;
set => SetProperty( ref _playerSerial, value );
}
public string PlayerStatus
{
get => _playerStatus;
set => SetProperty( ref _playerStatus, value );
}
public string Product { get; } = Strings.ProductName;
public string ShardFeatures
{
get => _shardFeatures;
set => SetProperty( ref _shardFeatures, value );
}
public string ShardName
{
get => _shardName;
set => SetProperty( ref _shardName, value );
}
public ICommand ShowItemsCommand =>
_showItemsCommand ?? ( _showItemsCommand = ReactiveCommand.Create( ShowItems,
this.WhenAnyValue( e => e.Connected ).ObserveOn( RxApp.MainThreadScheduler ) ) );
public string Version { get; set; }
private static void OpenPayPal( object obj )
{
Process.Start( "https://www.paypal.me/reeeetus" );
}
private void LastTargetChangedEvent( int serial )
{
LastTargetSerial = serial;
}
private void OnMobileUpdatedEvent( Mobile mobile )
{
if ( mobile.Serial == Engine.Player?.Serial )
{
PlayerInitializedEvent( Engine.Player );
}
}
private static void LaunchHomepage( object obj )
{
Process.Start( "https://github.com/Reetus/ClassicAssist" );
}
private void MobilesOnCollectionChanged( int totalcount, bool added, Mobile[] mobiles )
{
MobileCount = totalcount;
}
private void ItemsOnCollectionChanged( int totalcount, bool added, Item[] items )
{
ItemCount = Engine.Items.GetTotalItemCount();
}
private static void ShowItems()
{
Item[] e = ItemCollection.GetAllItems( Engine.Items.GetItems() );
Engine.UIInvoker?.Invoke( "EntityCollectionViewer", new[] { (object) new ItemCollection( 0 ) { e } } );
}
private void PlayerInitializedEvent( PlayerMobile player )
{
PlayerSerial = player.Serial;
PlayerName = player.Name;
PlayerStatus = player.Status.ToString();
ShardFeatures = Engine.Features.ToString();
player.LastTargetChangedEvent += LastTargetChangedEvent;
player.MobileStatusUpdated += OnMobileStatusUpdated;
ShardName = Engine.CurrentShard?.Name ?? "Unknown";
}
private void OnMobileStatusUpdated( MobileStatus oldstatus, MobileStatus newstatus )
{
PlayerStatus = newstatus.ToString();
}
private void OnDisconnectedEvent()
{
Connected = false;
_timer?.Stop();
}
private static void CheckForUpdates( object obj )
{
string updaterPath = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory,
"ClassicAssist.Updater.exe" );
Version version = null;
if ( System.Version.TryParse(
FileVersionInfo.GetVersionInfo( Assembly.GetExecutingAssembly().Location ).ProductVersion,
out Version v ) )
{
version = v;
}
if ( !File.Exists( updaterPath ) )
{
return;
}
ProcessStartInfo psi = new ProcessStartInfo( updaterPath,
$"--pid {Process.GetCurrentProcess().Id} --path {Engine.StartupPath}" + ( version != null
? $" --version {version}"
: "" ) ) { UseShellExecute = false };
Process.Start( psi );
}
private void OnConnectedEvent()
{
Connected = true;
ConnectedTime = DateTime.Now;
_timer = new Timer( 1000 ) { AutoReset = true };
_timer.Elapsed += ( sender, args ) => { NotifyPropertyChanged( nameof( ConnectedTime ) ); };
_timer.Start();
_pingTimer = new Timer( 3000 ) { AutoReset = true };
_pingTimer.Elapsed += ( sender, args ) => PingServer();
_pingTimer.Start();
}
private void PingServer()
{
_pingTimer.Interval = 30000;
Random random = new Random();
byte value = (byte) random.Next( 1, byte.MaxValue );
Stopwatch sw = new Stopwatch();
sw.Start();
PacketWaitEntry we = Engine.PacketWaitEntries.Add(
new PacketFilterInfo( 0x73, new[] { new PacketFilterCondition( 1, new[] { value }, 1 ) } ),
PacketDirection.Incoming, true );
Engine.SendPacketToServer( new Ping( value ) );
bool result = we.Lock.WaitOne( 5000 );
sw.Stop();
if ( result )
{
Latency = sw.ElapsedMilliseconds;
}
}
internal static DateTime GetBuildDateTime( Assembly assembly )
{
try
{
var location = assembly?.Location;
if ( string.IsNullOrEmpty( location ) )
{
return DateTime.MinValue;
}
var productVersion = FileVersionInfo.GetVersionInfo( location ).ProductVersion;
if ( System.Version.TryParse( productVersion, out Version version ) && version != null )
{
DateTime buildDateTime =
new DateTime( 2020, 7, 3 ).Add( new TimeSpan( TimeSpan.TicksPerDay * version.Build ) );
return buildDateTime;
}
}
catch
{
// ignored
}
return DateTime.MinValue;
}
}
}
@@ -0,0 +1,597 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Autoloot;
using ClassicAssist.Data.Regions;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UI.ViewModels.Autoloot;
using ClassicAssist.UI.Misc;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Network.PacketFilter;
using ClassicAssist.UO.Network.Packets;
using ClassicAssist.UO.Objects;
using Microsoft.Scripting.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ReactiveUI;
using UOC = ClassicAssist.Shared.UO.Commands;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class AutolootViewModel : BaseViewModel, ISettingProvider
{
private const int LOOT_TIMEOUT = 5000;
private readonly object _autolootLock = new object();
private readonly IObservable<bool> _entrySelected;
private readonly IObservable<bool> _itemSelected;
private readonly string _propertiesFile = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory,
"Data", "Properties.json" );
private readonly string _propertiesFileCustom =
Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Data", "Properties.Custom.json" );
private ICommand _clipboardCopyCommand;
private ICommand _clipboardPasteCommand;
private ObservableCollection<PropertyEntry> _constraints = new ObservableCollection<PropertyEntry>();
private int _containerSerial;
private ICommand _defineCustomPropertiesCommand;
private bool _disableInGuardzone;
private bool _enabled;
private ICommand _insertCommand;
private ICommand _insertConstraintCommand;
private ICommand _insertMatchAnyCommand;
private ObservableCollectionEx<AutolootEntry> _items = new ObservableCollectionEx<AutolootEntry>();
private ICommand _removeCommand;
private ICommand _removeConstraintCommand;
private ICommand _removeSingleConstraintCommand;
private RelayCommand _resetContainerCommand;
private AutolootEntry _selectedItem;
private ObservableCollection<AutolootConstraintEntry> _selectedProperties =
new ObservableCollection<AutolootConstraintEntry>();
private AutolootConstraintEntry _selectedProperty;
private ICommand _selectHueCommand;
private ICommand _setContainerCommand;
public AutolootViewModel()
{
if ( !File.Exists( _propertiesFile ) )
{
return;
}
LoadProperties();
LoadCustomProperties();
AutolootHelpers.SetAutolootContainer = serial => ContainerSerial = serial;
IncomingPacketHandlers.CorpseContainerDisplayEvent += OnCorpseEvent;
AutolootManager.GetInstance().GetEntries = () => _items.ToList();
_entrySelected = this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null );
_itemSelected = this.WhenAnyValue( e => e.SelectedProperty, selector: e => e != null );
}
public ICommand ClipboardCopyCommand =>
_clipboardCopyCommand ?? ( _clipboardCopyCommand = new RelayCommand( ClipboardCopy, o => true ) );
public ICommand ClipboardPasteCommand =>
_clipboardPasteCommand ?? ( _clipboardPasteCommand = new RelayCommand( ClipboardPaste, o => true ) );
public ObservableCollection<PropertyEntry> Constraints
{
get => _constraints;
set => SetProperty( ref _constraints, value );
}
public int ContainerSerial
{
get => _containerSerial;
set => SetProperty( ref _containerSerial, value );
}
public ICommand DefineCustomPropertiesCommand =>
_defineCustomPropertiesCommand ??
( _defineCustomPropertiesCommand = new RelayCommand( DefineCustomProperties, o => true ) );
public bool DisableInGuardzone
{
get => _disableInGuardzone;
set => SetProperty( ref _disableInGuardzone, value );
}
public bool Enabled
{
get => _enabled;
set => SetProperty( ref _enabled, value );
}
public ICommand InsertCommand =>
_insertCommand ?? ( _insertCommand = ReactiveCommand.CreateFromTask( Insert ) );
public ICommand InsertConstraintCommand =>
_insertConstraintCommand ?? ( _insertConstraintCommand =
ReactiveCommand.Create<PropertyEntry>( InsertConstraint, _entrySelected ) );
public ICommand InsertMatchAnyCommand =>
_insertMatchAnyCommand ?? ( _insertMatchAnyCommand = new RelayCommand( InsertMatchAny, o => true ) );
public ObservableCollectionEx<AutolootEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand RemoveCommand =>
_removeCommand ??
( _removeCommand = ReactiveCommand.CreateFromTask<AutolootEntry>( Remove, _entrySelected ) );
public ICommand RemoveConstraintCommand =>
_removeConstraintCommand ?? ( _removeConstraintCommand =
ReactiveCommand.Create<IEnumerable<AutolootConstraintEntry>>( RemoveConstraint, _itemSelected ) );
public ICommand RemoveSingleConstraintCommand =>
_removeSingleConstraintCommand ?? ( _removeSingleConstraintCommand =
ReactiveCommand.Create<AutolootConstraintEntry>( RemoveSingleConstraint, _itemSelected ) );
public ICommand ResetContainerCommand => _resetContainerCommand = new RelayCommand( ResetContainer, o => true );
public AutolootEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public ObservableCollection<AutolootConstraintEntry> SelectedProperties
{
get => _selectedProperties;
set => SetProperty( ref _selectedProperties, value );
}
public AutolootConstraintEntry SelectedProperty
{
get => _selectedProperty;
set => SetProperty( ref _selectedProperty, value );
}
public ICommand SelectHueCommand =>
_selectHueCommand ?? ( _selectHueCommand =
ReactiveCommand.CreateFromTask<AutolootEntry>( SelectHue, _entrySelected ) );
public ICommand SetContainerCommand =>
_setContainerCommand ?? ( _setContainerCommand = new RelayCommandAsync( SetContainer, o => true ) );
public void Serialize( JObject json )
{
if ( json == null )
{
return;
}
JObject autolootObj = new JObject
{
{ "Enabled", Enabled },
{ "DisableInGuardzone", DisableInGuardzone },
{ "Container", ContainerSerial }
};
JArray itemsArray = new JArray();
foreach ( AutolootEntry entry in Items )
{
JObject entryObj = new JObject
{
{ "Name", entry.Name },
{ "ID", entry.ID },
{ "Autoloot", entry.Autoloot },
{ "Rehue", entry.Rehue },
{ "RehueHue", entry.RehueHue },
{ "Enabled", entry.Enabled }
};
if ( entry.Constraints != null )
{
JArray constraintsArray = new JArray();
foreach ( AutolootConstraintEntry constraint in entry.Constraints )
{
JObject constraintObj = new JObject
{
{ "Name", constraint.Property.Name },
{ "Operator", constraint.Operator.ToString() },
{ "Value", constraint.Value }
};
constraintsArray.Add( constraintObj );
}
entryObj.Add( "Properties", constraintsArray );
}
itemsArray.Add( entryObj );
}
autolootObj.Add( "Items", itemsArray );
json.Add( "Autoloot", autolootObj );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["Autoloot"] == null )
{
return;
}
JToken config = json["Autoloot"];
Enabled = config["Enabled"]?.ToObject<bool>() ?? true;
DisableInGuardzone = config["DisableInGuardzone"]?.ToObject<bool>() ?? false;
ContainerSerial = config["Container"]?.ToObject<int>() ?? 0;
if ( config["Items"] != null )
{
JToken items = config["Items"];
foreach ( JToken token in items )
{
AutolootEntry entry = new AutolootEntry
{
Name = token["Name"]?.ToObject<string>() ?? "Unknown",
ID = token["ID"]?.ToObject<int>() ?? 0,
Autoloot = token["Autoloot"]?.ToObject<bool>() ?? false,
Rehue = token["Rehue"]?.ToObject<bool>() ?? false,
RehueHue = token["RehueHue"]?.ToObject<int>() ?? 0,
Enabled = token["Enabled"]?.ToObject<bool>() ?? true
};
if ( token["Properties"] != null )
{
List<AutolootConstraintEntry> constraintsList = new List<AutolootConstraintEntry>();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach ( JToken constraintToken in token["Properties"] )
{
string constraintName = constraintToken["Name"]?.ToObject<string>() ?? "Unknown";
PropertyEntry propertyEntry = Constraints.FirstOrDefault( c => c.Name == constraintName );
if ( propertyEntry == null )
{
continue;
}
AutolootConstraintEntry constraintObj = new AutolootConstraintEntry
{
Property = propertyEntry,
Operator = constraintToken["Operator"]?.ToObject<AutolootOperator>() ??
AutolootOperator.Equal,
Value = constraintToken["Value"]?.ToObject<int>() ?? 0
};
constraintsList.Add( constraintObj );
}
entry.Constraints.AddRange( constraintsList );
}
Items.Add( entry );
}
}
}
private void RemoveSingleConstraint( AutolootConstraintEntry obj )
{
SelectedItem?.Constraints.Remove( obj );
}
private void LoadCustomProperties()
{
if ( !File.Exists( _propertiesFileCustom ) )
{
return;
}
JsonSerializer serializer = new JsonSerializer();
using ( StreamReader sr = new StreamReader( _propertiesFileCustom ) )
{
using ( JsonTextReader reader = new JsonTextReader( sr ) )
{
PropertyEntry[] constraints = serializer.Deserialize<PropertyEntry[]>( reader );
foreach ( PropertyEntry constraint in constraints )
{
Constraints.AddSorted( constraint );
}
}
}
}
private void LoadProperties()
{
JsonSerializer serializer = new JsonSerializer();
using ( StreamReader sr = new StreamReader( _propertiesFile ) )
{
using ( JsonTextReader reader = new JsonTextReader( sr ) )
{
PropertyEntry[] constraints = serializer.Deserialize<PropertyEntry[]>( reader );
foreach ( PropertyEntry constraint in constraints )
{
Constraints.AddSorted( constraint );
}
}
}
}
private void ClipboardPaste( object obj )
{
string text = Engine.UIInvoker.GetClipboardText();
try
{
IEnumerable<AutolootConstraintEntry> entries =
JsonConvert.DeserializeObject<IEnumerable<AutolootConstraintEntry>>( text );
if ( entries == null )
{
return;
}
foreach ( AutolootConstraintEntry entry in entries )
{
if ( !SelectedItem.Constraints.Contains( entry ) )
{
SelectedItem?.Constraints.Add( entry );
}
}
}
catch ( Exception )
{
// ignored
}
}
private static void ClipboardCopy( object obj )
{
if ( !( obj is IList<AutolootConstraintEntry> entries ) )
{
return;
}
string text = JsonConvert.SerializeObject( entries );
Engine.UIInvoker.SetClipboardText( text );
}
public void OnCorpseEvent( int serial )
{
if ( !Enabled )
{
return;
}
lock ( _autolootLock )
{
Item item = Engine.Items.GetItem( serial );
if ( item == null || item.ID != 0x2006 )
{
return;
}
PacketWaitEntry we = Engine.PacketWaitEntries.Add(
new PacketFilterInfo( 0x3C, new[] { PacketFilterConditions.IntAtPositionCondition( serial, 19 ) } ),
PacketDirection.Incoming );
we.Lock.WaitOne( 2000 );
IEnumerable<Item> items = Engine.Items.GetItem( serial )?.Container?.GetItems();
if ( items == null )
{
return;
}
if ( Engine.Features.HasFlag( FeatureFlags.AOS ) )
{
Engine.SendPacketToServer( new BatchQueryProperties( items.Select( i => i.Serial ).ToArray() ) );
Thread.Sleep( 1000 );
}
List<Item> lootItems = new List<Item>();
// If change logic, also change in DebugAutolootViewModel
foreach ( AutolootEntry entry in Items )
{
if ( !entry.Enabled )
{
continue;
}
IEnumerable<Item> matchItems = AutolootHelpers.AutolootFilter( items, entry );
if ( matchItems == null )
{
continue;
}
foreach ( Item matchItem in matchItems )
{
if ( entry.Rehue )
{
Engine.SendPacketToClient( new ContainerContentUpdate( matchItem.Serial, matchItem.ID,
matchItem.Direction, matchItem.Count, matchItem.X, matchItem.Y, matchItem.Grid,
matchItem.Owner, entry.RehueHue ) );
}
if ( DisableInGuardzone &&
Engine.Player.GetRegion().Attributes.HasFlag( RegionAttributes.Guarded ) )
{
continue;
}
if ( entry.Autoloot )
{
lootItems.Add( matchItem );
}
}
}
foreach ( Item lootItem in lootItems.Distinct() )
{
int containerSerial = ContainerSerial;
if ( containerSerial == 0 || Engine.Items.GetItem( containerSerial ) == null )
{
containerSerial = Engine.Player.GetLayer( Layer.Backpack );
}
UOC.SystemMessage( string.Format( Strings.Autolooting___0__, lootItem.Name ), 61 );
Task t = ActionPacketQueue.EnqueueDragDrop( lootItem.Serial, lootItem.Count, containerSerial,
QueuePriority.Medium, true, true );
t.Wait( LOOT_TIMEOUT );
}
}
}
private void RemoveConstraint( object obj )
{
if ( !( obj is IEnumerable<AutolootConstraintEntry> constraints ) )
{
return;
}
foreach ( AutolootConstraintEntry constraintEntry in constraints.ToList() )
{
SelectedItem?.Constraints.Remove( constraintEntry );
}
}
private void InsertConstraint( object obj )
{
if ( !( obj is PropertyEntry propertyEntry ) )
{
return;
}
List<AutolootConstraintEntry> constraints =
new List<AutolootConstraintEntry>( SelectedItem.Constraints )
{
new AutolootConstraintEntry { Property = propertyEntry }
};
SelectedItem.Constraints = new ObservableCollection<AutolootConstraintEntry>( constraints );
}
private void DefineCustomProperties( object obj )
{
Engine.UIInvoker.InvokeDialog<CustomPropertiesViewModel>( "CustomPropertiesWindow" );
Constraints.Clear();
LoadProperties();
LoadCustomProperties();
}
private void ResetContainer( object obj )
{
ContainerSerial = 0;
}
private async Task SetContainer( object arg )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Target_container___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
ContainerSerial = serial;
}
private void InsertMatchAny( object obj )
{
AutolootEntry entry = new AutolootEntry
{
Name = Strings.Any, ID = -1, Constraints = new ObservableCollection<AutolootConstraintEntry>()
};
Items.Add( entry );
}
private async Task Insert( CancellationToken cancellationToken )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
UOC.SystemMessage( Strings.Cannot_find_item___ );
return;
}
AutolootEntry entry = new AutolootEntry
{
Name = TileData.GetStaticTile( item.ID ).Name,
ID = item.ID,
Constraints = new ObservableCollection<AutolootConstraintEntry>()
};
Items.Add( entry );
}
private async Task Remove( object arg )
{
if ( !( arg is AutolootEntry entry ) )
{
return;
}
Items.Remove( entry );
await Task.CompletedTask;
}
private static async Task SelectHue( object obj )
{
if ( !( obj is AutolootEntry entry ) )
{
return;
}
int hue = await Engine.UIInvoker.GetHueAsync();
entry.RehueHue = hue;
}
}
}
@@ -0,0 +1,174 @@
using System.Collections.ObjectModel;
using System.Reactive;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Counters;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class CountersTabViewModel : BaseViewModel, ISettingProvider
{
private ICommand _insertEntryCommand;
private ObservableCollection<CountersAgentEntry> _items = new ObservableCollection<CountersAgentEntry>();
private ICommand _recountCommand;
private ICommand _removeEntryCommand;
private CountersAgentEntry _selectedItem;
private bool _warn = true;
private int _warnAmount;
public CountersTabViewModel()
{
CountersManager manager = CountersManager.GetInstance();
manager.Items = Items;
manager.RecountAll = Recount;
}
public ICommand InsertEntryCommand =>
_insertEntryCommand ?? ( _insertEntryCommand = new RelayCommandAsync( InsertEntry, o => true ) );
public ObservableCollection<CountersAgentEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand RecountCommand => _recountCommand ?? ( _recountCommand = ReactiveCommand.Create( Recount ) );
public ICommand RemoveEntryCommand =>
_removeEntryCommand ?? ( _removeEntryCommand = ReactiveCommand.Create<CountersAgentEntry>( RemoveEntry,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public CountersAgentEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public bool Warn
{
get => _warn;
set => SetProperty( ref _warn, value );
}
public int WarnAmount
{
get => _warnAmount;
set => SetProperty( ref _warnAmount, value );
}
public void Serialize( JObject json )
{
JObject options = new JObject { { "Warn", Warn }, { "WarnAmount", WarnAmount } };
JArray items = new JArray();
foreach ( CountersAgentEntry entry in Items )
{
JObject entryObj = new JObject
{
{ "Name", entry.Name }, { "Graphic", entry.Graphic }, { "Color", entry.Color }
};
items.Add( entryObj );
}
options.Add( "Items", items );
json?.Add( "Counters", options );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["Counters"] == null )
{
return;
}
Warn = json["Counters"]["Warn"]?.ToObject<bool>() ?? false;
WarnAmount = json["Counters"]["WarnAmount"]?.ToObject<int>() ?? 0;
foreach ( JToken token in json["Counters"]["Items"] )
{
if ( token != null )
{
Items.Add( new CountersAgentEntry
{
Name = token["Name"].ToObject<string>() ?? "Unknown",
Graphic = token["Graphic"].ToObject<int>(),
Color = token["Color"].ToObject<int>()
} );
}
}
}
private void RemoveEntry( object obj )
{
if ( !( obj is CountersAgentEntry entry ) )
{
return;
}
Items.Remove( entry );
}
private void Recount()
{
foreach ( CountersAgentEntry item in Items )
{
int count = item.Count;
item.Recount();
if ( Warn && item.Count <= WarnAmount && count > WarnAmount )
{
Commands.SystemMessage(
string.Format( Strings.Counter___0___amount_is_now__1____, item.Name, item.Count ), 61 );
}
}
}
private async Task InsertEntry( object arg )
{
int serial = await Commands.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
Commands.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
Commands.SystemMessage( Strings.Cannot_find_item___ );
return;
}
string name = TileData.GetStaticTile( item.ID ).Name;
if ( string.IsNullOrEmpty( name ) )
{
name = item.Name;
}
CountersAgentEntry entry = new CountersAgentEntry { Name = name, Graphic = item.ID, Color = item.Hue };
entry.Recount();
Items.Add( entry );
}
}
}
@@ -0,0 +1,394 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Dress;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class DressTabViewModel : HotkeyEntryViewModel<DressAgentEntry>, ISettingProvider
{
private readonly IObservable<bool> _entrySelected;
private readonly DressManager _manager;
private readonly Layer[] _validLayers =
{
Layer.Arms, Layer.Bracelet, Layer.Cloak, Layer.Earrings, Layer.Gloves, Layer.Helm, Layer.InnerLegs,
Layer.InnerTorso, Layer.MiddleTorso, Layer.Neck, Layer.OneHanded, Layer.OuterLegs, Layer.OuterTorso,
Layer.Pants, Layer.Ring, Layer.Shirt, Layer.Shoes, Layer.Talisman, Layer.TwoHanded, Layer.Waist
};
private ICommand _addDressItemCommand;
private ICommand _changeDressType;
private ICommand _clearDressItemsCommand;
private ICommand _dressAllItemsCommand;
private ICommand _importItemsCommand;
private bool _isDressingOrUndressing;
private readonly IObservable<bool> _itemSelected;
private bool _moveConflictingItems;
private ICommand _newDressEntryCommand;
private ICommand _removeDressEntryCommand;
private ICommand _removeDressItemCommand;
private DressAgentItem _selectedDressItem;
private DressAgentEntry _selectedItem;
private ICommand _setUndressContainerCommand;
private ICommand _undressAllItemsCommand;
private ICommand _undressItemsCommand;
private bool _useUo3DPackets;
public DressTabViewModel() : base( Strings.Dress )
{
_manager = DressManager.GetInstance();
_manager.Items = Items;
_entrySelected = this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null );
_itemSelected = this.WhenAnyValue( e => e.SelectedDressItem, selector: e => e != null );
}
public ICommand AddDressItemCommand =>
_addDressItemCommand ?? ( _addDressItemCommand = new RelayCommandAsync( AddDressItem, o => true ) );
//TODO UI
public ICommand ChangeDressTypeCommand =>
_changeDressType ??
( _changeDressType = new RelayCommand( ChangeDressType, o => SelectedDressItem != null ) );
public ICommand ClearDressItemsCommand =>
_clearDressItemsCommand ?? ( _clearDressItemsCommand =
ReactiveCommand.Create<DressAgentEntry>( ClearDressItems, _entrySelected ) );
public ICommand DressAllItemsCommand =>
_dressAllItemsCommand ?? ( _dressAllItemsCommand =
ReactiveCommand.CreateFromTask<DressAgentEntry>( DressAllItems,
_entrySelected.Merge( this.WhenAnyValue( e => e.IsDressingOrUndressing, e => !e ) ) ) );
public ICommand ImportItemsCommand =>
_importItemsCommand ?? ( _importItemsCommand =
ReactiveCommand.Create<DressAgentEntry>( ImportItems, _entrySelected ) );
public bool IsDressingOrUndressing
{
get => _isDressingOrUndressing;
set => SetProperty( ref _isDressingOrUndressing, value );
}
public bool MoveConflictingItems
{
get => _moveConflictingItems;
set => SetProperty( ref _moveConflictingItems, value );
}
public ICommand NewDressEntryCommand =>
_newDressEntryCommand ?? ( _newDressEntryCommand = new RelayCommand( NewDressEntry, o => true ) );
public ICommand RemoveDressEntryCommand =>
_removeDressEntryCommand ?? ( _removeDressEntryCommand =
ReactiveCommand.Create<DressAgentEntry>( RemoveDressEntry, _entrySelected ) );
public ICommand RemoveDressItemCommand =>
_removeDressItemCommand ?? ( _removeDressItemCommand =
ReactiveCommand.Create<DressAgentItem>( RemoveDressItem, _itemSelected ) );
public DressAgentItem SelectedDressItem
{
get => _selectedDressItem;
set => SetProperty( ref _selectedDressItem, value );
}
public DressAgentEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public ICommand SetUndressContainerCommand =>
_setUndressContainerCommand ?? ( _setUndressContainerCommand =
ReactiveCommand.CreateFromTask<DressAgentEntry>( SetUndressContainer, _entrySelected ) );
public ICommand UndressAllItemsCommand =>
_undressAllItemsCommand ?? ( _undressAllItemsCommand = ReactiveCommand.CreateFromTask( UndressAllItems,
this.WhenAnyValue( e => e.IsDressingOrUndressing, e => !e ) ) );
public ICommand UndressItemsCommand =>
_undressItemsCommand ?? ( _undressItemsCommand =
ReactiveCommand.CreateFromTask<DressAgentEntry>( UndressItems,
this.WhenAnyValue( e => e.IsDressingOrUndressing, e => !e ) ) );
public bool UseUO3DPackets
{
get => _useUo3DPackets;
set
{
SetProperty( ref _useUo3DPackets, value );
if ( _manager != null )
{
_manager.UseUO3DPackets = value;
}
}
}
public void Serialize( JObject json )
{
JObject dress = new JObject
{
{
"Options",
new JObject { ["MoveConflictingItems"] = MoveConflictingItems, ["UseUO3DPackets"] = UseUO3DPackets }
}
};
JArray dressEntries = new JArray();
foreach ( DressAgentEntry dae in Items )
{
JObject djson = new JObject();
SetJsonValue( djson, "Name", dae.Name );
SetJsonValue( djson, "UndressContainer", dae.UndressContainer );
SetJsonValue( djson, "PassToUO", dae.PassToUO );
SetJsonValue( djson, "Keys", dae.Hotkey.ToJObject() );
JArray items = new JArray();
if ( dae.Items != null )
{
foreach ( DressAgentItem dressAgentItem in dae.Items )
{
JObject item = new JObject
{
{ "Layer", (int) dressAgentItem.Layer },
{ "Serial", dressAgentItem.Serial },
{ "ID", dressAgentItem.ID },
{ "Type", (int) dressAgentItem.Type }
};
items.Add( item );
}
}
djson.Add( "Items", items );
dressEntries.Add( djson );
}
dress.Add( "Entries", dressEntries );
json?.Add( "Dress", dress );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["Dress"] == null )
{
return;
}
JToken dress = json["Dress"];
MoveConflictingItems = GetJsonValue( dress["Options"], "MoveConflictingItems", false );
UseUO3DPackets = _manager.UseUO3DPackets = GetJsonValue( dress["Options"], "UseUO3DPackets", false );
foreach ( JToken entry in dress["Entries"] )
{
DressAgentEntry dae = new DressAgentEntry
{
Name = GetJsonValue( entry, "Name", string.Empty ),
UndressContainer = GetJsonValue( entry, "UndressContainer", 0 ),
PassToUO = GetJsonValue( entry, "PassToUO", true ),
Hotkey = new ShortcutKeys( entry["Keys"] )
};
dae.Action = async hks => await DressAllItems( dae );
List<DressAgentItem> items = new List<DressAgentItem>();
if ( entry["Items"] != null )
{
items.AddRange( entry["Items"].Select( itemEntry => new DressAgentItem
{
Layer = GetJsonValue( itemEntry, "Layer", Layer.Invalid ),
Serial = GetJsonValue( itemEntry, "Serial", 0 ),
ID = GetJsonValue( itemEntry, "ID", -1 ),
Type = GetJsonValue( itemEntry, "Type", DressAgentItemType.Serial )
} ) );
}
dae.Items = new List<DressAgentItem>( items );
Items.Add( dae );
}
}
private async Task UndressItems( object arg )
{
if ( !( arg is DressAgentEntry dae ) )
{
return;
}
try
{
IsDressingOrUndressing = true;
await dae.Undress();
}
finally
{
IsDressingOrUndressing = false;
}
}
private static async Task SetUndressContainer( object obj )
{
if ( !( obj is DressAgentEntry entry ) )
{
return;
}
int serial = await Commands.GetTargeSerialAsync( Strings.Select_undress_container___ );
if ( serial <= 0 )
{
Commands.SystemMessage( Strings.Invalid_container___ );
return;
}
entry.UndressContainer = serial;
}
private static void ClearDressItems( object obj )
{
if ( !( obj is DressAgentEntry dae ) )
{
return;
}
dae.Items = new List<DressAgentItem>();
}
private void RemoveDressItem( object obj )
{
if ( !( obj is DressAgentItem removeItem ) )
{
return;
}
if ( !SelectedItem.Items.Contains( removeItem ) )
{
return;
}
List<DressAgentItem> list = SelectedItem.Items.ToList();
list.Remove( removeItem );
SelectedItem.Items = list;
}
private static async Task AddDressItem( object arg )
{
if ( !( arg is DressAgentEntry dae ) )
{
return;
}
int serial = await Commands.GetTargeSerialAsync( Strings.Target_clothing_item___ );
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
Commands.SystemMessage( Strings.Cannot_find_item___ );
return;
}
if ( item.Layer == Layer.Invalid )
{
Commands.SystemMessage( Strings.The_item_needs_to_be_equipped___ );
return;
}
dae.AddOrReplaceDressItem( item );
}
private async Task UndressAllItems( CancellationToken cancellationToken )
{
IsDressingOrUndressing = true;
await _manager.UndressAll( cancellationToken );
IsDressingOrUndressing = false;
}
private void NewDressEntry( object obj )
{
int count = Items.Count;
DressAgentEntry dae =
new DressAgentEntry { Name = $"Dress-{count + 1}", Items = new List<DressAgentItem>() };
dae.Action = async hks => await DressAllItems( dae );
Items.Add( dae );
}
private void RemoveDressEntry( object obj )
{
if ( !( obj is DressAgentEntry dae ) )
{
return;
}
dae.Hotkey = ShortcutKeys.Default;
Items.Remove( dae );
}
private async Task DressAllItems( object obj )
{
if ( !( obj is DressAgentEntry dae ) )
{
return;
}
IsDressingOrUndressing = true;
await _manager.DressAllItems( dae, MoveConflictingItems );
IsDressingOrUndressing = false;
}
private void ImportItems( object obj )
{
if ( !( obj is DressAgentEntry dae ) )
{
return;
}
_manager.ImportItems( dae );
}
public bool IsValidLayer( Layer layer )
{
return _validLayers.Any( l => l == layer );
}
private static void ChangeDressType( object obj )
{
if ( !( obj is DressAgentItem dai ) )
{
return;
}
dai.Type = dai.Type == DressAgentItemType.Serial ? DressAgentItemType.ID : DressAgentItemType.Serial;
}
}
}
@@ -0,0 +1,133 @@
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Friends;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Misc;
using ClassicAssist.UI.ViewModels;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class FriendsTabViewModel : BaseViewModel, ISettingProvider
{
private ICommand _addFriendCommand;
private ICommand _changeRehueOption;
private Options _options;
private ICommand _removeFriendCommand;
private FriendEntry _selectedItem;
private ICommand _selectHueCommand;
public ICommand AddFriendCommand =>
_addFriendCommand ?? ( _addFriendCommand = new RelayCommandAsync( AddFriend, o => true ) );
public ICommand ChangeRehueOption =>
_changeRehueOption ?? ( _changeRehueOption = new RelayCommand( ChangeRehue, o => true ) );
public Options Options
{
get => _options;
set => SetProperty( ref _options, value );
}
public ICommand RemoveFriendCommand =>
_removeFriendCommand ?? ( _removeFriendCommand = ReactiveCommand.CreateFromTask<FriendEntry>( RemoveFriend,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
//new RelayCommandAsync( RemoveFriend, o => SelectedItem != null ) );
public FriendEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public ICommand SelectHueCommand =>
_selectHueCommand ?? ( _selectHueCommand = ReactiveCommand.CreateFromTask( SelectHue,
this.WhenAnyValue( e => e.Options.RehueFriends, selector: e => e ) ) );
public void Serialize( JObject json )
{
JObject config = new JObject
{
["IncludePartyMembersInFriends"] = Options.IncludePartyMembersInFriends,
["PreventAttackingFriendsInWarMode"] = Options.PreventAttackingFriendsInWarMode,
["PreventTargetingFriendsWithHarmful"] = Options.PreventTargetingFriendsWithHarmful
};
JArray friends = new JArray();
foreach ( FriendEntry friend in Options.Friends )
{
friends.Add( new JObject { { "Name", friend.Name }, { "Serial", friend.Serial } } );
}
config.Add( "Items", friends );
json?.Add( "Friends", config );
}
public void Deserialize( JObject json, Options options )
{
Options = options;
Options.Friends.Clear();
if ( json?["Friends"] == null )
{
return;
}
JToken config = json["Friends"];
Options.IncludePartyMembersInFriends = config["IncludePartyMembersInFriends"]?.ToObject<bool>() ?? true;
Options.PreventAttackingFriendsInWarMode =
config["PreventAttackingFriendsInWarMode"]?.ToObject<bool>() ?? true;
Options.PreventTargetingFriendsWithHarmful =
config["PreventTargetingFriendsWithHarmful"]?.ToObject<bool>() ?? false;
if ( config["Items"] == null )
{
return;
}
foreach ( JToken token in config["Items"] )
{
Options.Friends.Add( new FriendEntry
{
Name = token["Name"].ToObject<string>(), Serial = token["Serial"].ToObject<int>()
} );
}
}
private static void ChangeRehue( object obj )
{
MainCommands.Resync();
}
private static async Task SelectHue( CancellationToken token )
{
int hue = await Engine.UIInvoker.GetHueAsync();
Options.CurrentOptions.RehueFriendsHue = hue;
MainCommands.Resync();
}
private static async Task AddFriend( object arg )
{
await Task.Run( () => MobileCommands.AddFriend() );
}
private static Task RemoveFriend( object arg )
{
if ( !( arg is FriendEntry fe ) )
{
return Task.CompletedTask;
}
MobileCommands.RemoveFriend( fe.Serial );
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,246 @@
using System.Reactive;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Data.Organizer;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class OrganizerTabViewModel : HotkeyEntryViewModel<OrganizerEntry>, ISettingProvider
{
private readonly OrganizerManager _manager;
private ReactiveCommand<OrganizerEntry, Unit> _insertItemCommand;
private bool _isOrganizing;
private ICommand _newOrganizerEntryCommand;
private ReactiveCommand<OrganizerEntry, Unit> _organizeCommand;
private ReactiveCommand<OrganizerItem, Unit> _removeItemCommand;
private ReactiveCommand<OrganizerEntry, Unit> _removeOrganizerAgentEntryCommand;
private OrganizerEntry _selectedItem;
private OrganizerItem _selectedOrganizerItem;
private ReactiveCommand<OrganizerEntry, Unit> _setContainersCommand;
public OrganizerTabViewModel() : base( Strings.Organizer )
{
_manager = OrganizerManager.GetInstance();
_manager.Items = Items;
}
public ReactiveCommand<OrganizerEntry, Unit> InsertItemCommand =>
_insertItemCommand ?? ( _insertItemCommand = ReactiveCommand.CreateFromTask<OrganizerEntry>( InsertItem,
this.WhenAnyValue( e => e.SelectedItem, e => e.IsOrganizing, ( e, f ) => e != null && !f ) ) );
public bool IsOrganizing
{
get => _isOrganizing;
set
{
SetProperty( ref _isOrganizing, value );
NotifyPropertyChanged( nameof( PlayStopButtonText ) );
}
}
public ICommand NewOrganizerEntryCommand =>
_newOrganizerEntryCommand ??
( _newOrganizerEntryCommand = new RelayCommand( NewOrganizerEntry, o => !IsOrganizing ) );
public ReactiveCommand<OrganizerEntry, Unit> OrganizeCommand =>
_organizeCommand ?? ( _organizeCommand = ReactiveCommand.CreateFromTask<OrganizerEntry>( Organize,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public string PlayStopButtonText => IsOrganizing ? Strings.Stop : Strings.Play;
public ReactiveCommand<OrganizerItem, Unit> RemoveItemCommand =>
_removeItemCommand ?? ( _removeItemCommand = ReactiveCommand.Create<OrganizerItem>( RemoveItem,
this.WhenAnyValue( e => e.IsOrganizing, e => e.SelectedOrganizerItem, ( e, f ) => !e && f != null ) ) );
public ReactiveCommand<OrganizerEntry, Unit> RemoveOrganizerAgentEntryCommand =>
_removeOrganizerAgentEntryCommand ?? ( _removeOrganizerAgentEntryCommand =
ReactiveCommand.Create<OrganizerEntry>( RemoveOrganizerAgentEntry,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public OrganizerEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public OrganizerItem SelectedOrganizerItem
{
get => _selectedOrganizerItem;
set => SetProperty( ref _selectedOrganizerItem, value );
}
public ReactiveCommand<OrganizerEntry, Unit> SetContainersCommand =>
_setContainersCommand ?? ( _setContainersCommand =
ReactiveCommand.CreateFromTask<OrganizerEntry>( _manager.SetContainers,
this.WhenAnyValue( e => e.SelectedItem, f => f.IsOrganizing, ( e, f ) => e != null && !f ) ) );
//new RelayCommandAsync( _manager.SetContainers, o => SelectedItem != null && !IsOrganizing ) );
public void Serialize( JObject json )
{
JArray organizer = new JArray();
foreach ( OrganizerEntry organizerEntry in Items )
{
JObject entryObj = new JObject();
SetJsonValue( entryObj, "Name", organizerEntry.Name );
SetJsonValue( entryObj, "Stack", organizerEntry.Stack );
SetJsonValue( entryObj, "SourceContainer", organizerEntry.SourceContainer );
SetJsonValue( entryObj, "DestinationContainer", organizerEntry.DestinationContainer );
SetJsonValue( entryObj, "Keys", organizerEntry.Hotkey.ToJObject() );
SetJsonValue( entryObj, "Complete", organizerEntry.Complete );
JArray itemsArray = new JArray();
foreach ( OrganizerItem organizerItem in organizerEntry.Items )
{
JObject itemsObj = new JObject();
SetJsonValue( itemsObj, "Item", organizerItem.Item );
SetJsonValue( itemsObj, "ID", organizerItem.ID );
SetJsonValue( itemsObj, "Hue", organizerItem.Hue );
SetJsonValue( itemsObj, "Amount", organizerItem.Amount );
itemsArray.Add( itemsObj );
}
entryObj.Add( "Items", itemsArray );
organizer.Add( entryObj );
}
json?.Add( "Organizer", organizer );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["Organizer"] == null )
{
return;
}
foreach ( JToken token in json["Organizer"] )
{
OrganizerEntry entry = new OrganizerEntry
{
Name = GetJsonValue( token, "Name", "Organizer" ),
Stack = GetJsonValue( token, "Stack", true ),
SourceContainer = GetJsonValue( token, "SourceContainer", 0 ),
DestinationContainer = GetJsonValue( token, "DestinationContainer", 0 ),
Hotkey = new ShortcutKeys( token["Keys"] ),
Complete = GetJsonValue( token, "Complete", false )
};
entry.Action = hks => Task.Run( async () => await _manager.Organize( entry ) );
entry.IsRunning = () => IsOrganizing;
foreach ( JToken itemToken in token["Items"] )
{
OrganizerItem item = new OrganizerItem
{
Item = GetJsonValue( itemToken, "Item", string.Empty ),
ID = GetJsonValue( itemToken, "ID", 0 ),
Hue = GetJsonValue( itemToken, "Hue", -1 ),
Amount = GetJsonValue( itemToken, "Amount", -1 )
};
entry.Items.Add( item );
}
Items.Add( entry );
}
}
private async Task Organize( object arg )
{
if ( !( arg is OrganizerEntry entry ) )
{
return;
}
IsOrganizing = true;
await _manager.Organize( entry );
IsOrganizing = false;
}
private void NewOrganizerEntry( object obj )
{
int count = Items.Count + 1;
OrganizerEntry entry = new OrganizerEntry
{
Name = $"Organizer-{count}",
Action = hks => Task.Run( async () => await _manager.Organize( SelectedItem ) ),
IsRunning = () => IsOrganizing
};
Items.Add( entry );
}
private void RemoveOrganizerAgentEntry( object obj )
{
if ( !( obj is OrganizerEntry entry ) )
{
return;
}
Items.Remove( entry );
}
private void RemoveItem( object obj )
{
if ( !( obj is OrganizerItem item ) )
{
return;
}
SelectedItem.Items.Remove( item );
}
private static async Task InsertItem( object arg )
{
if ( !( arg is OrganizerEntry entry ) )
{
return;
}
int serial = await Commands.GetTargeSerialAsync( Strings.Target_new_item___ );
if ( serial <= 0 )
{
Commands.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
Commands.SystemMessage( Strings.Cannot_find_item___ );
return;
}
OrganizerItem organizerItem = new OrganizerItem
{
Item = TileData.GetStaticTile( item.ID ).Name, ID = item.ID, Hue = item.Hue, Amount = -1
};
entry.Items.Add( organizerItem );
}
}
}
@@ -0,0 +1,279 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Scavenger;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
using UOC = ClassicAssist.Shared.UO.Commands;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class ScavengerTabViewModel : BaseViewModel, ISettingProvider
{
private const int SCAVENGER_DISTANCE = 2;
private readonly List<int> _ignoreList;
private readonly object _scavengeLock = new object();
private ICommand _clearAllCommand;
private int _containerSerial;
private bool _enabled;
private ICommand _insertCommand;
private ObservableCollection<ScavengerEntry> _items = new ObservableCollection<ScavengerEntry>();
private ICommand _removeCommand;
private ScavengerEntry _selectedItem;
private ICommand _setContainerCommand;
public ScavengerTabViewModel()
{
ScavengerManager manager = ScavengerManager.GetInstance();
manager.Items = Items;
manager.CheckArea = () => Task.Run( CheckArea );
_ignoreList = new List<int>();
}
public ICommand ClearAllCommand =>
_clearAllCommand ?? ( _clearAllCommand = ReactiveCommand.CreateFromTask( ClearAll ) );
public int ContainerSerial
{
get => _containerSerial;
set => SetProperty( ref _containerSerial, value );
}
public bool Enabled
{
get => _enabled;
set => SetProperty( ref _enabled, value );
}
public ICommand InsertCommand =>
_insertCommand ?? ( _insertCommand = new RelayCommandAsync( Insert, o => true ) );
public ObservableCollection<ScavengerEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand RemoveCommand =>
_removeCommand ?? ( _removeCommand = ReactiveCommand.CreateFromTask<ScavengerEntry>( Remove,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public ScavengerEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public ICommand SetContainerCommand =>
_setContainerCommand ?? ( _setContainerCommand = new RelayCommandAsync( SetContainer, o => true ) );
public void Serialize( JObject json )
{
Engine.Items.CollectionChanged -= ItemsOnCollectionChanged;
if ( json == null )
{
return;
}
JObject scavengerObj = new JObject { { "Enabled", Enabled }, { "Container", ContainerSerial } };
JArray itemsArray = new JArray();
foreach ( ScavengerEntry entry in Items )
{
itemsArray.Add( new JObject
{
{ "Graphic", entry.Graphic },
{ "Name", entry.Name },
{ "Hue", entry.Hue },
{ "Enabled", entry.Enabled }
} );
}
scavengerObj.Add( "Items", itemsArray );
json.Add( "Scavenger", scavengerObj );
}
public void Deserialize( JObject json, Options options )
{
Engine.Items.CollectionChanged += ItemsOnCollectionChanged;
Items.Clear();
if ( json?["Scavenger"] == null )
{
return;
}
JToken config = json["Scavenger"];
Enabled = config["Enabled"]?.ToObject<bool>() ?? true;
ContainerSerial = config["Container"]?.ToObject<int>() ?? 0;
if ( config["Items"] == null )
{
return;
}
foreach ( JToken token in config["Items"] )
{
ScavengerEntry entry = new ScavengerEntry
{
Graphic = token["Graphic"]?.ToObject<int>() ?? 0,
Name = token["Name"]?.ToObject<string>() ?? "Unknown",
Hue = token["Hue"]?.ToObject<int>() ?? 0,
Enabled = token["Enabled"]?.ToObject<bool>() ?? true
};
bool alreadyExists = Items.Any( s => s.Graphic == entry.Graphic && s.Hue == entry.Hue );
if ( !alreadyExists )
{
Items.Add( entry );
}
}
}
private void ItemsOnCollectionChanged( int totalcount, bool added, Item[] items )
{
if ( !added || !Enabled )
{
return;
}
bool hasNearby = items.Any( i => i.Distance <= SCAVENGER_DISTANCE );
if ( hasNearby )
{
CheckArea();
}
}
public void CheckArea()
{
if ( !Enabled || Engine.Player == null )
{
return;
}
List<Item> scavengerItems = new List<Item>();
if ( Engine.Player.WeightMax - Engine.Player.Weight <= 25 )
{
return;
}
lock ( _scavengeLock )
{
foreach ( ScavengerEntry entry in Items )
{
if ( !entry.Enabled )
{
continue;
}
Item[] matches = Engine.Items.SelectEntities( i =>
i.Distance <= SCAVENGER_DISTANCE && i.Owner == 0 && i.ID == entry.Graphic &&
( entry.Hue == -1 || i.Hue == entry.Hue ) && !_ignoreList.Contains( i.Serial ) );
if ( matches == null )
{
continue;
}
scavengerItems.AddRange( matches );
}
if ( scavengerItems.Count == 0 )
{
return;
}
Item container = Engine.Items.GetItem( _containerSerial ) ?? Engine.Player.Backpack;
if ( container == null )
{
return;
}
foreach ( Item scavengerItem in scavengerItems.Where( scavengerItem =>
scavengerItem.Distance <= SCAVENGER_DISTANCE ).Distinct() )
{
_ignoreList.Add( scavengerItem.Serial );
UOC.SystemMessage( string.Format( Strings.Scavenging___0__, scavengerItem.Name ?? "Unknown" ), 61 );
ActionPacketQueue.EnqueueDragDrop( scavengerItem.Serial, scavengerItem.Count, container.Serial,
QueuePriority.Low, true ).Wait();
}
}
}
private async Task Insert( object arg )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
UOC.SystemMessage( Strings.Cannot_find_item___ );
return;
}
string tiledataName = TileData.GetStaticTile( item.ID ).Name ?? "Unknown";
ScavengerEntry entry =
new ScavengerEntry { Enabled = true, Graphic = item.ID, Hue = item.Hue, Name = tiledataName };
Items.Add( entry );
}
private async Task Remove( object arg )
{
if ( !( arg is ScavengerEntry entry ) )
{
return;
}
Items.Remove( entry );
await Task.CompletedTask;
}
private async Task ClearAll( CancellationToken cancellationToken )
{
Items.Clear();
await Task.CompletedTask;
}
private async Task SetContainer( object arg )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Select_destination_container___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_container___ );
return;
}
ContainerSerial = serial;
}
}
}
@@ -0,0 +1,238 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Macros;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Data.Vendors;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
using UOC = ClassicAssist.Shared.UO.Commands;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class VendorBuyTabViewModel : BaseViewModel, ISettingProvider
{
private bool _enabled;
private bool _includeBackpackAmount;
private bool _includePurchasedAmount;
private ICommand _insertCommand;
private ObservableCollection<VendorBuyAgentEntry> _items = new ObservableCollection<VendorBuyAgentEntry>();
private ICommand _removeCommand;
private VendorBuyAgentEntry _selectedItem;
public VendorBuyTabViewModel()
{
IncomingPacketHandlers.VendorBuyDisplayEvent += OnVendorBuyDisplayEvent;
}
public bool Enabled
{
get => _enabled;
set => SetProperty( ref _enabled, value );
}
public bool IncludeBackpackAmount
{
get => _includeBackpackAmount;
set => SetProperty( ref _includeBackpackAmount, value );
}
public bool IncludePurchasedAmount
{
get => _includePurchasedAmount;
set => SetProperty( ref _includePurchasedAmount, value );
}
public ICommand InsertCommand =>
_insertCommand ?? ( _insertCommand = ReactiveCommand.CreateFromTask( Insert ) );
public ObservableCollection<VendorBuyAgentEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand RemoveCommand =>
_removeCommand ?? ( _removeCommand = ReactiveCommand.Create<VendorBuyAgentEntry>( Remove,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public VendorBuyAgentEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public void Serialize( JObject json )
{
if ( json == null )
{
return;
}
JObject config = new JObject
{
{ "Enabled", Enabled },
{ "IncludeBackpackAmount", IncludeBackpackAmount },
{ "IncludePurchasedAmount", IncludePurchasedAmount }
};
JArray itemObj = new JArray();
foreach ( VendorBuyAgentEntry entry in Items )
{
JObject entryObj = new JObject
{
{ "Enabled", entry.Enabled },
{ "Name", entry.Name },
{ "Graphic", entry.Graphic },
{ "Hue", entry.Hue },
{ "Amount", entry.Amount },
{ "MaxPrice", entry.MaxPrice }
};
itemObj.Add( entryObj );
}
config.Add( "Items", itemObj );
json.Add( "VendorBuy", config );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["VendorBuy"] == null )
{
return;
}
JToken config = json["VendorBuy"];
Enabled = config["Enabled"]?.ToObject<bool>() ?? false;
IncludeBackpackAmount = config["IncludeBackpackAmount"]?.ToObject<bool>() ?? false;
IncludePurchasedAmount = config["IncludePurchasedAmount"]?.ToObject<bool>() ?? false;
foreach ( JToken token in config["Items"] )
{
VendorBuyAgentEntry vbae = new VendorBuyAgentEntry
{
Enabled = token["Enabled"]?.ToObject<bool>() ?? false,
Name = token["Name"]?.ToObject<string>() ?? "Unknown",
Graphic = token["Graphic"]?.ToObject<int>() ?? 0,
Hue = token["Hue"]?.ToObject<int>() ?? 0,
Amount = token["Amount"]?.ToObject<int>() ?? 0,
MaxPrice = token["MaxPrice"]?.ToObject<int>() ?? 0
};
Items.Add( vbae );
}
}
private void OnVendorBuyDisplayEvent( int serial, ShopListEntry[] entries )
{
if ( !Enabled )
{
return;
}
IEnumerable<VendorBuyAgentEntry> items = Items.Where( i => i.Enabled );
List<ShopListEntry> buyList = new List<ShopListEntry>();
foreach ( VendorBuyAgentEntry entry in items )
{
IEnumerable<ShopListEntry> matches = entries.Where( i =>
i.Item.ID == entry.Graphic && ( entry.Hue == -1 || i.Item.Hue == entry.Hue ) &&
( entry.MaxPrice == -1 || i.Price <= entry.MaxPrice ) );
foreach ( ShopListEntry match in matches )
{
if ( entry.Amount != -1 )
{
if ( match.Amount > entry.Amount )
{
match.Amount = entry.Amount;
}
if ( IncludeBackpackAmount )
{
int currentAmount = ObjectCommands.CountType( entry.Graphic, "backpack", entry.Hue );
if ( currentAmount + match.Amount > entry.Amount )
{
match.Amount = entry.Amount - currentAmount;
}
}
}
if ( match.Amount > 0 )
{
buyList.Add( match );
}
}
}
if ( buyList.Count > 0 )
{
UOC.VendorBuy( serial, buyList.ToArray() );
}
if ( !MacroManager.QuietMode && buyList.Count == 0 )
{
UOC.SystemMessage( Strings.Buy_Agent__No_matches_found_ );
}
}
private async Task Insert( CancellationToken cancellationToken )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
UOC.SystemMessage( Strings.Cannot_find_item___ );
return;
}
string name = TileData.GetStaticTile( item.ID ).Name ?? item.Name;
Items.Add( new VendorBuyAgentEntry
{
Enabled = true,
Name = name,
Graphic = item.ID,
Amount = -1,
Hue = item.Hue,
MaxPrice = -1
} );
}
private void Remove( object obj )
{
if ( !( obj is VendorBuyAgentEntry entry ) )
{
return;
}
Items.Remove( entry );
}
}
}
@@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Vendors;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json.Linq;
using ReactiveUI;
using UOC = ClassicAssist.Shared.UO.Commands;
namespace ClassicAssist.Shared.UI.ViewModels.Agents
{
public class VendorSellTabViewModel : BaseViewModel, ISettingProvider
{
private ICommand _insertCommand;
private ObservableCollection<VendorSellAgentEntry> _items = new ObservableCollection<VendorSellAgentEntry>();
private ICommand _removeCommand;
private VendorSellAgentEntry _selectedItem;
public VendorSellTabViewModel()
{
IncomingPacketHandlers.VendorSellDisplayEvent += OnVendorSellDisplayEvent;
}
public ICommand InsertCommand =>
_insertCommand ?? ( _insertCommand = ReactiveCommand.CreateFromTask( Insert ) );
public ObservableCollection<VendorSellAgentEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand RemoveCommand =>
_removeCommand ?? ( _removeCommand = ReactiveCommand.Create<VendorSellAgentEntry>( Remove,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public VendorSellAgentEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public void Serialize( JObject json )
{
if ( json == null )
{
return;
}
JArray itemsObj = new JArray();
foreach ( VendorSellAgentEntry item in Items )
{
JObject itemObj = new JObject
{
{ "Enabled", item.Enabled },
{ "Graphic", item.Graphic },
{ "Hue", item.Hue },
{ "Amount", item.Amount },
{ "MinPrice", item.MinPrice },
{ "Name", item.Name }
};
itemsObj.Add( itemObj );
}
JObject config = new JObject { { "Items", itemsObj } };
json.Add( "VendorSell", config );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["VendorSell"] == null )
{
return;
}
JToken config = json["VendorSell"];
foreach ( JToken items in config?["Items"] )
{
VendorSellAgentEntry vsae = new VendorSellAgentEntry
{
Enabled = items["Enabled"]?.ToObject<bool>() ?? true,
Graphic = items["Graphic"]?.ToObject<int>() ?? 0,
Hue = items["Hue"]?.ToObject<int>() ?? 0,
Amount = items["Amount"]?.ToObject<int>() ?? -1,
MinPrice = items["MinPrice"]?.ToObject<int>() ?? 0,
Name = items["Name"]?.ToObject<string>() ?? string.Empty
};
Items.Add( vsae );
}
}
private void Remove( object arg )
{
if ( !( arg is VendorSellAgentEntry entry ) )
{
return;
}
Items.Remove( entry );
}
private void OnVendorSellDisplayEvent( int serial, SellListEntry[] entries )
{
List<SellListEntry> sellList = new List<SellListEntry>();
foreach ( SellListEntry entry in entries )
{
VendorSellAgentEntry match = Items.FirstOrDefault( i =>
i.Graphic == entry.ID && ( i.Hue == -1 || i.Hue == entry.Hue ) && entry.Price >= i.MinPrice &&
i.Enabled );
if ( match != null && match.Amount != -1 )
{
entry.Amount = Math.Min( match.Amount, entry.Amount );
}
if ( match != null )
{
sellList.Add( entry );
}
}
if ( sellList.Count > 0 )
{
Sell( serial, sellList.ToArray() );
}
}
public static void Sell( int vendorSerial, SellListEntry[] entries )
{
if ( entries == null || entries.Length == 0 )
{
return;
}
int len = 9 + entries.Length * 6;
PacketWriter pw = new PacketWriter( len );
pw.Write( (byte) 0x9F );
pw.Write( (short) len );
pw.Write( vendorSerial );
pw.Write( (short) entries.Length );
foreach ( SellListEntry entry in entries )
{
pw.Write( entry.Serial );
pw.Write( (short) entry.Amount );
}
Engine.SendPacketToServer( pw );
}
private async Task Insert( CancellationToken cancellationToken )
{
int serial = await UOC.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
UOC.SystemMessage( Strings.Invalid_or_unknown_object_id );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
UOC.SystemMessage( Strings.Cannot_find_item___ );
return;
}
string name = TileData.GetStaticTile( item.ID ).Name ?? item.Name;
Items.Add( new VendorSellAgentEntry
{
Enabled = true,
Name = name,
Graphic = item.ID,
Hue = item.Hue,
Amount = -1,
MinPrice = 0
} );
}
}
}
@@ -0,0 +1,110 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using ClassicAssist.Misc;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
namespace ClassicAssist.Shared.UI.ViewModels.Autoloot
{
public class ClilocSelectionViewModel : BaseViewModel
{
private ObservableCollection<ClilocEntry> _allClilocs = new ObservableCollection<ClilocEntry>();
private MessageBoxResult _dialogResult = MessageBoxResult.Cancel;
private ObservableCollection<ClilocEntry> _filteredClilocs = new ObservableCollection<ClilocEntry>();
private string _filterText;
private ICommand _okCommand;
private ClilocEntry _selectedCliloc;
public ClilocSelectionViewModel()
{
foreach ( KeyValuePair<int, string> kvp in Cliloc.GetItems() )
{
AllClilocs.Add( new ClilocEntry { Key = kvp.Key, Value = kvp.Value } );
}
UpdateEntries( _filterText );
}
public ObservableCollection<ClilocEntry> AllClilocs
{
get => _allClilocs;
set => SetProperty( ref _allClilocs, value );
}
public MessageBoxResult DialogResult
{
get => _dialogResult;
set => SetProperty( ref _dialogResult, value );
}
public ObservableCollection<ClilocEntry> FilteredClilocs
{
get => _filteredClilocs;
set => SetProperty( ref _filteredClilocs, value );
}
public string FilterText
{
get => _filterText;
set
{
SetProperty( ref _filterText, value );
UpdateEntries( value );
}
}
public ICommand OKCommand => _okCommand ?? ( _okCommand = new RelayCommand( OK, o => SelectedCliloc != null ) );
public ClilocEntry SelectedCliloc
{
get => _selectedCliloc;
set => SetProperty( ref _selectedCliloc, value );
}
private void OK( object obj )
{
DialogResult = MessageBoxResult.OK;
}
private void UpdateEntries( string filterText )
{
IEnumerable<ClilocEntry> matches = AllClilocs.Where( m =>
string.IsNullOrEmpty( filterText ) || m.Key.ToString().Contains( filterText ) ||
m.Value.ToLower().Contains( filterText.ToLower() ) );
FilteredClilocs.Clear();
foreach ( ClilocEntry clilocEntry in matches )
{
FilteredClilocs.Add( clilocEntry );
}
}
public class ClilocEntry
{
public int Key { get; set; }
public string Value { get; set; }
}
}
}
@@ -0,0 +1,225 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data.Autoloot;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Objects;
using Newtonsoft.Json;
namespace ClassicAssist.Shared.UI.ViewModels.Autoloot
{
public class CustomPropertiesViewModel : BaseViewModel
{
private readonly string _propertiesFileCustom =
Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Data", "Properties.Custom.json" );
private ICommand _chooseFromItemCommand;
private ObservableCollection<CustomProperty> _properties = new ObservableCollection<CustomProperty>();
private ICommand _removeCommand;
private ICommand _saveCommand;
private CustomProperty _selectedProperty;
public CustomPropertiesViewModel()
{
LoadCustomProperties();
}
public ICommand ChooseFromClilocCommand => new RelayCommand( ChooseFromCliloc, o => true );
public ICommand ChooseFromItemCommand =>
_chooseFromItemCommand ?? ( _chooseFromItemCommand = new RelayCommandAsync( ChooseFromItem, o => true ) );
public ObservableCollection<CustomProperty> Properties
{
get => _properties;
set => SetProperty( ref _properties, value );
}
public ICommand RemoveCommand =>
_removeCommand ?? ( _removeCommand = new RelayCommand( Remove, o => SelectedProperty != null ) );
public ICommand SaveCommand => _saveCommand ?? ( _saveCommand = new RelayCommand( Save, o => true ) );
public CustomProperty SelectedProperty
{
get => _selectedProperty;
set => SetProperty( ref _selectedProperty, value );
}
private void ChooseFromCliloc( object obj )
{
ClilocSelectionViewModel vm = new ClilocSelectionViewModel();
Engine.UIInvoker.InvokeDialog( "ClilocSelectionWindow", dataContext: vm );
if ( vm.DialogResult != MessageBoxResult.OK )
{
return;
}
if ( Properties.Any( p => p.Cliloc == vm.SelectedCliloc.Key ) )
{
return;
}
Properties.AddSorted( new CustomProperty
{
Cliloc = vm.SelectedCliloc.Key,
Name = vm.SelectedCliloc.Value,
Arguments = vm.SelectedCliloc.Value.Contains( "~" )
} );
}
private async Task ChooseFromItem( object obj )
{
int serial = await Commands.GetTargeSerialAsync( Strings.Target_object___, 90000 );
if ( serial == 0 )
{
Commands.SystemMessage( Strings.Cannot_find_item___ );
return;
}
Item item = Engine.Items.GetItem( serial );
if ( item == null )
{
Commands.SystemMessage( Strings.Cannot_find_item___ );
return;
}
if ( item.Properties == null )
{
Commands.SystemMessage( Strings.Item_properties_null_or_not_loaded___ );
return;
}
PropertySelectionViewModel vm = new PropertySelectionViewModel( item.Properties );
await Engine.UIInvoker.InvokeDialog( "PropertySelectionWindow", dataContext: vm );
if ( vm.DialogResult != MessageBoxResult.OK )
{
return;
}
IEnumerable<SelectProperties> selectedProperties = vm.Properties.Where( p => p.Selected );
foreach ( SelectProperties property in selectedProperties )
{
if ( Properties.Any( p => p.Cliloc == property.Property.Cliloc ) )
{
continue;
}
Properties.AddSorted( new CustomProperty
{
Name = property.Name,
Cliloc = property.Property.Cliloc,
Arguments = property.Property.Arguments != null && property.Property.Arguments.Length > 0
} );
}
}
private void Remove( object obj )
{
if ( SelectedProperty == null )
{
return;
}
Properties.Remove( SelectedProperty );
}
private void Save( object obj )
{
SaveCustomProperties();
}
private void SaveCustomProperties()
{
List<PropertyEntry> properties = Properties.Select( property => new PropertyEntry
{
ClilocIndex = property.Arguments ? 0 : -1,
Clilocs = new[] { property.Cliloc },
ConstraintType = 0,
Name = property.Name
} ).ToList();
File.WriteAllText( _propertiesFileCustom, JsonConvert.SerializeObject( properties ) );
}
private void LoadCustomProperties()
{
if ( !File.Exists( _propertiesFileCustom ) )
{
return;
}
JsonSerializer serializer = new JsonSerializer();
using ( StreamReader sr = new StreamReader( _propertiesFileCustom ) )
{
using ( JsonTextReader reader = new JsonTextReader( sr ) )
{
PropertyEntry[] constraints = serializer.Deserialize<PropertyEntry[]>( reader );
foreach ( PropertyEntry constraint in constraints )
{
CustomProperty customProperty = new CustomProperty
{
Name = constraint.Name,
Cliloc = constraint.Clilocs[0],
Arguments = constraint.ClilocIndex == 0
};
Properties.AddSorted( customProperty );
}
}
}
}
}
public class CustomProperty : IComparable<CustomProperty>
{
public bool Arguments { get; set; }
public int Cliloc { get; set; }
public string Name { get; set; }
public int CompareTo( CustomProperty other )
{
if ( ReferenceEquals( this, other ) )
{
return 0;
}
return ReferenceEquals( null, other )
? 1
: string.Compare( Name, other.Name, StringComparison.InvariantCultureIgnoreCase );
}
}
}
@@ -0,0 +1,77 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using ClassicAssist.Misc;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.Shared.UI.ViewModels.Autoloot
{
public class PropertySelectionViewModel : BaseViewModel
{
private MessageBoxResult _dialogResult = MessageBoxResult.Cancel;
private ICommand _okCommand;
private ObservableCollection<SelectProperties> _properties = new ObservableCollection<SelectProperties>();
public PropertySelectionViewModel()
{
}
public PropertySelectionViewModel( IEnumerable<Property> properties )
{
foreach ( Property property in properties )
{
Properties.Add( new SelectProperties
{
Name = Cliloc.GetProperty( property.Cliloc ), Property = property, Selected = false
} );
}
}
public MessageBoxResult DialogResult
{
get => _dialogResult;
set => SetProperty( ref _dialogResult, value );
}
public ICommand OKCommand => _okCommand ?? ( _okCommand = new RelayCommand( OK, o => true ) );
public ObservableCollection<SelectProperties> Properties
{
get => _properties;
set => SetProperty( ref _properties, value );
}
private void OK( object obj )
{
DialogResult = MessageBoxResult.OK;
}
}
public class SelectProperties
{
public string Name { get; set; }
public Property Property { get; set; }
public bool Selected { get; set; }
}
}
@@ -0,0 +1,162 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Shared;
using ClassicAssist.UI.Misc;
using ReactiveUI;
namespace ClassicAssist.UI.ViewModels
{
public class BaseViewModel : ReactiveObject
{
private static readonly List<BaseViewModel> _viewModels = new List<BaseViewModel>();
protected IDispatcher _dispatcher;
public BaseViewModel()
{
_viewModels.Add( this );
_dispatcher = Engine.Dispatcher;
Options.CurrentOptions.PropertyChanged += OnOptionChanged;
}
public static BaseViewModel[] Instances => _viewModels.ToArray();
public virtual void SetProperty<T>( ref T obj, T value, [CallerMemberName] string propertyName = "" )
{
this.RaiseAndSetIfChanged( ref obj, value, propertyName );
}
protected void NotifyPropertyChanged( [CallerMemberName] string propertyName = "" )
{
this.RaisePropertyChanged( propertyName );
}
protected void OnOptionChanged( object sender, PropertyChangedEventArgs e )
{
PropertyInfo[] properties = GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance );
foreach ( PropertyInfo property in properties )
{
OptionsBindingAttribute attr = property.GetCustomAttribute<OptionsBindingAttribute>();
if ( attr == null || attr.Property != e.PropertyName )
{
continue;
}
if ( !( sender is Options options ) )
{
continue;
}
PropertyInfo optionsProperty = options.GetType().GetProperty( e.PropertyName );
if ( optionsProperty == null )
{
continue;
}
object propertyValue = optionsProperty.GetValue( Options.CurrentOptions );
property.SetValue( this, propertyValue );
}
}
}
public class RelayCommandAsync : ICommand
{
private readonly Func<object, bool> canExecuteMethod;
private readonly Func<object, Task> executedMethod;
public RelayCommandAsync( Func<object, Task> execute, Func<object, bool> canExecute )
{
executedMethod = execute ?? throw new ArgumentNullException( nameof( execute ) );
canExecuteMethod = canExecute;
}
public event EventHandler CanExecuteChanged
{
add => CanExecuteChangedInternal += value;
remove => CanExecuteChangedInternal -= value;
}
public bool CanExecute( object parameter )
{
return canExecuteMethod == null || canExecuteMethod( parameter );
}
public async void Execute( object parameter )
{
await executedMethod( parameter );
}
private event EventHandler CanExecuteChangedInternal;
// ReSharper disable once UnusedMember.Global
public void RaiseCanExecuteChanged()
{
CanExecuteChangedInternal?.Invoke( this, EventArgs.Empty );
}
}
public class RelayCommand : ICommand
{
private readonly Func<object, bool> _canExecute;
private readonly Action<object> _execute;
public RelayCommand( Action<object> execute, Func<object, bool> canExecute = null )
{
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add => CanExecuteChangedInternal += value;
remove => CanExecuteChangedInternal -= value;
}
public bool CanExecute( object parameter )
{
return _canExecute == null || _canExecute( parameter );
}
public void Execute( object parameter )
{
_execute( parameter );
}
private event EventHandler CanExecuteChangedInternal;
// ReSharper disable once UnusedMember.Global
public void RaiseCanExecuteChanged()
{
CanExecuteChangedInternal?.Invoke( this, EventArgs.Empty );
}
}
}
@@ -0,0 +1,141 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data.Autoloot;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Network.Packets;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugAutolootViewModel : BaseViewModel
{
private ICommand _clearResultsCommand;
private int _containerSerial;
private ICommand _retestContainerCommand;
private ICommand _testContainerCommand;
private string _testResults;
public ICommand ClearResultsCommand =>
_clearResultsCommand ?? ( _clearResultsCommand = new RelayCommand( ClearResults, o => true ) );
public int ContainerSerial
{
get => _containerSerial;
set => SetProperty( ref _containerSerial, value );
}
public ICommand RetestContainerCommand =>
_retestContainerCommand ?? ( _retestContainerCommand = new RelayCommand( RetestContainer, o => true ) );
public ICommand TestContainerCommand =>
_testContainerCommand ?? ( _testContainerCommand = new RelayCommandAsync( TestContainerAsync, o => true ) );
public string TestResults
{
get => _testResults;
set => SetProperty( ref _testResults, value );
}
private void ClearResults( object obj )
{
TestResults = string.Empty;
}
private void RetestContainer( object obj )
{
TestContainer( ContainerSerial );
}
private async Task TestContainerAsync( object arg )
{
int serial = await Commands.GetTargeSerialAsync( "Choose container...", 60000 );
if ( serial == 0 )
{
Commands.SystemMessage( Strings.Invalid_container___ );
}
ContainerSerial = serial;
TestContainer( serial );
}
private void TestContainer( int serial )
{
Item[] items = Engine.Items.GetItem( serial )?.Container?.GetItems();
if ( items == null )
{
TestResults += $"{Strings.Cannot_find_container___}\n";
Commands.SystemMessage( Strings.Cannot_find_container___ );
return;
}
Engine.SendPacketToServer( new BatchQueryProperties( items.Select( i => i.Serial ).ToArray() ) );
foreach ( AutolootEntry entry in AutolootManager.GetInstance().GetEntries() )
{
if ( !entry.Enabled )
{
TestResults += $"Entry {entry.Name} disabled...\n";
continue;
}
TestResults += $"Entry {entry.Name}...\n\n";
IEnumerable<Item> matchItems = AutolootHelpers.AutolootFilter( items, entry );
if ( matchItems == null )
{
TestResults += "No items matched...\n";
continue;
}
int count = 0;
foreach ( Item matchItem in matchItems )
{
count++;
TestResults += matchItem.ToString();
if ( matchItem.Properties != null )
{
TestResults += "\nProperties...\n\n";
foreach ( Property property in matchItem.Properties )
{
TestResults += $"{property.Text}\n";
}
}
TestResults += "\n";
}
TestResults += $"{count} matches...\n\n";
}
}
}
}
@@ -0,0 +1,56 @@
using System.Collections.ObjectModel;
using ClassicAssist.Data.BuffIcons;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Network;
using Microsoft.Scripting.Utils;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugBuffIconsViewModel : BaseViewModel
{
private readonly BuffIconManager _manager;
private ObservableCollection<string> _items = new ObservableCollection<string>();
private ObservableCollection<string> _messages = new ObservableCollection<string>();
private string _selectedItem;
public DebugBuffIconsViewModel()
{
_manager = BuffIconManager.GetInstance();
Items.AddRange( _manager.GetEnabledNames() );
IncomingPacketHandlers.BufficonEnabledDisabledEvent += OnBufficonEnabledDisabledEvent;
}
public ObservableCollection<string> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ObservableCollection<string> Messages
{
get => _messages;
set => SetProperty( ref _messages, value );
}
public string SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
private void OnBufficonEnabledDisabledEvent( int type, bool enabled, int duration )
{
BuffIconData data = _manager.GetDataByID( type );
_dispatcher.Invoke( () =>
{
Messages.Add( enabled ? $"Enabled: {data.Name}" : $"Disabled: {data?.Name}" );
Items.Clear();
Items.AddRange( _manager.GetEnabledNames() );
} );
}
}
}
@@ -0,0 +1,96 @@
using System.Collections.ObjectModel;
using System.Text;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Objects.Gumps;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugGumpViewModel : BaseViewModel
{
private ObservableCollection<Gump> _items = new ObservableCollection<Gump>();
private Gump _selectedItem;
private string _text;
public DebugGumpViewModel()
{
if ( Engine.Gumps.GetGumps( out Gump[] gumps ) )
{
foreach ( Gump gump in gumps )
{
Items.Add( gump );
}
}
IncomingPacketHandlers.GumpEvent += ( id, serial, gump ) => _dispatcher.Invoke( () =>
{
if ( Items.Contains( gump ) )
{
UpdateText( gump );
}
else
{
Items.Add( gump );
}
} );
OutgoingPacketHandlers.GumpEvent +=
( id, serial, gump ) => _dispatcher.Invoke( () => Items.Remove( gump ) );
}
public ObservableCollection<Gump> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public Gump SelectedItem
{
get => _selectedItem;
set
{
SetProperty( ref _selectedItem, value );
UpdateText( value );
}
}
public string Text
{
get => _text;
set => SetProperty( ref _text, value );
}
private void UpdateText( Gump value )
{
if ( value == null )
{
return;
}
StringBuilder sb = new StringBuilder();
sb.AppendLine( $"Gump ID: 0x{value.ID:x8}" );
sb.AppendLine( $"Serial: 0x{value.Serial:x8}" );
sb.AppendLine( $"Pages: {value.Pages?.Length}" );
sb.AppendLine();
sb.AppendLine(
$"Layout: ({value.Layout?.Length})\r\n\r\n{string.Join( "}\r\n", value.Layout?.Split( '}' ) ?? new string[0] )}" );
sb.AppendLine();
sb.AppendLine( $"Text: ({value.Strings.Length})\r\n\r\n{string.Join( "\r\n", value.Strings )}" );
sb.AppendLine();
sb.AppendLine( $"Elements ({value.GumpElements?.Length}):" );
sb.AppendLine();
if ( value.GumpElements != null )
{
foreach ( GumpElement element in value.GumpElements )
{
sb.AppendLine(
$"X: {element.X}, Y: {element.Y}, Type: {element.Type}, Cliloc: {element.Cliloc}, Text: {element.Text}" );
}
}
Text = sb.ToString();
}
}
}
@@ -0,0 +1,68 @@
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Network;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugJournalViewModel : BaseViewModel
{
private ICommand _clearCommand;
private ObservableCollection<string> _items = new ObservableCollection<string>();
private string _selectedItem;
public DebugJournalViewModel()
{
JournalEntry[] buffer = Engine.Journal.GetBuffer();
foreach ( JournalEntry journalEntry in buffer )
{
Items.Add( GetString( journalEntry ) );
}
IncomingPacketHandlers.JournalEntryAddedEvent += OnJournalEntryAddedEvent;
}
public ICommand ClearCommand => _clearCommand ?? ( _clearCommand = new RelayCommand( Clear, o => true ) );
public ObservableCollection<string> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public string SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
private void Clear( object obj )
{
Items.Clear();
}
private static string GetString( JournalEntry journalEntry )
{
StringBuilder sb = new StringBuilder();
sb.AppendLine( $"Name: {journalEntry.Name}" );
sb.AppendLine( $"Serial: 0x{journalEntry.Serial:x8}" );
sb.AppendLine( $"ID: 0x{journalEntry.ID:x4}" );
sb.AppendLine( $"Cliloc: {journalEntry.Cliloc}" );
sb.AppendLine( $"Text: {journalEntry.Text}" );
sb.AppendLine( $"Arguments: {string.Join( ",", journalEntry.Arguments ?? new string[0] )}" );
sb.AppendLine( $"Language: {journalEntry.SpeechLanguage}" );
sb.AppendLine( $"Type: {journalEntry.SpeechType}" );
return sb.ToString();
}
private void OnJournalEntryAddedEvent( JournalEntry je )
{
_dispatcher.Invoke( () => { Items.Add( GetString( je ) ); } );
}
}
}
@@ -0,0 +1,117 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.ObjectModel;
using System.Text;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugMenusViewModel : BaseViewModel
{
private ObservableCollection<Menu> _items = new ObservableCollection<Menu>();
private Menu _selectedItem;
private string _text;
public DebugMenusViewModel()
{
if ( Engine.Menus.GetMenus( out Menu[] menus ) )
{
foreach ( Menu menu in menus )
{
Items.Add( menu );
}
}
Engine.Menus.CollectionChangedEvent += OnCollectionChangedEvent;
}
public ObservableCollection<Menu> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public Menu SelectedItem
{
get => _selectedItem;
set
{
SetProperty( ref _selectedItem, value );
UpdateText( value );
}
}
public string Text
{
get => _text;
set => SetProperty( ref _text, value );
}
private void UpdateText( Menu menu )
{
if ( menu == null )
{
Text = string.Empty;
return;
}
StringBuilder sb = new StringBuilder();
sb.AppendLine( $"GumpID: 0x{menu.ID:x4}" );
sb.AppendLine( $"Serial: 0x{menu.Serial:x8}" );
sb.AppendLine( $"Title: {menu.Title}" );
sb.AppendLine( $"Entries: {menu.Entries?.Length ?? 0}" );
sb.AppendLine();
sb.AppendLine( "Entries:" );
if ( menu.Entries != null )
{
foreach ( MenuEntry menuEntry in menu.Entries )
{
sb.AppendLine( $"Index: {menuEntry.Index}" );
sb.AppendLine( $"ID: 0x{menuEntry.ID:x4}" );
sb.AppendLine( $"Hue: {menuEntry.Hue}" );
sb.AppendLine( $"Title: {menuEntry.Title}" );
sb.AppendLine();
}
}
Text = sb.ToString();
}
private void OnCollectionChangedEvent( Menu[] menus )
{
_dispatcher.Invoke( () =>
{
Items.Clear();
if ( menus == null )
{
return;
}
foreach ( Menu menu in menus )
{
Items.Add( menu );
}
} );
}
}
}
@@ -0,0 +1,93 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using Microsoft.Scripting.Utils;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugPropertiesViewModel : BaseViewModel
{
private ObservableCollection<Property> _items = new ObservableCollection<Property>();
private ICommand _targetCommand;
public ObservableCollection<Property> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand TargetCommand =>
_targetCommand ?? ( _targetCommand = new RelayCommandAsync( Target, o => true ) );
private async Task Target( object arg )
{
int serial = await Commands.GetTargeSerialAsync( Strings.Target_object___ );
if ( serial == 0 )
{
return;
}
Entity entity = UOMath.IsMobile( serial )
? Engine.Mobiles.GetMobile( serial )
: (Entity) Engine.Items.GetItem( serial );
if ( entity == null )
{
return;
}
if ( entity.Properties == null )
{
if ( Engine.Features.HasFlag( FeatureFlags.AOS ) )
{
PropertiesCommands.WaitForProperties( entity.Serial, 5000 );
}
if ( entity.Properties == null )
{
Commands.SystemMessage( Strings.Item_properties_null_or_not_loaded___ );
return;
}
}
List<Property> properties = entity.Properties.Select( entityProperty => new Property
{
Cliloc = entityProperty.Cliloc,
Text = Cliloc.GetProperty( entityProperty.Cliloc ),
Arguments = entityProperty.Arguments
} ).ToList();
Items.Clear();
Items.AddRange( properties );
}
}
}
@@ -0,0 +1,53 @@
using System.Collections.ObjectModel;
using ClassicAssist.Data.SpecialMoves;
using ClassicAssist.UI.ViewModels;
using Microsoft.Scripting.Utils;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugSpecialMovesViewModel : BaseViewModel
{
private readonly SpecialMovesManager _manager;
private ObservableCollection<string> _items = new ObservableCollection<string>();
private ObservableCollection<string> _messages = new ObservableCollection<string>();
private string _selectedItem;
public DebugSpecialMovesViewModel()
{
_manager = SpecialMovesManager.GetInstance();
Items.AddRange( _manager.GetEnabledNames() );
_manager.SpecialMovesChanged += OnSpecialMovesChanged;
}
public ObservableCollection<string> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ObservableCollection<string> Messages
{
get => _messages;
set => SetProperty( ref _messages, value );
}
public string SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
private void OnSpecialMovesChanged( string name, bool enabled )
{
_dispatcher.Invoke( () =>
{
Messages.Add( enabled ? $"Enabled: {name}" : $"Disabled: {name}" );
Items.Clear();
Items.AddRange( _manager.GetEnabledNames() );
} );
}
}
}
@@ -0,0 +1,77 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.Collections.ObjectModel;
using System.Linq;
using ClassicAssist.Data.Vendors;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
namespace ClassicAssist.Shared.UI.ViewModels.Debug
{
public class DebugVendorBuyViewModel : BaseViewModel
{
private bool _isEnabled;
private ObservableCollection<string> _messages = new ObservableCollection<string>();
public bool IsEnabled
{
get => _isEnabled;
set
{
if ( value != _isEnabled )
{
if ( value )
{
IncomingPacketHandlers.VendorBuyDisplayEvent += OnVendorBuyDisplayEvent;
}
else
{
IncomingPacketHandlers.VendorBuyDisplayEvent -= OnVendorBuyDisplayEvent;
}
}
SetProperty( ref _isEnabled, value );
}
}
public ObservableCollection<string> Messages
{
get => _messages;
set => SetProperty( ref _messages, value );
}
private void OnVendorBuyDisplayEvent( int serial, ShopListEntry[] entries )
{
_dispatcher.Invoke( () =>
{
Messages.Add( $"Vendor: Serial: 0x{serial:x}" );
foreach ( ShopListEntry entry in entries )
{
bool isCliloc = entry.Name.All( char.IsDigit );
Messages.Add(
$"\tName: {entry.Name} {( isCliloc ? $"({Cliloc.GetProperty( int.Parse( entry.Name ) )})" : string.Empty )}, Amount: {entry.Amount}, Price: {entry.Price}, ItemID: {entry.Item.ID} (0x{entry.Item.ID:x})" );
}
} );
}
}
}
@@ -0,0 +1,315 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using ClassicAssist.Annotations;
using ClassicAssist.Data;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Misc;
using ClassicAssist.UI.ViewModels;
using ClassicAssist.UO.Network.PacketFilter;
using Newtonsoft.Json.Linq;
namespace ClassicAssist.Shared.UI.ViewModels
{
public class DebugViewModel : BaseViewModel, ISettingProvider
{
private ICommand _changePacketEnabledCommand;
private ICommand _clearCommand;
private ICommand _exportLogCommand;
private ObservableCollection<PacketEntry> _items = new ObservableCollection<PacketEntry>();
private ObservableCollection<PacketEnabledEntry>
_packetEntries = new ObservableCollection<PacketEnabledEntry>();
private bool _running = true;
private PacketEntry _selectedItem;
private bool _topmost = true;
private ICommand _viewPlayerEquipmentCommand;
public DebugViewModel()
{
PacketEntries.Add( new PacketEnabledEntry { Name = Strings.All_Packets, PacketID = -1, Enabled = true } );
for ( byte i = 0; i < 0xFF; i++ )
{
PacketEntries.Add( new PacketEnabledEntry { Name = $"0x{i:x2}", PacketID = i, Enabled = i != 0x73 } );
}
Queue = new ThreadQueue<PacketEntry>( ProcessQueue );
Engine.PacketReceivedEvent += OnPacketReceivedEvent;
Engine.PacketSentEvent += OnPacketSentEvent;
Engine.InternalPacketReceivedEvent += OnInternalPacketReceivedEvent;
Engine.InternalPacketSentEvent += OnInternalPacketSentEvent;
}
public ICommand ChangePacketEnabledCommand =>
_changePacketEnabledCommand ??
( _changePacketEnabledCommand = new RelayCommand( EnableDisable, o => true ) );
public ICommand ClearCommand => _clearCommand ?? ( _clearCommand = new RelayCommand( Clear, o => true ) );
public ICommand ExportLogCommand =>
_exportLogCommand ?? ( _exportLogCommand = new RelayCommand( ExportLog, o => true ) );
public ObservableCollection<PacketEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ObservableCollection<PacketEnabledEntry> PacketEntries
{
get => _packetEntries;
set => SetProperty( ref _packetEntries, value );
}
public ThreadQueue<PacketEntry> Queue { get; set; }
public bool Running
{
get => _running;
set => SetProperty( ref _running, value );
}
public PacketEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public bool Topmost
{
get => _topmost;
set => SetProperty( ref _topmost, value );
}
public ICommand ViewPlayerEquipmentCommand =>
_viewPlayerEquipmentCommand ??
( _viewPlayerEquipmentCommand = new RelayCommand( ViewPlayerEquipment, o => true ) );
public void Serialize( JObject json )
{
if ( json?["Debug"] != null )
{
return;
}
JObject options = new JObject();
json?.Add( "Debug", options );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
if ( json?["Debug"] == null )
{
}
}
private void ExportLog( object obj )
{
if ( !( obj is IEnumerable<PacketEntry> items ) )
{
}
//TODO UI
//SaveFileDialog sfd = new SaveFileDialog
//{
// InitialDirectory = Engine.StartupPath ?? Environment.CurrentDirectory,
// Filter = "JSON Packet Log|*.packets.json",
// FileName = "export.packets.json"
//};
//bool? result = sfd.ShowDialog();
//if ( !result.HasValue || !result.Value || string.IsNullOrEmpty( sfd.FileName ) )
//{
// return;
//}
//string fileName = sfd.FileName;
//JArray jArray = new JArray();
//foreach ( PacketEntry packetEntry in items )
//{
// jArray.Add( new JObject
// {
// { "Title", packetEntry.Title },
// { "DateTime", packetEntry.DateTime },
// { "Direction", packetEntry.Direction.ToString() },
// { "Length", packetEntry.Length },
// { "Data", packetEntry.Data.Aggregate( string.Empty, ( current, b ) => current + $"{b:x2} " ) },
// { "Base64", Convert.ToBase64String( packetEntry.Data ) }
// } );
//}
//File.WriteAllText( fileName, jArray.ToString() );
}
private void ProcessQueue( PacketEntry entry )
{
_dispatcher.Invoke( () => { Items.Add( entry ); } );
}
private void OnInternalPacketSentEvent( byte[] data, int length )
{
if ( PacketEntries.FirstOrDefault( e => e.PacketID == data[0] )?.Enabled == false )
{
return;
}
if ( !Running )
{
return;
}
PacketEntry entry = new PacketEntry
{
Title = "Internal Outgoing Packet", Data = data, Direction = PacketDirection.Outgoing
};
Queue.Enqueue( entry );
}
private void OnInternalPacketReceivedEvent( byte[] data, int length )
{
if ( PacketEntries.FirstOrDefault( e => e.PacketID == data[0] )?.Enabled == false )
{
return;
}
if ( !Running )
{
return;
}
PacketEntry entry = new PacketEntry
{
Title = "Internal Incoming Packet", Data = data, Direction = PacketDirection.Incoming
};
Queue.Enqueue( entry );
}
private void OnPacketSentEvent( byte[] data, int length )
{
if ( PacketEntries.FirstOrDefault( e => e.PacketID == data[0] )?.Enabled == false )
{
return;
}
if ( !Running )
{
return;
}
PacketEntry entry = new PacketEntry
{
Title = "Outgoing Packet", Data = data, Direction = PacketDirection.Outgoing
};
Queue.Enqueue( entry );
}
private void OnPacketReceivedEvent( byte[] data, int length )
{
if ( PacketEntries.FirstOrDefault( e => e.PacketID == data[0] )?.Enabled == false )
{
return;
}
if ( !Running )
{
return;
}
PacketEntry entry = new PacketEntry
{
Title = "Incoming Packet", Data = data, Direction = PacketDirection.Incoming
};
Queue.Enqueue( entry );
}
private void ViewPlayerEquipment( object obj )
{
//TODO UI
//EntityCollectionViewer window = new EntityCollectionViewer
//{
// DataContext = new EntityCollectionViewerViewModel( Engine.Player?.Equipment ) { Topmost = Topmost }
//};
//window.Show();
}
private void Clear( object obj )
{
Items.Clear();
}
private void EnableDisable( object obj )
{
if ( !( obj is PacketEnabledEntry packetEnabledEntry ) )
{
return;
}
if ( packetEnabledEntry.PacketID != -1 )
{
return;
}
foreach ( PacketEnabledEntry entry in PacketEntries )
{
entry.Enabled = packetEnabledEntry.Enabled;
}
}
public class PacketEnabledEntry : INotifyPropertyChanged
{
private bool _enabled;
private string _name;
private int _packetId;
public bool Enabled
{
get => _enabled;
set => SetProperty( ref _enabled, value );
}
public string Name
{
get => _name;
set => SetProperty( ref _name, value );
}
public int PacketID
{
get => _packetId;
set => SetProperty( ref _packetId, value );
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = null )
{
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
}
// ReSharper disable once RedundantAssignment
public virtual void SetProperty<T>( ref T obj, T value, [CallerMemberName] string propertyName = "" )
{
obj = value;
OnPropertyChanged( propertyName );
}
}
}
}
@@ -0,0 +1,367 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Filters;
using ClassicAssist.Data.Macros;
using ClassicAssist.Misc;
using ClassicAssist.Shared;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UI.ViewModels;
using ClassicAssist.Shared.UO;
using ClassicAssist.UI.Misc;
using Newtonsoft.Json.Linq;
namespace ClassicAssist.UI.ViewModels
{
public class GeneralControlViewModel : BaseViewModel, ISettingProvider
{
private static ICommand _saveProfileCommand;
private ICommand _changeProfileCommand;
private ICommand _configureFilterCommand;
private bool _isLinkedProfile;
private ICommand _linkUnlinkProfileCommand;
private ICommand _newProfileCommand;
private Options _options;
private ObservableCollection<string> _profiles = new ObservableCollection<string>();
private ICommand _removeSavedPasswordCommand;
private Dictionary<string, string> _savedPasswords = new Dictionary<string, string>();
private string _selectedProfile = Options.CurrentOptions.Name;
public GeneralControlViewModel()
{
Type[] filterTypes =
{
typeof( WeatherFilter ), typeof( SeasonFilter ), typeof( LightLevelFilter ),
typeof( RepeatedMessagesFilter ), typeof( ClilocFilter ), typeof( BardsMusicFilter )
};
foreach ( Type type in filterTypes )
{
FilterEntry fe = (FilterEntry) Activator.CreateInstance( type );
Filters.Add( fe );
}
RefreshProfiles();
AssistantOptions.ProfileChangedEvent += OnProfileChangedEvent;
AssistantOptions.SavedPasswordsChanged += OnSavedPasswordsChangedEvent;
OnSavedPasswordsChangedEvent( this, EventArgs.Empty );
}
public ICommand ChangeProfileCommand =>
_changeProfileCommand ?? ( _changeProfileCommand = new RelayCommand( ChangeProfile, o => true ) );
public ICommand ConfigureFilterCommand =>
_configureFilterCommand ?? ( _configureFilterCommand = new RelayCommand( ConfigureFilter ) );
public ObservableCollectionEx<FilterEntry> Filters { get; set; } = new ObservableCollectionEx<FilterEntry>();
public bool IsLinkedProfile
{
get => _isLinkedProfile;
set => SetProperty( ref _isLinkedProfile, value );
}
[OptionsBinding( Property = "LightLevel" )]
public int LightLevelListen
{
get => throw new NotImplementedException();
set
{
FilterEntry filter = Filters.FirstOrDefault( f => f is LightLevelFilter );
if ( filter == null || !filter.Enabled )
{
return;
}
byte[] packet = { 0x4F, (byte) value };
Engine.SendPacketToClient( packet, packet.Length );
}
}
public ICommand LinkUnlinkProfileCommand =>
_linkUnlinkProfileCommand ?? ( _linkUnlinkProfileCommand = new RelayCommand( LinkUnlinkProfile ) );
public ICommand NewProfileCommand =>
_newProfileCommand ?? ( _newProfileCommand = new RelayCommandAsync( NewProfile, o => true ) );
public Options Options
{
get => _options;
set => SetProperty( ref _options, value );
}
public ObservableCollection<string> Profiles
{
get => _profiles;
set => SetProperty( ref _profiles, value );
}
public ICommand RemoveSavedPasswordCommand =>
_removeSavedPasswordCommand ?? ( _removeSavedPasswordCommand =
new RelayCommand( RemoveSavedPassword, o => AssistantOptions.SavePasswords ) );
public Dictionary<string, string> SavedPasswords
{
get => _savedPasswords;
set => SetProperty( ref _savedPasswords, value );
}
public bool SavePasswords
{
get => AssistantOptions.SavePasswords;
set => AssistantOptions.SavePasswords = value;
}
public bool SavePasswordsOnlyBlank
{
get => AssistantOptions.SavePasswordsOnlyBlank;
set => AssistantOptions.SavePasswordsOnlyBlank = value;
}
public ICommand SaveProfileCommand =>
_saveProfileCommand ?? ( _saveProfileCommand = new RelayCommand( SaveProfile ) );
public string SelectedProfile
{
get => _selectedProfile;
set => SetProperty( ref _selectedProfile, value );
}
public void Serialize( JObject json )
{
JObject obj = new JObject
{
["AlwaysOnTop"] = Options.CurrentOptions.AlwaysOnTop,
["LightLevel"] = Options.CurrentOptions.LightLevel,
["ActionDelay"] = Options.CurrentOptions.ActionDelay,
["ActionDelayMS"] = Options.CurrentOptions.ActionDelayMS,
["Debug"] = Options.CurrentOptions.Debug
};
JArray filtersArray = new JArray();
foreach ( FilterEntry filterEntry in Filters )
{
JObject filterObj = new JObject
{
{ "Name", filterEntry.GetType().ToString() }, { "Enabled", filterEntry.Enabled }
};
if ( filterEntry is IConfigurableFilter configurableFilter )
{
JObject options = configurableFilter.Serialize();
filterObj.Add( "Options", options );
}
filtersArray.Add( filterObj );
}
obj.Add( "Filters", filtersArray );
json?.Add( "General", obj );
}
public void Deserialize( JObject json, Options options )
{
Options = options;
// Reset current filters to default value
foreach ( FilterEntry filterEntry in Filters )
{
FilterOptionsAttribute a =
(FilterOptionsAttribute) Attribute.GetCustomAttribute( filterEntry.GetType(),
typeof( FilterOptionsAttribute ) );
if ( a == null )
{
continue;
}
filterEntry.Enabled = a.DefaultEnabled;
if ( filterEntry is IConfigurableFilter configurableFilter )
{
configurableFilter.ResetOptions();
}
}
if ( json?["General"] == null )
{
return;
}
JToken general = json["General"];
Options.LightLevel = general["LightLevel"]?.ToObject<int>() ?? 100;
Options.ActionDelay = general["ActionDelay"]?.ToObject<bool>() ?? false;
Options.ActionDelayMS = general["ActionDelayMS"]?.ToObject<int>() ?? 900;
Options.AlwaysOnTop = general["AlwaysOnTop"]?.ToObject<bool>() ?? false;
Options.Debug = general["Debug"]?.ToObject<bool>() ?? false;
if ( general["Filters"] == null )
{
return;
}
foreach ( JToken token in general["Filters"] )
{
string filterName = token["Name"]?.ToObject<string>() ?? string.Empty;
bool enabled = token["Enabled"]?.ToObject<bool>() ?? false;
FilterEntry filter = Filters.FirstOrDefault( f => f.GetType().ToString().Equals( filterName ) );
if ( filter != null )
{
filter.Enabled = enabled;
}
if ( filter is IConfigurableFilter configurableFilter && token["Options"] != null )
{
configurableFilter.Deserialize( token["Options"] );
}
}
}
private void OnSavedPasswordsChangedEvent( object sender, EventArgs e )
{
Dictionary<string, string> newList =
AssistantOptions.SavedPasswords.ToDictionary( kvp => kvp.Key, kvp => kvp.Value );
SavedPasswords = newList;
}
private void RemoveSavedPassword( object obj )
{
if ( !( obj is KeyValuePair<string, string> kvp ) )
{
return;
}
SavedPasswords.Remove( kvp.Key );
AssistantOptions.SavedPasswords.Remove( kvp.Key );
AssistantOptions.OnPasswordsChanged();
}
private static void ConfigureFilter( object obj )
{
if ( !( obj is IConfigurableFilter configurableFilter ) )
{
return;
}
configurableFilter.Configure();
}
private void OnProfileChangedEvent( string profile )
{
_dispatcher.Invoke( () =>
{
Options = Options.CurrentOptions;
if ( Engine.Player != null )
{
IsLinkedProfile = AssistantOptions.GetLinkedProfile( Engine.Player.Serial ) == profile;
}
SelectedProfile = profile;
} );
}
private static void SaveProfile( object obj )
{
Options.Save( Options.CurrentOptions );
Commands.SystemMessage( Strings.Profile_saved___ );
}
private void RefreshProfiles()
{
string[] profiles = Options.GetProfiles();
if ( profiles == null )
{
return;
}
Profiles.Clear();
foreach ( string profile in profiles )
{
Profiles.Add( Path.GetFileName( profile ) );
}
}
private void ChangeProfile( object obj )
{
if ( !( obj is string profileName ) )
{
return;
}
MacroManager.GetInstance().StopAll();
LoadProfile( profileName );
Engine.UpdateWindowTitle();
}
private void LinkUnlinkProfile( object obj )
{
if ( Engine.Player == null )
{
return;
}
if ( AssistantOptions.GetLinkedProfile( Engine.Player.Serial ) == Options.CurrentOptions.Name )
{
AssistantOptions.RemoveLinkedProfile( Engine.Player.Serial );
IsLinkedProfile = false;
}
else
{
AssistantOptions.SetLinkedProfile( Engine.Player.Serial, Options.CurrentOptions.Name );
IsLinkedProfile = true;
}
}
private void LoadProfile( string profile )
{
foreach ( FilterEntry filterEntry in Filters )
{
filterEntry?.Action( false );
}
Options.ClearOptions();
Options.CurrentOptions = new Options();
Options.Load( profile, Options.CurrentOptions );
AssistantOptions.LastProfile = profile;
if ( Engine.Player != null )
{
IsLinkedProfile = AssistantOptions.GetLinkedProfile( Engine.Player.Serial ) == profile;
}
}
private async Task NewProfile( object arg )
{
NewProfileViewModel vm = new NewProfileViewModel();
await Engine.UIInvoker.InvokeDialog( "NewProfileWindow", dataContext: vm );
if (!string.IsNullOrEmpty( vm.FileName ) )
{
RefreshProfiles();
SelectedProfile = vm.FileName;
ChangeProfile( vm.FileName );
}
}
}
}
@@ -0,0 +1,63 @@
using System.Collections.Specialized;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Data.Hotkeys.Commands;
using ClassicAssist.UI.Misc;
using Newtonsoft.Json.Linq;
namespace ClassicAssist.UI.ViewModels
{
public abstract class HotkeyEntryViewModel<T> : BaseViewModel where T : HotkeyEntry
{
private readonly HotkeyCommand _category;
private ObservableCollectionEx<T> _items = new ObservableCollectionEx<T>();
protected HotkeyEntryViewModel( string name )
{
_category = new HotkeyCommand { Name = name, IsCategory = true };
HotkeyManager hotkey = HotkeyManager.GetInstance();
hotkey.AddCategory( _category );
Items.CollectionChanged += OnCollectionChanged;
_category.Children = new ObservableCollectionEx<HotkeyEntry>();
}
public ObservableCollectionEx<T> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
~HotkeyEntryViewModel()
{
Items.CollectionChanged -= OnCollectionChanged;
}
protected virtual void OnCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
_category.Children = new ObservableCollectionEx<HotkeyEntry>();
foreach ( T item in Items )
{
_category.Children.Add( item );
}
}
protected void SetJsonValue( JToken json, string name, JToken value )
{
json[name] = value;
}
protected T2 GetJsonValue<T2>( JToken json, string name, T2 defaultValue )
{
if ( json == null )
{
return defaultValue;
}
return json[name] == null ? defaultValue : json[name].ToObject<T2>();
}
}
}
@@ -0,0 +1,374 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reflection;
using ClassicAssist.Data;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Data.Hotkeys.Commands;
using ClassicAssist.Data.Spells;
using ClassicAssist.Misc;
using ClassicAssist.Shared;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Misc;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.UI.ViewModels
{
public class HotkeysTabViewModel : BaseViewModel, ISettingProvider
{
private readonly HotkeyManager _hotkeyManager;
private readonly List<HotkeyCommand> _serializeCategories = new List<HotkeyCommand>();
private ReactiveCommand<HotkeyEntry, Unit> _clearHotkeyCommand;
private ReactiveCommand<HotkeyEntry, Unit> _executeCommand;
private HotkeyCommand _masteriesCategory;
private HotkeyEntry _selectedItem;
private HotkeyCommand _spellsCategory;
public HotkeysTabViewModel()
{
_hotkeyManager = HotkeyManager.GetInstance();
_hotkeyManager.ClearAllHotkeys = ClearAllHotkeys;
}
public ReactiveCommand<HotkeyEntry, Unit> ClearHotkeyCommand =>
_clearHotkeyCommand ?? ( _clearHotkeyCommand = ReactiveCommand.Create<HotkeyEntry>( ClearHotkey,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
public ReactiveCommand<HotkeyEntry, Unit> ExecuteCommand =>
_executeCommand ?? ( _executeCommand = ReactiveCommand.Create<HotkeyEntry>( ExecuteHotkey,
this.WhenAnyValue( e => e.SelectedItem, e => e != null && !e.IsCategory ) ) );
public ShortcutKeys Hotkey
{
get => SelectedItem?.Hotkey;
set => CheckOverwriteHotkey( SelectedItem, value );
}
public ObservableCollectionEx<HotkeyCommand> Items
{
get => _hotkeyManager.Items;
set => _hotkeyManager.Items = value;
}
public HotkeyEntry SelectedItem
{
get => _selectedItem;
set
{
SetProperty( ref _selectedItem, value == null || !value.IsCategory ? value : null );
NotifyPropertyChanged( nameof( Hotkey ) );
}
}
public void Serialize( JObject json )
{
JObject hotkeys = new JObject();
JArray commandsArray = new JArray();
foreach ( HotkeyCommand category in _serializeCategories )
{
foreach ( HotkeyEntry categoryChild in category.Children )
{
if ( Equals( categoryChild.Hotkey, ShortcutKeys.Default ) )
{
continue;
}
JObject entry = new JObject
{
{ "Type", categoryChild.GetType().FullName },
{ "Keys", categoryChild.Hotkey.ToJObject() },
{ "PassToUO", categoryChild.PassToUO }
};
commandsArray.Add( entry );
}
}
hotkeys.Add( "Commands", commandsArray );
JArray spellsArray = new JArray();
foreach ( HotkeyEntry spellsCategoryChild in _spellsCategory.Children )
{
if ( Equals( spellsCategoryChild.Hotkey, ShortcutKeys.Default ) )
{
continue;
}
JObject entry = new JObject
{
{ "Name", spellsCategoryChild.Name },
{ "Keys", spellsCategoryChild.Hotkey.ToJObject() },
{ "PassToUO", spellsCategoryChild.PassToUO }
};
spellsArray.Add( entry );
}
hotkeys.Add( "Spells", spellsArray );
JArray masteryArray = new JArray();
foreach ( HotkeyEntry masteriesCategoryChild in _masteriesCategory.Children )
{
if ( Equals( masteriesCategoryChild.Hotkey, ShortcutKeys.Default ) )
{
continue;
}
JObject entry = new JObject
{
{ "Name", masteriesCategoryChild.Name },
{ "Keys", masteriesCategoryChild.Hotkey.ToJObject() },
{ "PassToUO", masteriesCategoryChild.PassToUO }
};
masteryArray.Add( entry );
}
hotkeys.Add( "Masteries", masteryArray );
json?.Add( "Hotkeys", hotkeys );
}
public void Deserialize( JObject json, Options options )
{
IEnumerable<Type> hotkeyCommands = Assembly.GetExecutingAssembly().GetTypes()
.Where( i => i.IsSubclassOf( typeof( HotkeyCommand ) ) );
foreach ( Type hotkeyCommand in hotkeyCommands )
{
HotkeyCommand hkc = (HotkeyCommand) Activator.CreateInstance( hotkeyCommand );
HotkeyCommandAttribute attr = hkc.GetType().GetCustomAttribute<HotkeyCommandAttribute>();
string categoryName = Strings.Commands;
if ( attr != null && !string.IsNullOrEmpty( attr.Category ) )
{
categoryName = Strings.ResourceManager.GetString( attr.Category );
}
HotkeyCommand category = Items.FirstOrDefault( hke => hke.Name == categoryName && hke.IsCategory );
if ( category != null )
{
if ( category.Children == null )
{
category.Children = new ObservableCollectionEx<HotkeyEntry>();
}
if ( category.Children.Contains( hkc ) )
{
category.Children.Remove( hkc );
}
category.Children.Add( hkc );
}
else
{
category = new HotkeyCommand
{
Name = categoryName, IsCategory = true, Children = new ObservableCollectionEx<HotkeyEntry>()
};
category.Children.Add( hkc );
_hotkeyManager.AddCategory( category );
_serializeCategories.Add( category );
}
}
JToken hotkeys = json?["Hotkeys"];
if ( hotkeys?["Commands"] != null )
{
foreach ( JToken token in hotkeys["Commands"] )
{
JToken type = token["Type"];
foreach ( HotkeyCommand category in _serializeCategories )
{
HotkeyEntry entry =
category.Children.FirstOrDefault( o => o.GetType().FullName == type.ToObject<string>() );
if ( entry == null )
{
continue;
}
JToken keys = token["Keys"];
entry.Hotkey = new ShortcutKeys( keys );
entry.PassToUO = token["PassToUO"]?.ToObject<bool>() ?? true;
}
}
}
if ( _spellsCategory != null )
{
_hotkeyManager.Items.Remove( _spellsCategory );
}
_spellsCategory = new HotkeyCommand { Name = Strings.Spells, IsCategory = true };
SpellManager spellManager = SpellManager.GetInstance();
SpellData[] spells = spellManager.GetSpellData();
ObservableCollectionEx<HotkeyEntry> children = new ObservableCollectionEx<HotkeyEntry>();
foreach ( SpellData spell in spells )
{
HotkeyCommand hkc = new HotkeyCommand
{
Name = spell.Name,
Action = hks => spellManager.CastSpell( spell.ID ),
Hotkey = ShortcutKeys.Default,
PassToUO = true
};
children.Add( hkc );
}
_spellsCategory.Children = children;
_hotkeyManager.AddCategory( _spellsCategory );
JToken spellsObj = hotkeys?["Spells"];
if ( spellsObj != null )
{
foreach ( JToken token in spellsObj )
{
JToken name = token["Name"];
HotkeyEntry entry =
_spellsCategory.Children.FirstOrDefault( s => s.Name == name.ToObject<string>() );
if ( entry == null )
{
continue;
}
entry.Hotkey = new ShortcutKeys( token["Keys"] );
entry.PassToUO = token["PassToUO"]?.ToObject<bool>() ?? true;
}
}
if ( _masteriesCategory != null )
{
_hotkeyManager.Items.Remove( _masteriesCategory );
}
_masteriesCategory = new HotkeyCommand { Name = Strings.Masteries, IsCategory = true };
SpellData[] masteries = spellManager.GetMasteryData();
ObservableCollectionEx<HotkeyEntry> masteryChildren = new ObservableCollectionEx<HotkeyEntry>();
foreach ( SpellData mastery in masteries )
{
HotkeyCommand hkc = new HotkeyCommand
{
Name = mastery.Name,
Action = hks => spellManager.CastSpell( mastery.ID ),
Hotkey = ShortcutKeys.Default,
PassToUO = true
};
masteryChildren.Add( hkc );
}
_masteriesCategory.Children = masteryChildren;
_hotkeyManager.AddCategory( _masteriesCategory );
JToken masteryObj = hotkeys?["Masteries"];
if ( masteryObj != null )
{
foreach ( JToken token in masteryObj )
{
JToken name = token["Name"];
HotkeyEntry entry =
_masteriesCategory.Children.FirstOrDefault( s => s.Name == name.ToObject<string>() );
if ( entry == null )
{
continue;
}
entry.Hotkey = new ShortcutKeys( token["Keys"] );
entry.PassToUO = token["PassToUO"]?.ToObject<bool>() ?? true;
}
}
}
private async void CheckOverwriteHotkey( HotkeyEntry selectedItem, ShortcutKeys hotkey )
{
HotkeyEntry conflict = null;
foreach ( HotkeyCommand hotkeyEntry in Items )
{
foreach ( HotkeyEntry entry in hotkeyEntry.Children )
{
if ( entry.Hotkey.Equals( hotkey ) )
{
conflict = entry;
}
}
}
if ( conflict != null && !ReferenceEquals( selectedItem, conflict ) )
{
MessageBoxResult result = await Engine.MessageBoxProvider.Show(
string.Format( Strings.Overwrite_existing_hotkey___0____, conflict ), Strings.Warning,
MessageBoxButtons.YesNo );
if ( result == MessageBoxResult.No )
{
NotifyPropertyChanged( nameof( Hotkey ) );
return;
}
}
SelectedItem.Hotkey = hotkey;
NotifyPropertyChanged( nameof( Hotkey ) );
}
private void ClearAllHotkeys()
{
foreach ( HotkeyEntry entryChild in _serializeCategories.SelectMany( hotkeyEntry => hotkeyEntry.Children ) )
{
entryChild.Hotkey = ShortcutKeys.Default;
}
foreach ( HotkeyEntry spellEntry in _spellsCategory.Children )
{
spellEntry.Hotkey = ShortcutKeys.Default;
}
}
private void ClearHotkey( object obj )
{
if ( obj is HotkeyEntry cmd )
{
cmd.Hotkey = ShortcutKeys.Default;
this.RaisePropertyChanged( nameof( Hotkey ) );
}
}
private static void ExecuteHotkey( object obj )
{
if ( obj is HotkeyEntry cmd )
{
cmd.Action( cmd );
}
}
}
}
@@ -0,0 +1,492 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Data.Macros;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Misc;
using ClassicAssist.Shared;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ReactiveUI;
namespace ClassicAssist.UI.ViewModels
{
public class MacrosTabViewModel : HotkeyEntryViewModel<MacroEntry>, ISettingProvider
{
private readonly MacroManager _manager;
private int _caretPosition;
private ReactiveCommand<MacroEntry, Unit> _clearHotkeyCommand;
//TODO
//private TextDocument _document;
private ReactiveCommand<MacroEntry, Unit> _executeCommand;
private ICommand _inspectObjectCommand;
private bool _isRecording;
private RelayCommand _newMacroCommand;
private ICommand _recordCommand;
private RelayCommand _removeMacroCommand;
private ReactiveCommand<MacroEntry, Unit> _removeMacroConfirmCommand;
private ICommand _saveMacroCommand;
private MacroEntry _selectedItem;
private ICommand _showActiveObjectsWindowCommand;
private ICommand _showCommandsCommand;
private ICommand _showMacrosWikiCommand;
private ReactiveCommand<MacroEntry, Unit> _stopCommand;
public MacrosTabViewModel() : base( Strings.Macros )
{
Engine.DisconnectedEvent += OnDisconnectedEvent;
_manager = MacroManager.GetInstance();
_manager.IsRecording = () => _isRecording;
_manager.InsertDocument = str => { _dispatcher.Invoke( () => { SelectedItem.Macro += str; } ); };
_manager.NewMacro = NewMacro;
_manager.Items = Items;
}
public int CaretPosition
{
get => _caretPosition;
set => SetProperty( ref _caretPosition, value );
}
public ReactiveCommand<MacroEntry, Unit> ClearHotkeyCommand =>
_clearHotkeyCommand ?? ( _clearHotkeyCommand = ReactiveCommand.Create<MacroEntry>( ClearHotkey,
this.WhenAnyValue( e => e.SelectedItem, selector: e => e != null ) ) );
//TODO
//public TextDocument Document
//{
// get => _document;
// set => SetProperty( ref _document, value );
//}
public ReactiveCommand<MacroEntry, Unit> ExecuteCommand =>
_executeCommand ?? ( _executeCommand = ReactiveCommand.CreateFromTask<MacroEntry>( Execute,
this.WhenAnyValue( x => x.IsRecording, x => x.SelectedItem, x => x.SelectedItem.IsRunning,
( b, entry, running ) => !b && entry != null && !running ) ) );
public ShortcutKeys Hotkey
{
get => SelectedItem?.Hotkey;
set => CheckOverwriteHotkey( SelectedItem, value );
}
//TODO
public ICommand InspectObjectCommand =>
_inspectObjectCommand ?? ( _inspectObjectCommand = new RelayCommandAsync( InspectObject, o => true ) );
public bool IsRecording
{
get => _isRecording;
set => SetProperty( ref _isRecording, value );
}
public RelayCommand NewMacroCommand =>
_newMacroCommand ??
( _newMacroCommand = new RelayCommand( NewMacro, o => !SelectedItem?.IsRunning ?? true ) );
public ICommand RecordCommand =>
_recordCommand ?? ( _recordCommand = new RelayCommand( Record, o => SelectedItem != null ) );
public string RecordLabel => IsRecording ? Strings.Stop : Strings.Record;
public RelayCommand RemoveMacroCommand =>
_removeMacroCommand ?? ( _removeMacroCommand =
new RelayCommand( RemoveMacro, o => !SelectedItem?.IsRunning ?? SelectedItem != null ) );
public ReactiveCommand<MacroEntry, Unit> RemoveMacroConfirmCommand =>
_removeMacroConfirmCommand ?? ( _removeMacroConfirmCommand =
ReactiveCommand.Create<MacroEntry, Unit>( RemoveMacroConfirm,
this.WhenAnyValue( o => o.SelectedItem, selector: o => o != null ) ) );
public ICommand SaveMacroCommand =>
_saveMacroCommand ?? ( _saveMacroCommand = new RelayCommand( SaveMacro, o => true ) );
public MacroEntry SelectedItem
{
get => _selectedItem;
set
{
SetProperty( ref _selectedItem, value );
NotifyPropertyChanged( nameof( Hotkey ) );
}
}
public ICommand ShowActiveObjectsWindowCommand =>
_showActiveObjectsWindowCommand ?? ( _showActiveObjectsWindowCommand =
new RelayCommand( ShowActiveObjectsWindow, o => true ) );
public ICommand ShowCommandsCommand =>
_showCommandsCommand ?? ( _showCommandsCommand = new RelayCommand( ShowCommands, o => true ) );
public ICommand ShowMacrosWikiCommand =>
_showMacrosWikiCommand ?? ( _showMacrosWikiCommand = new RelayCommand( ShowMacrosWiki, o => true ) );
//public ICommand StopCommand =>
// _stopCommand ?? ( _stopCommand = new RelayCommandAsync( Stop, o => SelectedItem?.IsRunning ?? false ) );
public ReactiveCommand<MacroEntry, Unit> StopCommand =>
_stopCommand ?? ( _stopCommand = ReactiveCommand.CreateFromTask<MacroEntry>( Stop,
this.WhenAnyValue( e => e.SelectedItem.IsRunning ) ) );
public void Serialize( JObject json )
{
JObject macros = new JObject();
JArray macroArray = new JArray();
IEnumerable<MacroEntry> globalMacros = Items.Where( e => e.Global );
if ( globalMacros.Any() )
{
string globalJson = JsonConvert.SerializeObject( globalMacros, Formatting.Indented );
File.WriteAllText( Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Macros.json" ),
globalJson );
}
foreach ( MacroEntry macroEntry in Items.Where( e => !e.Global ) )
{
JObject entry = new JObject
{
{ "Name", macroEntry.Name },
{ "Loop", macroEntry.Loop },
{ "DoNotAutoInterrupt", macroEntry.DoNotAutoInterrupt },
{ "Macro", macroEntry.Macro },
{ "PassToUO", macroEntry.PassToUO },
{ "Keys", macroEntry.Hotkey.ToJObject() },
{ "IsBackground", macroEntry.IsBackground },
{ "IsAutostart", macroEntry.IsAutostart },
{ "Disableable", macroEntry.Disableable }
};
JArray aliasesArray = new JArray();
foreach ( JObject aliasObj in macroEntry.Aliases.Select( kvp =>
new JObject { { "Key", kvp.Key }, { "Value", kvp.Value } } ) )
{
aliasesArray.Add( aliasObj );
}
entry.Add( "Aliases", aliasesArray );
macroArray.Add( entry );
}
macros.Add( "Macros", macroArray );
JArray aliasArray = new JArray();
foreach ( JObject entry in AliasCommands.GetAllAliases()
.Select( kvp => new JObject { { "Name", kvp.Key }, { "Value", kvp.Value } } ) )
{
aliasArray.Add( entry );
}
macros.Add( "Alias", aliasArray );
json?.Add( "Macros", macros );
}
public void Deserialize( JObject json, Options options )
{
Items.Clear();
string globalPath = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Macros.json" );
if ( File.Exists( globalPath ) )
{
string globalJson = File.ReadAllText( globalPath );
MacroEntry[] globalMacros = JsonConvert.DeserializeObject<MacroEntry[]>( globalJson );
if ( globalMacros != null )
{
foreach ( MacroEntry entry in globalMacros )
{
entry.Action = async hks => await Execute( entry );
if ( Options.CurrentOptions.SortMacrosAlphabetical )
{
Items.AddSorted( entry );
}
else
{
Items.Add( entry );
}
}
}
}
JToken config = json?["Macros"];
if ( config == null )
{
return;
}
if ( config["Macros"] != null )
{
foreach ( JToken token in config["Macros"] )
{
MacroEntry entry = new MacroEntry
{
Name = GetJsonValue( token, "Name", string.Empty ),
Loop = GetJsonValue( token, "Loop", false ),
DoNotAutoInterrupt = GetJsonValue( token, "DoNotAutoInterrupt", false ),
Macro = GetJsonValue( token, "Macro", string.Empty ),
PassToUO = GetJsonValue( token, "PassToUO", true ),
Hotkey = new ShortcutKeys( token["Keys"] ),
IsBackground = GetJsonValue( token, "IsBackground", false ),
IsAutostart = GetJsonValue( token, "IsAutostart", false ),
Disableable = GetJsonValue( token, "Disableable", true )
};
if ( token["Aliases"] != null )
{
foreach ( JToken aliasToken in token["Aliases"] )
{
entry.Aliases.Add( aliasToken["Key"].ToObject<string>(),
aliasToken["Value"].ToObject<int>() );
}
}
// Global macro takes precedence for hotkey
if ( Items.Any( e => Equals( e.Hotkey, entry.Hotkey ) && e.Global ) )
{
entry.Hotkey = ShortcutKeys.Default;
}
entry.Action = async hks =>
await Engine.Dispatcher.InvokeAsync( async () => await Execute( entry ) );
if ( Options.CurrentOptions.SortMacrosAlphabetical )
{
Items.AddSorted( entry );
}
else
{
Items.Add( entry );
}
}
}
if ( config["Alias"] != null )
{
foreach ( JToken token in config["Alias"] )
{
AliasCommands.SetAlias( token["Name"].ToObject<string>(), token["Value"].ToObject<int>() );
}
}
string modulePath = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Modules" );
if ( !Directory.Exists( modulePath ) )
{
Directory.CreateDirectory( modulePath );
}
string assistantModule = Path.Combine( modulePath, "Assistant.py" );
if ( !File.Exists( assistantModule ) )
{
File.WriteAllText( assistantModule, "from ClassicAssist.Shared import Engine as _Engine\nEngine = _Engine" );
}
}
private Unit RemoveMacroConfirm( object obj )
{
if ( !( obj is MacroEntry entry ) )
{
return Unit.Default;
}
//TODO
//MessageBoxResult result = MessageBox.Show( string.Format( Strings.Really_remove_macro___0___, entry.Name ),
// Strings.Warning, MessageBoxButton.YesNo, MessageBoxImage.Warning );
//if ( result == MessageBoxResult.No )
//{
// return;
//}
RemoveMacro( entry );
return Unit.Default;
}
private static void ShowMacrosWiki( object obj )
{
Process.Start( Strings.MACRO_WIKI_URL );
}
private bool CanExecute( object arg )
{
if ( !( arg is MacroEntry entry ) )
{
return false;
}
if ( entry.IsRunning )
{
return false;
}
return true;
}
private void CheckOverwriteHotkey( HotkeyEntry selectedItem, ShortcutKeys hotkey )
{
HotkeyEntry conflict = null;
foreach ( HotkeyEntry hotkeyEntry in HotkeyManager.GetInstance().Items )
{
foreach ( HotkeyEntry entry in hotkeyEntry.Children )
{
if ( entry.Hotkey.Equals( hotkey ) )
{
conflict = entry;
}
}
}
if ( conflict != null && !ReferenceEquals( selectedItem, conflict ) )
{
//TODO
//MessageBoxResult result =
// MessageBox.Show( string.Format( Strings.Overwrite_existing_hotkey___0____, conflict ),
// Strings.Warning, MessageBoxButton.YesNo );
//if ( result == MessageBoxResult.No )
//{
// NotifyPropertyChanged( nameof( Hotkey ) );
// return;
//}
}
SelectedItem.Hotkey = hotkey;
NotifyPropertyChanged( nameof( Hotkey ) );
}
private static void SaveMacro( object obj )
{
//Saves whole profile, think of better way
Options.Save( Options.CurrentOptions );
}
private async Task Execute( object obj )
{
if ( !( obj is MacroEntry entry ) )
{
return;
}
_manager.Execute( entry );
await Task.CompletedTask;
}
private static void ShowActiveObjectsWindow( object obj )
{
//TODO UI
//ActiveObjectsWindow window = new ActiveObjectsWindow();
//window.Show();
}
private void OnDisconnectedEvent()
{
_manager.StopAll();
}
private void ClearHotkey( object obj )
{
if ( !( obj is MacroEntry entry ) )
{
return;
}
entry.Hotkey = ShortcutKeys.Default;
this.RaisePropertyChanged( nameof( Hotkey ) );
}
private static async Task InspectObject( object arg )
{
await Commands.InspectObjectAsync();
}
private void NewMacro( object obj )
{
int count = Items.Count;
MacroEntry macro = new MacroEntry { Name = $"Macro-{count + 1}", Macro = string.Empty };
macro.Action = async hks => await Execute( macro );
Items.Add( macro );
}
private void NewMacro( string name, string macroText )
{
MacroEntry macro = new MacroEntry { Name = name, Macro = macroText };
macro.Action = async hks => await Execute( macro );
Items.Add( macro );
SelectedItem = macro;
}
private void RemoveMacro( object obj )
{
if ( obj is MacroEntry entry )
{
Items.Remove( entry );
}
}
private async Task Stop( object obj )
{
if ( !( obj is MacroEntry entry ) )
{
return;
}
entry.Stop();
await Task.CompletedTask;
}
private void ShowCommands( object obj )
{
//TODO UI
//MacrosCommandWindow window = new MacrosCommandWindow { DataContext = new MacrosCommandViewModel( this ) };
//window.ShowDialog();
}
private void Record( object obj )
{
if ( IsRecording )
{
IsRecording = false;
NotifyPropertyChanged( nameof( RecordLabel ) );
return;
}
IsRecording = true;
NotifyPropertyChanged( nameof( RecordLabel ) );
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.Windows.Input;
using ClassicAssist.Shared;
using ClassicAssist.Data;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Misc;
namespace ClassicAssist.UI.ViewModels
{
public class MainWindowViewModel : BaseViewModel
{
private bool _alwaysOnTop;
private ICommand _debugCommand;
//TODO UI
//private DebugWindow _debugWindow;
private string _status = Strings.Ready___;
private string _title = Strings.ProductName;
public MainWindowViewModel()
{
Engine.UpdateWindowTitleEvent += OnUpdateWindowTitleEvent;
}
[OptionsBinding( Property = "AlwaysOnTop" )]
public bool AlwaysOnTop
{
get => _alwaysOnTop;
set => SetProperty( ref _alwaysOnTop, value );
}
public ICommand DebugCommand =>
_debugCommand ?? ( _debugCommand = new RelayCommand( ShowDebugWindow, o => true ) );
public string Status
{
get => _status;
set => SetProperty( ref _status, value );
}
public string Title
{
get => _title;
set => SetProperty( ref _title, value );
}
private void OnUpdateWindowTitleEvent()
{
Title = string.IsNullOrEmpty( Engine.Player?.Name )
? Strings.ProductName
: $"{Engine.Player?.Name} - {( Options.CurrentOptions.ShowProfileNameWindowTitle ? $"({Options.CurrentOptions.Name}) - " : "" )}{Strings.ProductName}";
}
private static void ShowDebugWindow( object obj )
{
Engine.UIInvoker.Invoke( "DebugWindow" );
}
}
}
@@ -0,0 +1,80 @@
using System.IO;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.ViewModels;
using ReactiveUI;
namespace ClassicAssist.Shared.UI.ViewModels
{
public enum NewProfileOption
{
Blank,
Duplicate
}
public class NewProfileViewModel : BaseViewModel
{
private ICommand _changeOptionCommand;
private string _name;
private ICommand _okCommand;
private NewProfileOption _option = NewProfileOption.Duplicate;
// Avalonia only
public ICommand ChangeOptionCommand =>
_changeOptionCommand ?? ( _changeOptionCommand = ReactiveCommand.Create<NewProfileOption>( ChangeOption ) );
public string FileName { get; set; }
public string Name
{
get => _name;
set => SetProperty( ref _name, value );
}
public ICommand OkCommand =>
_okCommand ?? ( _okCommand = new RelayCommand( Ok, o => !string.IsNullOrEmpty( Name ) ) );
public NewProfileOption Option
{
get => _option;
set => SetProperty( ref _option, value );
}
private void Ok( object obj )
{
string profileName = Name?.Trim();
bool valid = profileName?.IndexOfAny( Path.GetInvalidFileNameChars() ) == -1;
if ( valid )
{
FileName = $"{profileName}.json";
if ( Option == NewProfileOption.Duplicate )
{
Options options = Options.CurrentOptions;
options.Name = $"{profileName}.json";
Options.Save( options );
}
else
{
Options.ClearOptions();
Options options = new Options { Name = $"{profileName}.json" };
Options.CurrentOptions = options;
Options.Load( options.Name, options );
Options.Save( options );
}
}
else
{
Engine.MessageBoxProvider.Show( Strings.Profile_name_contains_illegal_characters_ );
}
}
private void ChangeOption( NewProfileOption obj )
{
Option = obj;
}
}
}
@@ -0,0 +1,438 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Windows.Input;
using ClassicAssist.Misc;
using ClassicAssist.Shared;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Models;
using ClassicAssist.UO;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using Microsoft.Scripting.Utils;
namespace ClassicAssist.UI.ViewModels
{
public class ObjectInspectorViewModel : BaseViewModel
{
private ICommand _copyToClipboardCommand;
private ObservableCollection<ObjectInspectorData> _items = new ObservableCollection<ObjectInspectorData>();
private ObjectInspectorData _selectedItem;
public ObjectInspectorViewModel()
{
Items.AddRange( new List<ObjectInspectorData>
{
new ObjectInspectorData { Name = "Name", Value = "Value", Category = "Category" }
} );
}
public ObjectInspectorViewModel( Entity entity )
{
AddEntityProperties( entity );
if ( entity is Mobile mobile )
{
AddMobileProperties( mobile );
}
//AddPublicProperties( entity );
}
public ObjectInspectorViewModel( StaticTile staticTile )
{
AddStaticProperties( staticTile );
}
public ObjectInspectorViewModel( LandTile landTile )
{
AddLandProperties( landTile );
}
public ICommand CopyToClipboardCommand
{
get
{
return _copyToClipboardCommand ?? ( _copyToClipboardCommand =
new RelayCommand( o => CopyToClipboard(), o => _selectedItem != null ) );
}
}
public ObservableCollection<ObjectInspectorData> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ObjectInspectorData SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
private void AddLandProperties( LandTile landTile )
{
AddData( typeof( Entity ), nameof( Entity.Name ), landTile.Name, Strings.Entity );
AddData( "Flags", landTile.Flags.ToString(), Strings.Entity );
AddData( typeof( Entity ), nameof( Entity.ID ), landTile.ID, Strings.Entity, Strings.Graphic );
AddData( "Position", $"{landTile.X}, {landTile.Y}, {landTile.Z}", Strings.Entity );
}
private void AddStaticProperties( StaticTile staticTile )
{
AddData( typeof( Entity ), nameof( Entity.Name ), staticTile.Name, Strings.Entity );
AddData( "Flags", staticTile.Flags.ToString(), Strings.Entity );
AddData( typeof( Entity ), nameof( Entity.ID ), staticTile.ID, Strings.Entity, Strings.Graphic );
AddData( typeof( Entity ), nameof( Entity.Hue ), staticTile.Hue, Strings.Entity, Strings.Color );
AddData( "Position", $"{staticTile.X}, {staticTile.Y}, {staticTile.Z}", Strings.Entity );
AddData( "Weight", staticTile.Weight.ToString(), Strings.Entity );
AddData( "Height", staticTile.Height.ToString(), Strings.Entity );
AddData( "Quality", staticTile.Quality.ToString(), Strings.Entity );
AddData( "Quantity", staticTile.Quantity.ToString(), Strings.Entity );
}
private void AddEntityProperties( Entity entity )
{
AddData( typeof( Entity ), nameof( Entity.Name ), entity.Name, Strings.Entity );
AddData( typeof( Entity ), nameof( Entity.Serial ), entity.Serial, Strings.Entity );
AddData( typeof( Entity ), nameof( Entity.ID ), entity.ID, Strings.Entity, Strings.Graphic );
AddData( typeof( Entity ), nameof( Entity.Hue ), entity.Hue, Strings.Entity, Strings.Color );
AddData( "Position", $"{entity.X}, {entity.Y}, {entity.Z}", Strings.Entity );
}
private void AddMobileProperties( Mobile mobile )
{
AddData( typeof( Mobile ), nameof( Mobile.Name ), mobile.Name, Strings.Mobile );
AddData( "Sex", mobile.Status.HasFlag( MobileStatus.Female ) ? "Female" : "Male", Strings.Mobile );
if ( mobile is PlayerMobile player )
{
AddData( typeof( Mobile ), nameof( Mobile.Hits ), player.Hits, Strings.Mobile );
AddData( typeof( Mobile ), nameof( Mobile.HitsMax ), player.HitsMax, Strings.Mobile, "Max Health" );
}
else
{
float health = mobile.Hits;
float maxHealth = mobile.HitsMax;
float per = health / maxHealth * 100;
AddData( "Hits", ( (uint) per ).ToString() + '%', Strings.Mobile );
}
AddData( typeof( Mobile ), nameof( Mobile.Notoriety ), mobile.Notoriety, Strings.Mobile );
AddData( typeof( Mobile ), nameof( Mobile.Status ), mobile.Status, Strings.Mobile, "Flags" );
#region Equipment Properties
Item[] equipment = GetEquipmentItems( mobile );
if ( equipment == null )
{
return;
}
AddEquipmentProperty( equipment, new[] { 1060448, 1153735 }, new[] { 0, 0 }, "Physical Resist",
Strings.Resistances );
AddEquipmentProperty( equipment, new[] { 1060447, 1153737 }, new[] { 0, 0 }, "Fire Resist",
Strings.Resistances );
AddEquipmentProperty( equipment, new[] { 1060445, 1153739 }, new[] { 0, 0 }, "Cold Resist",
Strings.Resistances );
AddEquipmentProperty( equipment, new[] { 1060449, 1153736 }, new[] { 0, 0 }, "Poison Resist",
Strings.Resistances );
AddEquipmentProperty( equipment, new[] { 1060446, 1153738 }, new[] { 0, 0 }, "Energy Resist",
Strings.Resistances );
AddEquipmentProperty( equipment, 1060413, 0, "Faster Casting", Strings.Magical );
AddEquipmentProperty( equipment, 1060412, 0, "Faster Cast Recovery", Strings.Magical );
AddEquipmentProperty( equipment, 1060434, 0, "Lower Reagent Cost", Strings.Magical );
AddEquipmentProperty( equipment, 1060433, 0, "Lower Mana Cost", Strings.Magical );
AddEquipmentProperty( equipment, 1060483, 0, "Spell Damage Increase", Strings.Magical );
AddEquipmentProperty( equipment, 1060408, 0, "Defense Chance Increase", Strings.Combat );
AddEquipmentProperty( equipment, 1060415, 0, "Hit Chance Increase", Strings.Combat );
AddEquipmentProperty( equipment, 1060401, 0, "Damage Increase", Strings.Combat );
AddEquipmentProperty( equipment, 1060402, 0, "Damage Increase", Strings.Combat );
AddEquipmentProperty( equipment, 1060486, 0, "Swing Speed Increase", Strings.Combat );
AddEquipmentProperty( equipment, 1060485, 0, "Strength Bonus", Strings.Stats );
AddEquipmentProperty( equipment, 1060432, 0, "Intelligence Bonus", Strings.Stats );
AddEquipmentProperty( equipment, 1060409, 0, "Dexterity Bonus", Strings.Stats );
AddEquipmentProperty( equipment, 1060431, 0, "Hit Point Increase", Strings.Stats );
AddEquipmentProperty( equipment, 1060439, 0, "Mana Increase", Strings.Stats );
AddEquipmentProperty( equipment, 1060484, 0, "Stamina Increase", Strings.Stats );
AddEquipmentProperty( equipment, 1060444, 0, "Hit Point Regeneration", Strings.Regeneration );
AddEquipmentProperty( equipment, 1060440, 0, "Mana Regeneration", Strings.Regeneration );
AddEquipmentProperty( equipment, 1060443, 0, "Stamina Regeneration", Strings.Regeneration );
AddEquipmentProperty( equipment, 1060436, 0, "Luck", "Misc" );
AddEquipmentPropertyWithSymbol( equipment, 1153733, 0, 1, "Max Defense Chance Increase",
Strings.Buffs___Penalties );
AddEquipmentPropertyWithSymbol( equipment, 1153735, 1, 2, "Physical Resist", Strings.Buffs___Penalties );
AddEquipmentPropertyWithSymbol( equipment, 1153737, 1, 2, "Fire Resist", Strings.Buffs___Penalties );
AddEquipmentPropertyWithSymbol( equipment, 1153739, 1, 2, "Cold Resist", Strings.Buffs___Penalties );
AddEquipmentPropertyWithSymbol( equipment, 1153736, 1, 2, "Poison Resist", Strings.Buffs___Penalties );
AddEquipmentPropertyWithSymbol( equipment, 1153738, 1, 2, "Energy Resist", Strings.Buffs___Penalties );
#endregion
}
private static Item[] GetEquipmentItems( Mobile mobile )
{
List<Item> items = new List<Item>();
foreach ( Item item in mobile.GetEquippedItems() )
{
items.Add( item );
}
return items.ToArray();
}
private void AddEquipmentProperty( Item[] items, int cliloc, int argumentIndex, string name, string category )
{
AddEquipmentProperty( items, new[] { cliloc }, new[] { argumentIndex }, name, category );
}
private void AddEquipmentProperty( Item[] items, IReadOnlyList<int> clilocs, IReadOnlyList<int> argumentIndexs,
string name, string category )
{
int amount = clilocs.Select( ( t, i ) => CountPropertyList( items.ToArray(), t, argumentIndexs[i] ) ).Sum();
if ( amount > 0 )
{
AddData( new ObjectInspectorData
{
Name = name, Value = amount.ToString(), Category = category, IsExpanded = false
} );
}
}
private void AddEquipmentPropertyWithSymbol( Item[] items, int cliloc, int symbolIndex, int argumentIndex,
string name, string category )
{
int amount = CountPropertyListWithSymbol( items.ToArray(), cliloc, symbolIndex, argumentIndex );
if ( amount != 0 )
{
AddData( new ObjectInspectorData
{
Name = name, Value = amount.ToString(), Category = category, IsExpanded = false
} );
}
}
private static int CountProperty( int serial, int cliloc, int argumentIndex )
{
Item item = Engine.Items.GetItem( serial );
Property[] properties = item?.Properties;
if ( properties == null )
{
return 0;
}
return properties.Where( p => p.Cliloc == cliloc ).Select( p => int.Parse( p.Arguments[argumentIndex] ) )
.FirstOrDefault();
}
private static int CountPropertyList( IEnumerable<Item> items, int cliloc, int argumentIndex )
{
return items.Sum( t => CountProperty( t.Serial, cliloc, argumentIndex ) );
}
private static int CountPropertyListWithSymbol( IReadOnlyList<Item> items, int cliloc, int symbolIndex,
int argumentIndex )
{
int total = 0;
foreach ( Item t in items )
{
int count = CountProperty( t.Serial, cliloc, argumentIndex );
Property[] properties = t.Properties;
if ( properties == null )
{
continue;
}
foreach ( Property p in properties )
{
if ( p.Cliloc != cliloc )
{
continue;
}
string symbol = p.Arguments[symbolIndex];
if ( symbol == "-" )
{
total -= count;
}
else
{
total += count;
}
}
}
return total;
}
private static string GetDisplayFormat( Type type, string propertyName, object value )
{
if ( propertyName == null )
{
return value.ToString();
}
DisplayFormatAttribute attr = type.GetPropertyAttribute<DisplayFormatAttribute>( propertyName );
return attr != null ? attr.ToString( value ) : value?.ToString() ?? string.Empty;
}
private void AddData( Type type, string propertyName, object value, string category, string nameOverride = "",
Action<object> action = null )
{
AddData( new ObjectInspectorData
{
Name = string.IsNullOrEmpty( nameOverride ) ? propertyName : nameOverride,
Value = GetDisplayFormat( type, propertyName, value ),
Category = category,
OnDoubleClick = action
} );
}
private void AddData( string name, string value, string category )
{
AddData( new ObjectInspectorData { Name = name, Value = value, Category = category } );
}
private void AddData( ObjectInspectorData data )
{
_dispatcher.Invoke( () => { Items.Add( data ); } );
}
private void CopyToClipboard()
{
try
{
//TODO
//Clipboard.SetData( DataFormats.Text, _selectedItem.Value );
}
catch ( Exception )
{
// ignored
}
}
private void AddPublicProperties( Entity entity )
{
List<ObjectInspectorData> data = new List<ObjectInspectorData>();
IOrderedEnumerable<PropertyInfo> properties = entity.GetType().GetProperties().OrderBy( p => p.Name );
foreach ( PropertyInfo p in properties )
{
object value = p.GetValue( entity );
string valueString = "null";
if ( value != null )
{
valueString = value.ToString();
}
DisplayFormatAttribute attr = entity.GetType().GetPropertyAttribute<DisplayFormatAttribute>( p.Name );
if ( attr != null )
{
valueString = attr.ToString( value );
}
data.Add( new ObjectInspectorData
{
Name = p.Name,
Value = valueString,
Category = Strings.Public_Properties,
IsExpanded = true,
OnDoubleClick = GetDoubleClickAction( value )
} );
}
Items.AddRange( data );
}
private static Action<object> GetDoubleClickAction( object value )
{
if ( value == null )
{
return null;
}
if ( value is IObjectInspectorDoubleClick )
{
return o => ( (IObjectInspectorDoubleClick) value ).OnDoubleClick( o );
}
if ( value is ItemCollection collection )
{
return o => ShowItemCollection( collection );
}
if ( value is Item item )
{
return o => InspectObject( item.Serial );
}
return null;
}
private static void InspectObject( int serial )
{
Entity entity;
if ( UOMath.IsMobile( serial ) )
{
entity = Engine.Mobiles.GetMobile( serial );
}
else
{
entity = Engine.Items.GetItem( serial );
}
if ( entity == null )
{
return;
}
Engine.UIInvoker.Invoke( "ObjectInspectorWindow", null, typeof( ObjectInspectorViewModel ),
new object[] { entity } );
}
private static void ShowItemCollection( ItemCollection collection )
{
if ( collection == null )
{
}
//TODO
//EntityCollectionViewer window = new EntityCollectionViewer
//{
// DataContext = new EntityCollectionViewerViewModel( collection ),
// Topmost = true
//};
//window.ShowDialog();
}
}
public interface IObjectInspectorDoubleClick
{
void OnDoubleClick( object o );
}
}
@@ -0,0 +1,212 @@
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using ClassicAssist.Data;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Misc;
using ClassicAssist.Shared;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Misc;
using ClassicAssist.UO.Gumps;
using Newtonsoft.Json.Linq;
namespace ClassicAssist.UI.ViewModels
{
public class OptionsTabViewModel : BaseViewModel, ISettingProvider
{
private Options _currentOptions;
private ICommand _setLanguageOverrideCommand;
public Options CurrentOptions
{
get => _currentOptions;
set => SetProperty( ref _currentOptions, value );
}
public ICommand SetLanguageOverrideCommand =>
_setLanguageOverrideCommand ?? ( _setLanguageOverrideCommand = new RelayCommand( SetLanguageOverride ) );
public void Serialize( JObject json )
{
if ( CurrentOptions == null )
{
return;
}
JObject options = new JObject();
JObject useOnce = new JObject { ["Persist"] = CurrentOptions.PersistUseOnce };
if ( CurrentOptions.PersistUseOnce )
{
JArray useOnceItems = new JArray();
foreach ( int serial in ActionCommands.UseOnceList )
{
useOnceItems.Add( serial );
}
useOnce.Add( "Items", useOnceItems );
}
options.Add( "UseOnce", useOnce );
options.Add( "UseDeathScreenWhilstHidden", CurrentOptions.UseDeathScreenWhilstHidden );
options.Add( "CommandPrefix", CurrentOptions.CommandPrefix );
options.Add( "RangeCheckLastTarget", CurrentOptions.RangeCheckLastTarget );
options.Add( "RangeCheckLastTargetAmount", CurrentOptions.RangeCheckLastTargetAmount );
options.Add( "UseExperimentalFizzleDetection", CurrentOptions.UseExperimentalFizzleDetection );
options.Add( "UseObjectQueue", CurrentOptions.UseObjectQueue );
options.Add( "UseObjectQueueAmount", CurrentOptions.UseObjectQueueAmount );
options.Add( "QueueLastTarget", CurrentOptions.QueueLastTarget );
options.Add( "MaxTargetQueueLength", CurrentOptions.MaxTargetQueueLength );
options.Add( "SmartTargetOption", CurrentOptions.SmartTargetOption.ToString() );
options.Add( "LimitMouseWheelTrigger", CurrentOptions.LimitMouseWheelTrigger );
options.Add( "LimitMouseWheelTriggerMS", CurrentOptions.LimitMouseWheelTriggerMS );
options.Add( "AutoAcceptPartyInvite", CurrentOptions.AutoAcceptPartyInvite );
options.Add( "AutoAcceptPartyOnlyFromFriends", CurrentOptions.AutoAcceptPartyOnlyFromFriends );
options.Add( "PreventTargetingInnocentsInGuardzone", CurrentOptions.PreventTargetingInnocentsInGuardzone );
options.Add( "PreventAttackingInnocentsInGuardzone", CurrentOptions.PreventAttackingInnocentsInGuardzone );
options.Add( "LastTargetMessage", CurrentOptions.LastTargetMessage );
options.Add( "FriendTargetMessage", CurrentOptions.FriendTargetMessage );
options.Add( "EnemyTargetMessage", CurrentOptions.EnemyTargetMessage );
options.Add( "DefaultMacroQuietMode", CurrentOptions.DefaultMacroQuietMode );
options.Add( "GetFriendEnemyUsesIgnoreList", CurrentOptions.GetFriendEnemyUsesIgnoreList );
options.Add( "AbilitiesGump", CurrentOptions.AbilitiesGump );
options.Add( "AbilitiesGumpX", CurrentOptions.AbilitiesGumpX );
options.Add( "AbilitiesGumpY", CurrentOptions.AbilitiesGumpY );
options.Add( "ShowProfileNameWindowTitle", CurrentOptions.ShowProfileNameWindowTitle );
options.Add( "SortMacrosAlphabetical", CurrentOptions.SortMacrosAlphabetical );
options.Add( "ShowResurrectionWaypoints", CurrentOptions.ShowResurrectionWaypoints );
options.Add( "RehueFriends", CurrentOptions.RehueFriends );
options.Add( "RehueFriendsHue", CurrentOptions.RehueFriendsHue );
options.Add( "CheckHandsPotions", CurrentOptions.CheckHandsPotions );
options.Add( "MacrosGump", CurrentOptions.MacrosGump );
options.Add( "MacrosGumpX", CurrentOptions.MacrosGumpX );
options.Add( "MacrosGumpY", CurrentOptions.MacrosGumpY );
json?.Add( "Options", options );
}
public void Deserialize( JObject json, Options options )
{
CurrentOptions = options;
CurrentOptions.PropertyChanged += OnOptionsChanged;
ActionCommands.UseOnceList.Clear();
JToken config = json?["Options"];
if ( config?["UseOnce"] != null )
{
CurrentOptions.PersistUseOnce = config["UseOnce"]["Persist"]?.ToObject<bool>() ?? false;
if ( CurrentOptions.PersistUseOnce )
{
foreach ( JToken token in config["UseOnce"]["Items"] )
{
ActionCommands.UseOnceList.Add( token.ToObject<int>() );
}
}
}
CurrentOptions.UseDeathScreenWhilstHidden =
config?["UseDeathScreenWhilstHidden"]?.ToObject<bool>() ?? false;
CurrentOptions.CommandPrefix = config?["CommandPrefix"]?.ToObject<char>() ?? '=';
CurrentOptions.RangeCheckLastTarget = config?["RangeCheckLastTarget"]?.ToObject<bool>() ?? false;
CurrentOptions.RangeCheckLastTargetAmount = config?["RangeCheckLastTargetAmount"]?.ToObject<int>() ?? 11;
CurrentOptions.UseExperimentalFizzleDetection =
config?["UseExperimentalFizzleDetection"]?.ToObject<bool>() ?? false;
CurrentOptions.UseObjectQueue = config?["UseObjectQueue"]?.ToObject<bool>() ?? false;
CurrentOptions.UseObjectQueueAmount = config?["UseObjectQueueAmount"]?.ToObject<int>() ?? 5;
CurrentOptions.QueueLastTarget = config?["QueueLastTarget"]?.ToObject<bool>() ?? false;
CurrentOptions.MaxTargetQueueLength = config?["MaxTargetQueueLength"]?.ToObject<int>() ?? 1;
CurrentOptions.SmartTargetOption =
config?["SmartTargetOption"]?.ToObject<SmartTargetOption>() ?? SmartTargetOption.None;
CurrentOptions.LimitMouseWheelTrigger = config?["LimitMouseWheelTrigger"]?.ToObject<bool>() ?? false;
CurrentOptions.LimitMouseWheelTriggerMS = config?["LimitMouseWheelTriggerMS"]?.ToObject<int>() ?? 25;
CurrentOptions.AutoAcceptPartyInvite = config?["AutoAcceptPartyInvite"]?.ToObject<bool>() ?? false;
CurrentOptions.AutoAcceptPartyOnlyFromFriends =
config?["AutoAcceptPartyOnlyFromFriends"]?.ToObject<bool>() ?? false;
CurrentOptions.PreventTargetingInnocentsInGuardzone =
config?["PreventTargetingInnocentsInGuardzone"]?.ToObject<bool>() ?? false;
CurrentOptions.PreventAttackingInnocentsInGuardzone =
config?["PreventAttackingInnocentsInGuardzone"]?.ToObject<bool>() ?? false;
CurrentOptions.LastTargetMessage = config?["LastTargetMessage"]?.ToObject<string>() ?? "[Last Target]";
CurrentOptions.FriendTargetMessage = config?["FriendTargetMessage"]?.ToObject<string>() ?? "[Friend]";
CurrentOptions.EnemyTargetMessage = config?["EnemyTargetMessage"]?.ToObject<string>() ?? "[Enemy]";
CurrentOptions.DefaultMacroQuietMode = config?["DefaultMacroQuietMode"]?.ToObject<bool>() ?? false;
CurrentOptions.GetFriendEnemyUsesIgnoreList =
config?["GetFriendEnemyUsesIgnoreList"]?.ToObject<bool>() ?? false;
CurrentOptions.AbilitiesGump = config?["AbilitiesGump"]?.ToObject<bool>() ?? true;
CurrentOptions.AbilitiesGumpX = config?["AbilitiesGumpX"]?.ToObject<int>() ?? 100;
CurrentOptions.AbilitiesGumpY = config?["AbilitiesGumpY"]?.ToObject<int>() ?? 100;
CurrentOptions.ShowProfileNameWindowTitle =
config?["ShowProfileNameWindowTitle"]?.ToObject<bool>() ?? false;
CurrentOptions.SortMacrosAlphabetical = config?["SortMacrosAlphabetical"]?.ToObject<bool>() ?? false;
CurrentOptions.ShowResurrectionWaypoints = config?["ShowResurrectionWaypoints"]?.ToObject<bool>() ?? true;
CurrentOptions.RehueFriends = config?["RehueFriends"]?.ToObject<bool>() ?? false;
CurrentOptions.RehueFriendsHue = config?["RehueFriendsHue"]?.ToObject<int>() ?? 35;
CurrentOptions.CheckHandsPotions = config?["CheckHandsPotions"]?.ToObject<bool>() ?? false;
CurrentOptions.MacrosGump = config?["MacrosGump"]?.ToObject<bool>() ?? true;
CurrentOptions.MacrosGumpX = config?["MacrosGumpX"]?.ToObject<int>() ?? 100;
CurrentOptions.MacrosGumpY = config?["MacrosGumpY"]?.ToObject<int>() ?? 100;
if ( CurrentOptions.AbilitiesGumpX < 0 )
{
CurrentOptions.AbilitiesGumpX = 100;
}
if ( CurrentOptions.AbilitiesGumpY < 0 )
{
CurrentOptions.AbilitiesGumpY = 100;
}
if ( CurrentOptions.MacrosGump )
{
MacrosGump.Initialize();
}
}
// Replay CurrentOptions changes onto Options.CurrentOptions
// TODO: Fix Options
private void OnOptionsChanged( object sender, PropertyChangedEventArgs args )
{
if ( args.PropertyName == "Name" )
{
return;
}
object val = CurrentOptions.GetType().GetProperty( args.PropertyName )?.GetValue( CurrentOptions );
if ( val == null )
{
return;
}
object oldVal = Options.CurrentOptions.GetType().GetProperty( args.PropertyName )
?.GetValue( Options.CurrentOptions );
if ( !val.Equals( oldVal ) )
{
Options.CurrentOptions.GetType().GetProperty( args.PropertyName )
?.SetValue( Options.CurrentOptions, val );
}
}
private static async void SetLanguageOverride( object obj )
{
if ( !( obj is Language language ) )
{
return;
}
AssistantOptions.LanguageOverride = language;
await Engine.MessageBoxProvider.Show( Strings.Restart_game_for_changes_to_take_effect___,
Strings.Restart_game_for_changes_to_take_effect___ );
}
}
}
@@ -0,0 +1,87 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared;
using ClassicAssist.Misc;
using ClassicAssist.UO.Gumps;
namespace ClassicAssist.UI.ViewModels
{
public class RepositionableGumpViewModel : BaseViewModel
{
private readonly RepositionableGump _gump;
private int _horizontalMax;
private int _verticalMax;
private int _x;
private int _y;
public RepositionableGumpViewModel()
{
}
public RepositionableGumpViewModel( RepositionableGump gump, int initialX, int initialY )
{
_gump = gump;
X = initialX;
Y = initialY;
HorizontalMax = 3840;
VerticalMax = 2160;
if ( !NativeMethods.GetWindowRect( Engine.WindowHandle, out NativeMethods.RECT rect ) )
{
return;
}
HorizontalMax = rect.Right - rect.Left;
VerticalMax = rect.Bottom - rect.Top;
}
public int HorizontalMax
{
get => _horizontalMax;
set => SetProperty( ref _horizontalMax, value );
}
public int VerticalMax
{
get => _verticalMax;
set => SetProperty( ref _verticalMax, value );
}
public int X
{
get => _x;
set
{
SetProperty( ref _x, value );
_gump?.SetPosition( _x, _y );
}
}
public int Y
{
get => _y;
set
{
SetProperty( ref _y, value );
_gump?.SetPosition( _x, _y );
}
}
}
}
@@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using ClassicAssist.Shared;
using ClassicAssist.Data;
using ClassicAssist.Data.Hotkeys;
using ClassicAssist.Data.Hotkeys.Commands;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Data.Skills;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UI.Misc;
using ClassicAssist.UO;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network;
using ClassicAssist.UO.Network.Packets;
using Newtonsoft.Json.Linq;
namespace ClassicAssist.UI.ViewModels
{
public class SkillsTabViewModel : BaseViewModel, ISettingProvider
{
private HotkeyCommand _hotkeyCategory;
private ObservableCollectionEx<SkillEntry> _items = new ObservableCollectionEx<SkillEntry>();
private ICommand _resetDeltasCommand;
private SkillEntry _selectedItem;
private ICommand _setAllSkillLocksCommand;
private ICommand _setSkillLocksCommand;
private float _totalBase;
private ICommand _useSkillCommand;
public SkillsTabViewModel()
{
Items.CollectionChanged += ( sender, args ) => { UpdateTotalBase(); };
IncomingPacketHandlers.SkillUpdatedEvent += OnSkillUpdatedEvent;
IncomingPacketHandlers.SkillsListEvent += OnSkillsListEvent;
if ( Engine.Player != null && Engine.Connected )
{
Shared.UO.Commands.MobileQuery( Engine.Player.Serial, MobileQueryType.SkillsRequest );
}
SkillManager manager = SkillManager.GetInstance();
manager.Items = Items;
}
public ObservableCollectionEx<SkillEntry> Items
{
get => _items;
set => SetProperty( ref _items, value );
}
public ICommand ResetDeltasCommand =>
_resetDeltasCommand ?? ( _resetDeltasCommand = new RelayCommand( ResetDeltas, o => true ) );
public SkillEntry SelectedItem
{
get => _selectedItem;
set => SetProperty( ref _selectedItem, value );
}
public ICommand SetAllSkillLocksCommand =>
_setAllSkillLocksCommand ?? ( _setAllSkillLocksCommand = new RelayCommand( SetAllSkillLocks, o => true ) );
public ICommand SetSkillLocksCommand =>
_setSkillLocksCommand ?? ( _setSkillLocksCommand = new RelayCommand( SetSkillLocks, o => true ) );
public float TotalBase
{
get => _totalBase;
set => SetProperty( ref _totalBase, value );
}
public ICommand UseSkillCommand =>
_useSkillCommand ?? ( _useSkillCommand =
new RelayCommand( UseSkill, o => SelectedItem?.Skill.Invokable ?? false ) );
public void Serialize( JObject json )
{
JArray skills = new JArray();
if ( _hotkeyCategory?.Children == null )
{
return;
}
foreach ( HotkeyEntry hks in _hotkeyCategory.Children )
{
if ( Equals( hks.Hotkey, ShortcutKeys.Default ) )
{
continue;
}
skills.Add( new JObject
{
{ "Name", hks.Name }, { "Keys", hks.Hotkey.ToJObject() }, { "PassToUO", hks.PassToUO }
} );
}
json.Add( "Skills", skills );
}
public void Deserialize( JObject json, Options options )
{
HotkeyManager hotkey = HotkeyManager.GetInstance();
if ( Skills.GetSkillsArray() == null )
{
return;
}
IOrderedEnumerable<SkillData> skills =
Skills.GetSkillsArray().Where( s => s.Invokable ).OrderBy( s => s.Name );
ObservableCollectionEx<HotkeyEntry> hotkeyEntries = new ObservableCollectionEx<HotkeyEntry>();
foreach ( SkillData skill in skills )
{
hotkeyEntries.Add( new HotkeyCommand
{
Action = hks => SkillCommands.UseSkill( skill.Name ), Name = skill.Name
} );
}
if ( json["Skills"] != null )
{
foreach ( HotkeyEntry hke in hotkeyEntries )
{
JToken token = json["Skills"].FirstOrDefault( jo => jo["Name"].ToObject<string>() == hke.Name );
if ( token == null )
{
continue;
}
hke.Hotkey = new ShortcutKeys( token["Keys"] );
hke.PassToUO = token["PassToUO"].ToObject<bool>();
}
}
_hotkeyCategory = hotkey.Items.FirstOrDefault( hk => hk.IsCategory && hk.Name == Strings.Skills ) ??
new HotkeyCommand { Name = Strings.Skills, IsCategory = true };
_hotkeyCategory.Children = hotkeyEntries;
hotkey.AddCategory( _hotkeyCategory );
}
private void ResetDeltas( object obj )
{
foreach ( SkillEntry skillEntry in Items )
{
skillEntry.Delta = 0;
}
}
private void SetSkillLocks( object obj )
{
LockStatus lockStatus = (LockStatus) obj;
if ( SelectedItem == null )
{
return;
}
Shared.UO.Commands.ChangeSkillLock( SelectedItem, lockStatus );
}
private void SetAllSkillLocks( object obj )
{
LockStatus lockStatus = (LockStatus) (int) obj;
IEnumerable<SkillEntry> skillsToSet = Items.Where( i => i.LockStatus != lockStatus );
foreach ( SkillEntry skillEntry in skillsToSet )
{
Shared.UO.Commands.ChangeSkillLock( skillEntry, lockStatus, false );
}
Shared.UO.Commands.MobileQuery( Engine.Player.Serial, MobileQueryType.SkillsRequest );
}
private void UpdateTotalBase()
{
TotalBase = Items.Sum( se => se.Base );
}
private void OnSkillsListEvent( SkillInfo[] skills )
{
_dispatcher.Invoke( () => { Items.Clear(); } );
foreach ( SkillInfo si in skills )
{
Skill skill = new Skill
{
ID = si.ID, Name = Skills.GetSkillName( si.ID ), Invokable = Skills.IsInvokable( si.ID )
};
SkillEntry se = new SkillEntry
{
Skill = skill,
Value = si.Value,
Base = si.BaseValue,
Cap = si.SkillCap,
LockStatus = si.LockStatus
};
_dispatcher.Invoke( () => { Items.Add( se ); } );
}
}
private void UseSkill( object obj )
{
if ( SelectedItem == null )
{
return;
}
if ( SelectedItem.Skill.Invokable )
{
Engine.SendPacketToServer( new UseSkill( SelectedItem.Skill.ID ) );
}
}
private void OnSkillUpdatedEvent( int skillID, float value, float baseValue, LockStatus lockStatus,
float skillCap )
{
SkillEntry entry = _items.FirstOrDefault( se => se.Skill.ID == skillID );
if ( entry == null )
{
return;
}
_dispatcher.Invoke( () =>
{
entry.Delta += baseValue - entry.Base;
entry.Value = value;
entry.Base = baseValue;
entry.Cap = skillCap;
entry.LockStatus = lockStatus;
} );
}
}
}