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,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 );
}
}
}
}