first commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
#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.Linq;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Bards Music", DefaultEnabled = true )]
|
||||
public class BardsMusicFilter : DynamicFilterEntry
|
||||
{
|
||||
private static readonly int[] _bardsMusic = { 0x38, 0x39, 0x43, 0x44, 0x45, 0x46, 0x4C, 0x4D, 0x52, 0x53 };
|
||||
private static bool _isEnabled;
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
_isEnabled = enabled;
|
||||
}
|
||||
|
||||
public override bool CheckPacket( ref byte[] packet, ref int length, PacketDirection direction )
|
||||
{
|
||||
if ( packet == null || !_isEnabled )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( packet[0] != 0x54 || direction != PacketDirection.Incoming )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int soundId = ( packet[2] << 8 ) | packet[3];
|
||||
|
||||
return _bardsMusic.Contains( soundId );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.UO.Data;
|
||||
using ClassicAssist.UO.Network.Packets;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Cliloc Filter", DefaultEnabled = false )]
|
||||
public class ClilocFilter : FilterEntry, IConfigurableFilter
|
||||
{
|
||||
public static Dictionary<int, string> Filters { get; set; } = new Dictionary<int, string>();
|
||||
|
||||
public static bool IsEnabled { get; set; }
|
||||
|
||||
public void Configure()
|
||||
{
|
||||
//TODO
|
||||
//ClilocFilterConfigureWindow window =
|
||||
// new ClilocFilterConfigureWindow { Topmost = Options.CurrentOptions.AlwaysOnTop };
|
||||
|
||||
//window.ShowDialog();
|
||||
}
|
||||
|
||||
public void Deserialize( JToken token )
|
||||
{
|
||||
if ( token?["Filters"] == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( JToken filterToken in token["Filters"] )
|
||||
{
|
||||
int key = filterToken["Key"].ToObject<int>();
|
||||
string val = filterToken["Value"]?.ToObject<string>();
|
||||
|
||||
if ( !Filters.ContainsKey( key ) )
|
||||
{
|
||||
Filters.Add( key, val );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JObject Serialize()
|
||||
{
|
||||
JArray itemsArray = new JArray();
|
||||
|
||||
foreach ( KeyValuePair<int, string> kvp in Filters )
|
||||
{
|
||||
itemsArray.Add( new JObject { { "Key", kvp.Key }, { "Value", kvp.Value } } );
|
||||
}
|
||||
|
||||
return new JObject { { "Filters", itemsArray } };
|
||||
}
|
||||
|
||||
public void ResetOptions()
|
||||
{
|
||||
Filters.Clear();
|
||||
}
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
IsEnabled = enabled;
|
||||
}
|
||||
|
||||
public static bool CheckMessage( JournalEntry journalEntry )
|
||||
{
|
||||
if ( !IsEnabled || journalEntry.Cliloc == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Filters.All( f => f.Key != journalEntry.Cliloc ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyValuePair<int, string> match = Filters.FirstOrDefault( f => f.Key == journalEntry.Cliloc );
|
||||
|
||||
Engine.SendPacketToClient( new UnicodeText( journalEntry.Serial, journalEntry.ID, journalEntry.SpeechType,
|
||||
journalEntry.SpeechHue, journalEntry.SpeechFont, Strings.UO_LOCALE, journalEntry.Name, match.Value ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckMessageAffix( JournalEntry journalEntry, MessageAffixType affixType, string affix )
|
||||
{
|
||||
if ( !IsEnabled || journalEntry.Cliloc == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Filters.All( f => f.Key != journalEntry.Cliloc ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyValuePair<int, string> match = Filters.FirstOrDefault( f => f.Key == journalEntry.Cliloc );
|
||||
|
||||
string text = affixType.HasFlag( MessageAffixType.Prepend )
|
||||
? $"{affix}{match.Value}"
|
||||
: $"{match.Value}{affix}";
|
||||
|
||||
Engine.SendPacketToClient( new UnicodeText( journalEntry.Serial, journalEntry.ID, JournalSpeech.Say,
|
||||
journalEntry.SpeechHue, journalEntry.SpeechFont, Strings.UO_LOCALE, journalEntry.Name, text ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#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 ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
public abstract class DynamicFilterEntry : FilterEntry
|
||||
{
|
||||
protected DynamicFilterEntry()
|
||||
{
|
||||
Filters.Add( this );
|
||||
}
|
||||
|
||||
public static List<DynamicFilterEntry> Filters { get; set; } = new List<DynamicFilterEntry>();
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool CheckPacket( ref byte[] packet, ref int length, PacketDirection direction )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
public abstract class FilterEntry : INotifyPropertyChanged
|
||||
{
|
||||
private bool _enabled;
|
||||
private bool _isConfigurable;
|
||||
private string _name;
|
||||
|
||||
protected FilterEntry()
|
||||
{
|
||||
Action = OnChanged;
|
||||
|
||||
FilterOptionsAttribute a =
|
||||
(FilterOptionsAttribute) Attribute.GetCustomAttribute( GetType(), typeof( FilterOptionsAttribute ) );
|
||||
|
||||
if ( a == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string resourceName = Strings.ResourceManager.GetString( a.Name );
|
||||
|
||||
if ( string.IsNullOrEmpty( resourceName ) )
|
||||
{
|
||||
throw new InvalidOperationException( $"No localized text for filter: {a.Name}" );
|
||||
}
|
||||
|
||||
Name = string.IsNullOrEmpty( resourceName ) ? a.Name : resourceName;
|
||||
Enabled = a.DefaultEnabled;
|
||||
IsConfigurable = typeof( IConfigurableFilter ).IsAssignableFrom( GetType() );
|
||||
}
|
||||
|
||||
public Action<bool> Action { get; set; }
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _enabled, value );
|
||||
Action?.Invoke( value );
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConfigurable
|
||||
{
|
||||
get => _isConfigurable;
|
||||
set => SetProperty( ref _isConfigurable, value );
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetProperty( ref _name, value );
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnChanged( bool enabled )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = null )
|
||||
{
|
||||
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
|
||||
}
|
||||
|
||||
// ReSharper disable once RedundantAssignment
|
||||
public void SetProperty<T>( ref T field, T value, [CallerMemberName] string propertyName = null )
|
||||
{
|
||||
field = value;
|
||||
OnPropertyChanged( propertyName );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
public class FilterOptionsAttribute : Attribute
|
||||
{
|
||||
public bool DefaultEnabled { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
public interface IConfigurableFilter
|
||||
{
|
||||
void Configure();
|
||||
void Deserialize( JToken token );
|
||||
JObject Serialize();
|
||||
void ResetOptions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Light Level", DefaultEnabled = true )]
|
||||
public class LightLevelFilter : DynamicFilterEntry
|
||||
{
|
||||
public override bool CheckPacket( ref byte[] packet, ref int length, PacketDirection direction )
|
||||
{
|
||||
if ( packet[0] == 0x4E && Enabled )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( packet[0] != 0x4F || !Enabled )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
packet[1] = (byte) Options.CurrentOptions.LightLevel;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ClassicAssist.UO.Data;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Repeated Messages", DefaultEnabled = false )]
|
||||
public class RepeatedMessagesFilter : FilterEntry, IConfigurableFilter
|
||||
{
|
||||
public static MessageFilterOptions FilterOptions { get; set; } = new MessageFilterOptions();
|
||||
|
||||
public static bool IsEnabled { get; set; }
|
||||
private static List<RepeatedMessageEntry> RepeatedMessageEntries { get; } = new List<RepeatedMessageEntry>();
|
||||
|
||||
public void Configure()
|
||||
{
|
||||
//TODO
|
||||
//RepeatedMessagesFilterConfigureWindow window = new RepeatedMessagesFilterConfigureWindow( FilterOptions );
|
||||
//window.ShowDialog();
|
||||
}
|
||||
|
||||
public void Deserialize( JToken token )
|
||||
{
|
||||
if ( token == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FilterOptions = new MessageFilterOptions
|
||||
{
|
||||
SendToJournal = token["SendToJournal"]?.ToObject<bool>() ?? false,
|
||||
MessageLimit = token["MessageLimit"]?.ToObject<int>() ?? 5,
|
||||
TimeLimit = token["TimeLimit"]?.ToObject<int>() ?? 5,
|
||||
BlockedTime = token["BlockedTime"]?.ToObject<int>() ?? 5
|
||||
};
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
FilterOptions = new MessageFilterOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public JObject Serialize()
|
||||
{
|
||||
return new JObject
|
||||
{
|
||||
{ "SendToJournal", FilterOptions.SendToJournal },
|
||||
{ "MessageLimit", FilterOptions.MessageLimit },
|
||||
{ "TimeLimit", FilterOptions.TimeLimit },
|
||||
{ "BlockedTime", FilterOptions.BlockedTime }
|
||||
};
|
||||
}
|
||||
|
||||
public void ResetOptions()
|
||||
{
|
||||
FilterOptions = new MessageFilterOptions();
|
||||
}
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
IsEnabled = enabled;
|
||||
}
|
||||
|
||||
public static bool CheckMessage( JournalEntry journalEntry )
|
||||
{
|
||||
if ( !IsEnabled )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( journalEntry.SpeechType != JournalSpeech.System &&
|
||||
( journalEntry.Name != "System" || journalEntry.Serial != -1 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( FilterOptions.MessageLimit == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RepeatedMessageEntry entry = RepeatedMessageEntries.FirstOrDefault( e => e.Message == journalEntry.Text );
|
||||
|
||||
if ( entry != null && entry.Blocked && entry.Expires < DateTime.Now )
|
||||
{
|
||||
RepeatedMessageEntries.Remove( entry );
|
||||
}
|
||||
|
||||
if ( entry != null && entry.Blocked && entry.Expires > DateTime.Now )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( RepeatedMessageEntries.All( e => e.Message != journalEntry.Text ) )
|
||||
{
|
||||
RepeatedMessageEntries.Add( new RepeatedMessageEntry
|
||||
{
|
||||
FirstReceived = DateTime.Now,
|
||||
LastReceived = DateTime.Now,
|
||||
Count = 1,
|
||||
Message = journalEntry.Text
|
||||
} );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
entry = RepeatedMessageEntries.FirstOrDefault( e => e.Message == journalEntry.Text );
|
||||
|
||||
if ( entry == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( entry.LastReceived < DateTime.Now - TimeSpan.FromSeconds( FilterOptions.TimeLimit ) )
|
||||
{
|
||||
RepeatedMessageEntries.Remove( entry );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( entry.Count < FilterOptions.MessageLimit )
|
||||
{
|
||||
entry.Count++;
|
||||
entry.LastReceived = DateTime.Now;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Options.CurrentOptions.Debug )
|
||||
{
|
||||
Shared.UO.Commands.SystemMessage( $"Filtering message: {journalEntry.Text}" );
|
||||
}
|
||||
|
||||
entry.Blocked = true;
|
||||
entry.Expires = DateTime.Now + TimeSpan.FromSeconds( FilterOptions.BlockedTime );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal class RepeatedMessageEntry
|
||||
{
|
||||
public bool Blocked { get; set; }
|
||||
public int Count { get; set; }
|
||||
public DateTime Expires { get; set; } = DateTime.Now;
|
||||
public DateTime FirstReceived { get; set; }
|
||||
public DateTime LastReceived { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public class MessageFilterOptions
|
||||
{
|
||||
public int BlockedTime { get; set; } = 5;
|
||||
public int MessageLimit { get; set; } = 5;
|
||||
public bool SendToJournal { get; set; }
|
||||
public int TimeLimit { get; set; } = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UO.Data;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Seasons", DefaultEnabled = false )]
|
||||
public class SeasonFilter : FilterEntry
|
||||
{
|
||||
private readonly byte[] _desolationSeason = { 0xBC, 0x04, 0x00 };
|
||||
private readonly byte[] _standardSeason = { 0xBC, 0x00, 0x00 };
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
PacketFilterInfo pfi = new PacketFilterInfo( 0xBC, OnSeasonChange );
|
||||
|
||||
if ( enabled )
|
||||
{
|
||||
Engine.AddReceiveFilter( pfi );
|
||||
|
||||
if ( Engine.Player != null && Engine.Player.Map == Map.Felucca )
|
||||
{
|
||||
Engine.SendPacketToClient( _desolationSeason, _desolationSeason.Length );
|
||||
return;
|
||||
}
|
||||
|
||||
Engine.SendPacketToClient( _standardSeason, _standardSeason.Length );
|
||||
}
|
||||
else
|
||||
{
|
||||
Engine.RemoveReceiveFilter( pfi );
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSeasonChange( byte[] arg1, PacketFilterInfo arg2 )
|
||||
{
|
||||
if ( Engine.Player != null && Engine.Player.Map == Map.Felucca )
|
||||
{
|
||||
Engine.SendPacketToClient( _desolationSeason, _desolationSeason.Length );
|
||||
return;
|
||||
}
|
||||
|
||||
Engine.SendPacketToClient( _standardSeason, _standardSeason.Length );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.Data.Filters
|
||||
{
|
||||
[FilterOptions( Name = "Weather", DefaultEnabled = true )]
|
||||
public class WeatherFilter : FilterEntry
|
||||
{
|
||||
private static void OnWeatherPacket( byte[] arg1, PacketFilterInfo arg2 )
|
||||
{
|
||||
byte[] packet = { 0x65, 0xFF, 0x00, 0x00 };
|
||||
|
||||
Engine.SendPacketToClient( packet, packet.Length );
|
||||
}
|
||||
|
||||
protected override void OnChanged( bool enabled )
|
||||
{
|
||||
PacketFilterInfo pfi = new PacketFilterInfo( 0x65, null, OnWeatherPacket );
|
||||
|
||||
if ( enabled )
|
||||
{
|
||||
Engine.AddReceiveFilter( pfi );
|
||||
}
|
||||
else
|
||||
{
|
||||
Engine.RemoveReceiveFilter( pfi );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user