Skip to content

Commit

Permalink
feat: Change offset manager to use better functions that all are in o…
Browse files Browse the repository at this point in the history
…ffset attribute now as well a centralized patternfinder through proxy
  • Loading branch information
nt153133 committed Jun 9, 2024
1 parent 61a1b49 commit 71f8ee8
Show file tree
Hide file tree
Showing 8 changed files with 1,026 additions and 611 deletions.
359 changes: 336 additions & 23 deletions Memory/Attributes/OffsetAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,368 @@ Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You should have received a copy of the license along with this
work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
Orginal work done by zzi, contibutions by Omninewb, Freiheit, and mastahg
Original work done by zzi, contibutions by Omninewb, Freiheit, and mastahg
*/

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using ff14bot;
using ff14bot.Enums;
using GreyMagic;
using LlamaLibrary.Memory.PatternFinders;

namespace LlamaLibrary.Memory.Attributes
// ReSharper disable InvertIf
// ReSharper disable SimplifyLinqExpressionUseMinByAndMaxBy

namespace LlamaLibrary.Memory.Attributes;

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class OffsetAttribute : Attribute
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class OffsetAttribute : Attribute
public readonly string Pattern;
public readonly string PatternCN;
public readonly string PatternDawntrail;
public bool IgnoreCache;
public int ExpectedValue = 0;
public virtual int Priority => 0;
public virtual bool IsValid(ForceClientMode clientMode) => true;
protected static readonly Language Language
#if RB_CN
= Language.Chinese;
#else
= Language.Eng;
#endif

public OffsetAttribute(string pattern, bool ignoreCache = false, int expectedValue = 0)
{
Pattern = pattern;
if (!Pattern.StartsWith("Search "))
{
Pattern = "Search " + Pattern;
}

PatternCN = Pattern;
PatternDawntrail = Pattern;
IgnoreCache = ignoreCache;
ExpectedValue = expectedValue;
}

protected OffsetAttribute(string pattern, string cnPattern, bool ignoreCache = false, int expectedValue = 0)
{
public bool IgnoreCache;
public string Pattern = "";
public string PatternCN = "";
PatternCN = cnPattern;
if (!PatternCN.StartsWith("Search "))
{
PatternCN = "Search " + PatternCN;
}

Pattern = pattern;

if (string.IsNullOrEmpty(Pattern))
{
Pattern = cnPattern;
}

PatternDawntrail = Pattern;

IgnoreCache = ignoreCache;
ExpectedValue = expectedValue;
}

protected OffsetAttribute(string pattern, string cnPattern, string dawntrailPattern, bool ignoreCache = false, int expectedValue = 0)
{
PatternCN = cnPattern;
if (!string.IsNullOrEmpty(cnPattern) && !PatternCN.StartsWith("Search "))
{
PatternCN = "Search " + PatternCN;
}

PatternDawntrail = dawntrailPattern;
if (!string.IsNullOrEmpty(dawntrailPattern) && !PatternDawntrail.StartsWith("Search "))
{
PatternDawntrail = "Search " + PatternDawntrail;
}

Pattern = pattern;

if (string.IsNullOrEmpty(Pattern))
{
Pattern = !string.IsNullOrEmpty(dawntrailPattern) ? PatternDawntrail : PatternCN;
}

if (!string.IsNullOrEmpty(Pattern) && !Pattern.StartsWith("Search "))
{
Pattern = "Search " + Pattern;
}

IgnoreCache = ignoreCache;
ExpectedValue = expectedValue;
}

public OffsetAttribute(string pattern, bool ignoreCache = false, int expectedValue = 0)
public string GetPattern(ForceClientMode forceClientMode = ForceClientMode.None)
{
return forceClientMode switch
{
Pattern = pattern;
if (!Pattern.StartsWith("Search "))
ForceClientMode.CN => PatternCN,
ForceClientMode.Dawntrail => PatternDawntrail,
_ => Language switch
{
Pattern = "Search " + Pattern;
Language.Chn => PatternCN,
_ => Pattern
}
};
}
}

