forked from sruon/ffxivlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BaseObject.cs
113 lines (99 loc) · 3.96 KB
/
BaseObject.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace ffxivlib
{
/// <summary>
/// Abstract base class for various objects
/// </summary>
/// <typeparam name="TU">Structure type</typeparam>
public abstract class BaseObject<TU>
{
#region Properties
/// <summary>
/// Address of object in FFXIV memory space.
/// </summary>
public IntPtr Address { get; private set; }
/// <summary>
/// Structure related to object.
/// </summary>
public TU Structure { get; internal set; }
#endregion
#region Constructor
/// <summary>
/// Base class constructor, sets a few fields.
/// Cannot be instantiated on its own.
/// </summary>
/// <param name="structure">Structure</param>
/// <param name="address">Address</param>
internal BaseObject(TU structure, IntPtr address)
{
Structure = structure;
Address = address;
}
#endregion
#region PostConstructor
/// <summary>
/// Sets object properties from structure.
/// </summary>
internal void Initialize()
{
foreach (var field in typeof (TU).GetFields(BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public))
{
var value = field.GetValue(Structure);
var prop = GetType().GetProperty(field.Name);
if (prop != null)
{
prop.SetValue(this, value, null);
}
}
}
#endregion
#region Methods
/// <summary>
/// This function computes the address inside FFXIV process space to be modified for a given field
/// and then modifies it.
/// This will be deprecated with proper setters.
/// </summary>
/// <typeparam name="TX">Type of the value to modify, stick to base types</typeparam>
/// <param name="field">Name of the structure field to modify</param>
/// <param name="value">Value to assign to field</param>
public virtual void Modify<TX>(string field, TX value)
{
IntPtr tobemodified = IntPtr.Add(Address, (int) Marshal.OffsetOf(typeof (TU), field));
try
{
object byteValue = typeof (BitConverter).GetMethod("GetBytes", new[] {value.GetType()})
.Invoke(null, new object[] {value});
MemoryReader.GetInstance().WriteAddress(tobemodified, byteValue as byte[]);
}
catch (AmbiguousMatchException)
{
/*
* This fixes 2 issues:
* 1. Reflector cannot determine the proper GetBytes()
* call for single byte values (or I'm just bad)
* 2. Hack for single byte values, above code create byte[2]
* array which are then written and cause crashes.
* I hate catching exceptions for this kind of shit.
* There is probably something more sexy to be done but it works.
*/
var byteArray = new byte[1];
byteArray[0] = Convert.ToByte(value);
MemoryReader.GetInstance().WriteAddress(tobemodified, byteArray);
}
}
/// <summary>
/// This refreshes the instance
/// It may have unexpected behavior if address changes.
/// This will be deprecated with proper getters.
/// </summary>
public virtual void Refresh()
{
Structure = MemoryReader.GetInstance().CreateStructFromAddress<TU>(Address);
}
#endregion
}
}