-
Notifications
You must be signed in to change notification settings - Fork 24
/
Chatlog.cs
159 lines (135 loc) · 4.97 KB
/
Chatlog.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace ffxivlib
{
public partial class Chatlog : BaseObject<Chatlog.CHATLOGINFO>
{
#region Constructor
public Chatlog(CHATLOGINFO structure, IntPtr address)
: base(structure, address)
{
Initialize();
}
#endregion
#region Fields
private readonly List<Entry> _buffer = new List<Entry>();
private readonly MemoryReader _mr = MemoryReader.GetInstance();
private readonly List<int> _offsetsList = new List<int>();
private int _currentOffset;
private int _previousArrayIndex;
private int _previousOffset;
#endregion
#region Private Methods
/// <summary>
/// Updates our offsets list
/// </summary>
private void UpdateOffsetArray()
{
_offsetsList.Clear();
for (int i = 0; i < Constants.CHATLOG_ARRAY_SIZE; i++)
_offsetsList.Add((int) _mr.ResolvePointer((IntPtr) (Structure.ArrayStart + (i*0x4))));
}
/// <summary>
/// Reads a single line and create an Entry out of it
/// </summary>
/// <param name="start">Start offset of the line</param>
/// <param name="end">End offset of the line</param>
/// <returns>Entry instance</returns>
private Entry ReadEntry(int start, int end)
{
int bytesread;
var entry =
new Entry(_mr.ReadAdress((IntPtr) (Structure.LogStart + start), (uint) (end - start), out bytesread));
return entry;
}
/// <summary>
/// This is a wrapper around ReadEntry
/// in order to create a List of Entry out
/// of all the lines we haven't processed yet.
/// </summary>
/// <param name="start">Array index to start at</param>
/// <param name="end">Array index to stop at</param>
/// <returns>List of Entry instances</returns>
private IEnumerable<Entry> ReadEntries(int start, int end)
{
var ret = new List<Entry>();
for (int i = start; i < end; i++)
{
UpdateOffsetArray();
_currentOffset = _offsetsList[i];
ret.Add(ReadEntry(_previousOffset, _currentOffset));
_previousOffset = _currentOffset;
}
return ret;
}
/// <summary>
/// This updates our internal buffer.
/// </summary>
private void UpdateBuffer()
{
UpdateOffsetArray();
Structure = _mr.CreateStructFromAddress<CHATLOGINFO>(Address);
int currentArrayIndex = (Structure.ArrayCurrent - Structure.ArrayStart) / 4;
// I forgot why we did this
if (currentArrayIndex < _previousArrayIndex)
{
_buffer.AddRange(ReadEntries(_previousArrayIndex, (int)Constants.CHATLOG_ARRAY_SIZE));
_previousOffset = 0;
_previousArrayIndex = 0;
}
if (_previousArrayIndex < currentArrayIndex)
_buffer.AddRange(ReadEntries(_previousArrayIndex, currentArrayIndex));
_previousArrayIndex = currentArrayIndex;
}
#endregion
#region Public methods
/// <summary>
/// Is there a new line?
/// </summary>
/// <returns></returns>
public bool IsNewLine()
{
UpdateBuffer();
return (_buffer.Count > 0);
}
/// <summary>
/// This returns a copy of our buffer, and clear it.
/// </summary>
/// <returns>List of Entry instances</returns>
public List<Entry> GetChatLogLines()
{
UpdateBuffer();
List<Entry> newList = _buffer.ToList();
_buffer.Clear();
return newList;
}
#endregion
#region Unmanaged structure
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct CHATLOGINFO
{
[MarshalAs(UnmanagedType.I4)] [FieldOffset(0)] public int Count;
[MarshalAs(UnmanagedType.I4)] [FieldOffset(0x20)] public int ArrayStart;
[MarshalAs(UnmanagedType.I4)] [FieldOffset(0x24)] public int ArrayCurrent;
[MarshalAs(UnmanagedType.I4)] [FieldOffset(0x30)] public int LogStart;
};
#endregion
}
public partial class FFXIVLIB
{
#region Public methods
/// <summary>
/// This function instantiates a Chatlog object
/// </summary>
/// <returns>Chatlog instance</returns>
public Chatlog GetChatlog()
{
IntPtr pointer = _mr.ResolvePointerPath(Constants.CHATPTR);
var c = new Chatlog(_mr.CreateStructFromAddress<Chatlog.CHATLOGINFO>(pointer), pointer);
return c;
}
#endregion
}
}