public static class OffsetAttributeExtensions
{
public static readonly ConcurrentDictionary<string, OffsetAttribute> AttributeCache = new ConcurrentDictionary<string, OffsetAttribute>();

public static string GetPattern(this MemberInfo property, ForceClientMode forceClientMode = ForceClientMode.None)
{
return property.OffsetAttribute(forceClientMode)?.GetPattern(forceClientMode) ?? string.Empty;
}

public static bool IgnoreCache(this MemberInfo property, ForceClientMode forceClientMode = ForceClientMode.None)
{
return property.OffsetAttribute(forceClientMode)?.IgnoreCache ?? false;
}

if (PatternCN == "")
public static OffsetAttribute? OffsetAttribute(this MemberInfo property, ForceClientMode forceClientMode)
{
if (!AttributeCache.TryGetValue(property.MemberName(), out var attribute))
{
attribute = property.GetCustomAttributes<OffsetAttribute>(true).Where(i => i.IsValid(forceClientMode)).OrderByDescending(x => x.Priority).FirstOrDefault();
if (attribute != null)
{
//ff14bot.Helpers.Logging.Write($"Found attribute {attribute.GetType().Name} for {property.MemberName()}");
AttributeCache.TryAdd(property.MemberName(), attribute);
}
else
{
PatternCN = pattern;
ff14bot.Helpers.Logging.Write($"No attribute found for {property.MemberName()}");
}
}

return attribute;
}

IgnoreCache = ignoreCache;
public static IntPtr SearchOffset(this ISearcher finder, string pattern)
{
if (string.IsNullOrEmpty(pattern))
{
ff14bot.Helpers.Logging.Write("Pattern is null or empty");
return IntPtr.Zero;
}

public OffsetAttribute(string pattern, string cnpattern, bool ignoreCache = false, int expectedValue = 0)
try
{
return finder.FindSingle(pattern, true);
}
catch (Exception e)
{
ff14bot.Helpers.Logging.Write(e.ToString());
return IntPtr.Zero;
}
}

public static IntPtr SearchOffset(this ISearcher finder, MemberInfo field, ForceClientMode forceClientMode = ForceClientMode.None)
{
return finder.SearchOffset(field.GetPattern(forceClientMode));
}

public static void SetValue(this MemberInfo field, IntPtr offset)
{
switch (field)
{
/*if (pattern != "")
Pattern = pattern;*/
PatternCN = cnpattern;
if (!PatternCN.StartsWith("Search "))
case FieldInfo fieldInfo:
if (fieldInfo.FieldType == typeof(IntPtr))
{
fieldInfo.SetValue(null, offset);
}
else
{
fieldInfo.SetValue(null, offset.ToInt32());
}

break;
case PropertyInfo propertyInfo:
if (propertyInfo.PropertyType == typeof(IntPtr))
{
propertyInfo.SetValue(null, offset);
}
else
{
propertyInfo.SetValue(null, offset.ToInt32());
}

break;
}
}

public static Type? GetMemberType(this MemberInfo field)
{
return field switch
{
FieldInfo fieldInfo => fieldInfo.FieldType,
PropertyInfo propertyInfo => propertyInfo.PropertyType,
Type type => type,
_ => null
};
}

public static void SetValue(this MemberInfo field, long offset)
{
try
{
switch (field)
{
PatternCN = "Search " + PatternCN;
case FieldInfo fieldInfo:
if (fieldInfo.FieldType == typeof(IntPtr))
{
fieldInfo.SetValue(null, Core.Memory.GetAbsolute(new IntPtr(offset)));
}
else
{
fieldInfo.SetValue(null, (int)offset);
}

break;
case PropertyInfo propertyInfo:
if (propertyInfo.PropertyType == typeof(IntPtr))
{
propertyInfo.SetValue(null, Core.Memory.GetAbsolute(new IntPtr(offset)));
}
else
{
propertyInfo.SetValue(null, (int)offset);
}

break;
}
}
catch (Exception e)
{
ff14bot.Helpers.Logging.Write(e.ToString());
ff14bot.Helpers.Logging.Write($"Failed to set {field.Name} with value {offset:X} {offset.GetType()}");
switch (field)
{
case FieldInfo fieldInfo:
ff14bot.Helpers.Logging.Write($"Field type: {fieldInfo.FieldType}");
break;
case PropertyInfo propertyInfo:
ff14bot.Helpers.Logging.Write($"Property type: {propertyInfo.PropertyType}");
break;
}

throw;
}
}

IgnoreCache = ignoreCache;
public static void SetValue(this MemberInfo info, object instance, IntPtr offset)
{
switch (info)
{
case FieldInfo fieldInfo:
fieldInfo.SetValue(instance, fieldInfo.FieldType == typeof(IntPtr) ? offset : offset.ToInt32());
break;
case PropertyInfo propertyInfo:
propertyInfo.SetValue(instance, propertyInfo.PropertyType == typeof(IntPtr) ? offset : offset.ToInt32());
break;
}
}

public class OffsetCNAttribute : OffsetAttribute
public static void SetValue(this MemberInfo info, object? instance, object? offset)
{
public OffsetCNAttribute(string pattern, bool ignoreCache = false, int expectedValue = 0) : base("", pattern, ignoreCache, expectedValue)
switch (info)
{
case FieldInfo fieldInfo:
fieldInfo.SetValue(instance, offset);
break;
case PropertyInfo propertyInfo:
propertyInfo.SetValue(instance, offset);
break;
}
}

public static IntPtr GetOffset(this MemberInfo field, ISearcher finder, ForceClientMode forceClientMode = ForceClientMode.None)
{
if (!field.IgnoreCache() && OffsetManager.OffsetCache.TryGetValue(field.MemberName(), out var offset))
{
switch (field.GetMemberType())
{
case { } type when type == typeof(IntPtr):
return Core.Memory.GetAbsolute(new IntPtr(offset));
case { } type when type == typeof(int):
return new IntPtr((int)offset);
}
}

var result = finder.SearchOffset(field, forceClientMode);
if (result != IntPtr.Zero)
{
try
{
OffsetManager.OffsetCache.TryAdd(field.MemberName(), field.GetMemberType() == typeof(IntPtr) ? Core.Memory.GetRelative(result).ToInt64() : result.ToInt32());
}
catch (Exception e)
{
ff14bot.Helpers.Logging.Write($"{field.MemberName()} with value {result.ToInt64():X} failed to add to cache.");
ff14bot.Helpers.Logging.Write(e.ToString());
}
}

return result;
}

public static string MemberName(this MemberInfo field)
{
return field switch
{
FieldInfo fieldInfo => $"{fieldInfo.DeclaringType?.FullName}.{fieldInfo.Name}",
PropertyInfo propertyInfo => $"{propertyInfo.DeclaringType?.FullName}.{propertyInfo.Name}",
_ => string.Empty
};
}
}

public class OffsetCNAttribute : OffsetAttribute
{
private static bool _isValid { get; } = Language == Language.Chn;

public override bool IsValid(ForceClientMode clientMode)
{
return clientMode == ForceClientMode.CN || _isValid;
}

public override int Priority { get; } = 1;

public OffsetCNAttribute(string pattern, bool ignoreCache = false, int expectedValue = 0) : base("", pattern, ignoreCache, expectedValue)
{
}
}

public class OffsetDawntrailAttribute : OffsetAttribute
{
private static bool _isValid { get; } = false;

public override bool IsValid(ForceClientMode clientMode)
{
return clientMode == ForceClientMode.Dawntrail || _isValid;
}

public override int Priority { get; } = 2;

public OffsetDawntrailAttribute(string pattern, bool ignoreCache = false, int expectedValue = 0) : base("", "", pattern, ignoreCache, expectedValue)
{
}
}

public enum ForceClientMode
{
None,
Global,
CN,
Dawntrail
}
Loading

0 comments on commit 71f8ee8

Please sign in to comment.