2015-06-30 00:07:12 +07:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
2019-04-04 10:22:02 +08:00
|
|
|
using File = System.IO.File;
|
|
|
|
|
using StreamReader = System.IO.StreamReader;
|
|
|
|
|
using MemoryStream = System.IO.MemoryStream;
|
|
|
|
|
using BinaryReader = System.IO.BinaryReader;
|
|
|
|
|
using BinaryWriter = System.IO.BinaryWriter;
|
2015-06-30 00:07:12 +07:00
|
|
|
|
|
|
|
|
namespace FalloutClient {
|
2019-04-04 10:22:02 +08:00
|
|
|
|
|
|
|
|
public partial class DebugEditor : Form
|
|
|
|
|
{
|
2015-06-30 00:07:12 +07:00
|
|
|
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
|
|
|
|
|
private struct ByteConverter {
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(0)]
|
|
|
|
|
private int i;
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(0)]
|
|
|
|
|
private float f;
|
|
|
|
|
|
|
|
|
|
public int GetAsInt(float f) {
|
2019-04-04 10:22:02 +08:00
|
|
|
this.f = f;
|
2015-06-30 00:07:12 +07:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
public float GetAsFloat(int i) {
|
2019-04-04 10:22:02 +08:00
|
|
|
this.i = i;
|
2015-06-30 00:07:12 +07:00
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
public byte[] GetAsBytes(ulong ul) {
|
2019-04-04 10:22:02 +08:00
|
|
|
byte[] b = new byte[8];
|
|
|
|
|
for (int i = 0; i < 8; i++) b[i] = (byte)((ul & ((ulong)0xff << (i * 8))) >> (i * 8));
|
2015-06-30 00:07:12 +07:00
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-04 10:22:02 +08:00
|
|
|
private static ByteConverter converter = new ByteConverter();
|
2015-06-30 00:07:12 +07:00
|
|
|
|
|
|
|
|
private enum Mode { Globals, MapVars, SGlobals, Arrays, Critters }
|
|
|
|
|
|
|
|
|
|
private readonly EditorConnection connection;
|
|
|
|
|
private Mode mode;
|
|
|
|
|
|
2019-04-04 10:22:02 +08:00
|
|
|
private readonly Dictionary<int, string> GlobNames = new Dictionary<int, string>();
|
|
|
|
|
private readonly Dictionary<uint, string> CritNames = new Dictionary<uint, string>();
|
2015-06-30 00:07:12 +07:00
|
|
|
|
|
|
|
|
private void Redraw() {
|
|
|
|
|
dataGridView1.SuspendLayout();
|
|
|
|
|
dataGridView1.Rows.Clear();
|
2019-04-04 10:22:02 +08:00
|
|
|
switch (mode) {
|
2015-06-30 00:07:12 +07:00
|
|
|
case Mode.Globals:
|
2019-04-04 10:22:02 +08:00
|
|
|
Column2.ReadOnly = false;
|
|
|
|
|
Column3.ReadOnly = false;
|
|
|
|
|
Column2.HeaderText = "Value (Int)";
|
|
|
|
|
Column3.HeaderText = "Value (Float)";
|
|
|
|
|
bEdit.Enabled = false;
|
|
|
|
|
for (int i = 0; i < connection.Globals.Length; i++) {
|
|
|
|
|
string name = GlobNames.ContainsKey(i) ? GlobNames[i] : "";
|
2015-06-30 00:07:12 +07:00
|
|
|
dataGridView1.Rows.Add(i, name, connection.Globals[i], converter.GetAsFloat(connection.Globals[i]));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Mode.MapVars:
|
2019-04-04 10:22:02 +08:00
|
|
|
Column2.ReadOnly = false;
|
|
|
|
|
Column3.ReadOnly = false;
|
|
|
|
|
Column2.HeaderText = "Value (Int)";
|
|
|
|
|
Column3.HeaderText = "Value (Float)";
|
|
|
|
|
bEdit.Enabled = false;
|
|
|
|
|
for (int i = 0; i < connection.MapVars.Length; i++) {
|
2015-06-30 00:07:12 +07:00
|
|
|
dataGridView1.Rows.Add(i, "", connection.MapVars[i], converter.GetAsFloat(connection.MapVars[i]));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Mode.SGlobals:
|
2019-04-04 10:22:02 +08:00
|
|
|
Column2.ReadOnly = false;
|
|
|
|
|
Column3.ReadOnly = false;
|
|
|
|
|
Column2.HeaderText = "Value (Int)";
|
|
|
|
|
Column3.HeaderText = "Value (Float)";
|
|
|
|
|
bEdit.Enabled = false;
|
|
|
|
|
for (int i = 0; i < connection.SGlobalKeys.Length; i++) {
|
|
|
|
|
string s = connection.SGlobalKeys[i] > 0xffffffff
|
|
|
|
|
? new string(System.Text.ASCIIEncoding.ASCII.GetChars(converter.GetAsBytes(connection.SGlobalKeys[i])))
|
|
|
|
|
: (connection.SGlobalKeys[i].ToString());
|
2015-06-30 00:07:12 +07:00
|
|
|
dataGridView1.Rows.Add(s, "", connection.sGlobals[i], converter.GetAsFloat(connection.sGlobals[i]));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Mode.Arrays:
|
2019-04-04 10:22:02 +08:00
|
|
|
Column2.ReadOnly = true;
|
|
|
|
|
Column3.ReadOnly = true;
|
|
|
|
|
Column2.HeaderText = "Array size";
|
|
|
|
|
Column3.HeaderText = "Array flags";
|
|
|
|
|
bEdit.Enabled = true;
|
|
|
|
|
for (int i = 0; i < connection.Arrays.Length; i++) {
|
|
|
|
|
bool isMap = connection.ArrayIsMap[i];
|
|
|
|
|
int arrlen = connection.ArrayLengths[i];
|
|
|
|
|
if (isMap) arrlen /= 2;
|
|
|
|
|
dataGridView1.Rows.Add(connection.Arrays[i], isMap ? "Map" : "", arrlen, "0x" + connection.ArrayDataSizes[i].ToString("x").ToUpper());
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Mode.Critters:
|
2019-04-04 10:22:02 +08:00
|
|
|
Column2.ReadOnly = true;
|
|
|
|
|
Column3.ReadOnly = true;
|
|
|
|
|
Column2.HeaderText = "Pid";
|
|
|
|
|
Column3.HeaderText = "Pointer";
|
|
|
|
|
bEdit.Enabled = true;
|
|
|
|
|
for (int i = 0; i < connection.Critters.Length / 2; i++) {
|
|
|
|
|
uint modcrit = (connection.Critters[i, 0] & 0xfffff);
|
|
|
|
|
string name = CritNames.ContainsKey(modcrit) ? CritNames[modcrit] : "";
|
|
|
|
|
dataGridView1.Rows.Add(i + 1, name, connection.Critters[i, 0].ToString("x").ToUpper(), connection.Critters[i, 1].ToString());
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
dataGridView1.ResumeLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal DebugEditor(EditorConnection connection) {
|
|
|
|
|
InitializeComponent();
|
2019-04-04 10:22:02 +08:00
|
|
|
this.connection = connection;
|
|
|
|
|
mode = Mode.Globals;
|
|
|
|
|
if (File.Exists(".\\data\\data\\vault13.gam")) {
|
|
|
|
|
StreamReader sr=new StreamReader(".\\data\\data\\vault13.gam");
|
|
|
|
|
int gvar = 0;
|
|
|
|
|
while (!sr.EndOfStream) {
|
|
|
|
|
string line = sr.ReadLine().TrimStart();
|
|
|
|
|
if (line.StartsWith("GVAR_")) GlobNames[gvar++] = line.Remove(line.IndexOf(':')).TrimEnd();
|
|
|
|
|
}
|
|
|
|
|
sr.Close();
|
|
|
|
|
} else if (File.Exists("globals.txt")) {
|
|
|
|
|
StreamReader sr = new StreamReader("globals.txt");
|
|
|
|
|
while (!sr.EndOfStream) {
|
|
|
|
|
string[] line = sr.ReadLine().Split(' ');
|
|
|
|
|
GlobNames[int.Parse(line[0])] = line[1];
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
sr.Close();
|
|
|
|
|
}
|
2019-04-04 10:22:02 +08:00
|
|
|
if (File.Exists("critters.txt")) {
|
|
|
|
|
StreamReader sr = new StreamReader("critters.txt");
|
|
|
|
|
while (!sr.EndOfStream) {
|
|
|
|
|
string line = sr.ReadLine();
|
|
|
|
|
CritNames[uint.Parse(line.Remove(line.IndexOf(' ')))] = line.Substring(line.IndexOf(' ') + 1);
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
sr.Close();
|
|
|
|
|
}
|
|
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DebugEditor_FormClosing(object sender, FormClosingEventArgs e) {
|
|
|
|
|
connection.WriteDataType(DataTypeSend.Exit);
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bGlobals_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
mode = Mode.Globals;
|
2015-06-30 00:07:12 +07:00
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bMapVars_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
mode = Mode.MapVars;
|
2015-06-30 00:07:12 +07:00
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bSGlobals_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
mode = Mode.SGlobals;
|
2015-06-30 00:07:12 +07:00
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bArrays_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
mode = Mode.Arrays;
|
2015-06-30 00:07:12 +07:00
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bCritters_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
mode = Mode.Critters;
|
2015-06-30 00:07:12 +07:00
|
|
|
Redraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
int[] array = null;
|
2015-06-30 00:07:12 +07:00
|
|
|
DataTypeSend dts;
|
2019-04-04 10:22:02 +08:00
|
|
|
switch (mode) {
|
2015-06-30 00:07:12 +07:00
|
|
|
case Mode.Globals:
|
2019-04-04 10:22:02 +08:00
|
|
|
array = connection.Globals;
|
|
|
|
|
dts = DataTypeSend.SetGlobal;
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
case Mode.MapVars:
|
2019-04-04 10:22:02 +08:00
|
|
|
array = connection.MapVars;
|
|
|
|
|
dts = DataTypeSend.SetMapVar;
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
case Mode.SGlobals:
|
2019-04-04 10:22:02 +08:00
|
|
|
array = connection.sGlobals;
|
|
|
|
|
dts = DataTypeSend.SetSGlobal;
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-04 10:22:02 +08:00
|
|
|
if (e.ColumnIndex == 2) {
|
2015-06-30 00:07:12 +07:00
|
|
|
int val;
|
2019-04-04 10:22:02 +08:00
|
|
|
if (!int.TryParse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), out val)) {
|
|
|
|
|
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = array[e.RowIndex];
|
2015-06-30 00:07:12 +07:00
|
|
|
} else {
|
2019-04-04 10:22:02 +08:00
|
|
|
array[e.RowIndex] = val;
|
2015-06-30 00:07:12 +07:00
|
|
|
connection.WriteDataType(dts);
|
|
|
|
|
connection.WriteInt(e.RowIndex);
|
|
|
|
|
connection.WriteInt(val);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
float val;
|
2019-04-04 10:22:02 +08:00
|
|
|
if (!float.TryParse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), out val)) {
|
|
|
|
|
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = array[e.RowIndex];
|
2015-06-30 00:07:12 +07:00
|
|
|
} else {
|
2019-04-04 10:22:02 +08:00
|
|
|
array[e.RowIndex] = converter.GetAsInt(val);
|
2015-06-30 00:07:12 +07:00
|
|
|
connection.WriteDataType(dts);
|
|
|
|
|
connection.WriteInt(e.RowIndex);
|
|
|
|
|
connection.WriteInt(converter.GetAsInt(val));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bEdit_Click(object sender, EventArgs e) {
|
2019-04-04 10:22:02 +08:00
|
|
|
if (dataGridView1.SelectedRows.Count == 0) return;
|
|
|
|
|
int i = dataGridView1.SelectedRows[0].Index;
|
|
|
|
|
switch (mode) {
|
2015-06-30 00:07:12 +07:00
|
|
|
case Mode.Arrays: {
|
2019-04-04 10:22:02 +08:00
|
|
|
DataType[] types = new DataType[connection.ArrayLengths[i]];
|
|
|
|
|
int[] lenType = new int[connection.ArrayLengths[i]];
|
|
|
|
|
string[] strings = new string[connection.ArrayLengths[i]];
|
|
|
|
|
connection.WriteDataType(DataTypeSend.GetArray); // code
|
|
|
|
|
connection.WriteInt(i); // index
|
|
|
|
|
int lenData = 0;
|
|
|
|
|
for (int j = 0; j < strings.Length; j++) {
|
|
|
|
|
types[j] = (DataType)connection.ReadInt();
|
|
|
|
|
lenType[j] = connection.ReadInt(); // len data of type
|
|
|
|
|
lenData += lenType[j];
|
|
|
|
|
}
|
|
|
|
|
byte[] buf = connection.ReadBytes(lenData); // read data
|
2015-06-30 00:07:12 +07:00
|
|
|
MemoryStream ms=new MemoryStream(buf);
|
|
|
|
|
BinaryReader br=new BinaryReader(ms);
|
2019-04-04 10:22:02 +08:00
|
|
|
ms.Position = 0;
|
|
|
|
|
for (int j = 0; j < strings.Length; j++) {
|
|
|
|
|
switch (types[j]) {
|
2015-06-30 00:07:12 +07:00
|
|
|
case DataType.Int:
|
2019-04-04 10:22:02 +08:00
|
|
|
strings[j] = br.ReadInt32().ToString();
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
case DataType.Float:
|
2019-04-04 10:22:02 +08:00
|
|
|
strings[j] = br.ReadSingle().ToString();
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
case DataType.String:
|
2019-04-04 10:22:02 +08:00
|
|
|
byte[] bytes = br.ReadBytes(lenType[j]);
|
|
|
|
|
strings[j] = System.Text.Encoding.ASCII.GetString(bytes, 0, lenType[j] - 1); //Array.IndexOf<byte>(bytes, 0)
|
2015-06-30 00:07:12 +07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
br.Close();
|
2019-04-04 10:22:02 +08:00
|
|
|
strings = EditorWindow.ShowEditor(null, types, strings);
|
|
|
|
|
if (strings != null) { // save
|
2015-06-30 00:07:12 +07:00
|
|
|
connection.WriteDataType(DataTypeSend.SetArray);
|
|
|
|
|
connection.WriteInt(i);
|
2019-04-04 10:22:02 +08:00
|
|
|
ms = new MemoryStream(connection.ArrayLengths[i] * connection.ArrayDataSizes[i]);
|
2015-06-30 00:07:12 +07:00
|
|
|
BinaryWriter bw=new BinaryWriter(ms);
|
2019-04-04 10:22:02 +08:00
|
|
|
for (int j = 0; j < strings.Length; j++) {
|
|
|
|
|
ms.Position = j * connection.ArrayDataSizes[i];
|
|
|
|
|
switch (types[j]) {
|
2015-06-30 00:07:12 +07:00
|
|
|
case DataType.Int:
|
|
|
|
|
bw.Write(int.Parse(strings[j]));
|
|
|
|
|
break;
|
|
|
|
|
case DataType.Float:
|
|
|
|
|
bw.Write(float.Parse(strings[j]));
|
|
|
|
|
break;
|
|
|
|
|
case DataType.String:
|
|
|
|
|
byte[] bytes=System.Text.Encoding.ASCII.GetBytes(strings[j]);
|
2019-04-04 10:22:02 +08:00
|
|
|
if (bytes.Length < connection.ArrayDataSizes[i]) bw.Write(bytes);
|
|
|
|
|
else bw.Write(bytes, 0, connection.ArrayDataSizes[i] - 1);
|
2015-06-30 00:07:12 +07:00
|
|
|
bw.Write(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-04 10:22:02 +08:00
|
|
|
connection.WriteBytes(ms.GetBuffer(), 0, connection.ArrayLengths[i] * connection.ArrayDataSizes[i]);
|
2015-06-30 00:07:12 +07:00
|
|
|
bw.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Mode.Critters: {
|
2019-04-04 10:22:02 +08:00
|
|
|
DataType[] types=new DataType[33];
|
|
|
|
|
string[] strings=new string[33];
|
|
|
|
|
string[] names=new string[33];
|
2015-06-30 00:07:12 +07:00
|
|
|
connection.WriteDataType(DataTypeSend.RetrieveCritter);
|
|
|
|
|
connection.WriteInt(i);
|
2019-04-04 10:22:02 +08:00
|
|
|
BinaryReader br=new BinaryReader(new System.IO.MemoryStream(connection.ReadBytes(33 * 4)));
|
|
|
|
|
for (int j = 0; j < 33; j++) {
|
|
|
|
|
types[j] = DataType.Int;
|
|
|
|
|
strings[j] = br.ReadInt32().ToString();
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
br.Close();
|
2019-04-04 10:22:02 +08:00
|
|
|
names[0] = " ID";
|
|
|
|
|
names[1] = " Tile";
|
|
|
|
|
names[6] = " Current frame";
|
|
|
|
|
names[7] = " Rotation";
|
|
|
|
|
names[8] = " FID";
|
|
|
|
|
names[9] = " Flags";
|
|
|
|
|
names[10] = " Elevation";
|
|
|
|
|
names[11] = " Inventory count";
|
|
|
|
|
names[13] = " Inventory pointer";
|
|
|
|
|
names[14] = " Reaction";
|
|
|
|
|
names[15] = " Combat state";
|
|
|
|
|
names[16] = " Current AP";
|
|
|
|
|
names[17] = " Combat flags";
|
|
|
|
|
names[18] = " Last Turn Damage";
|
|
|
|
|
names[19] = " AI Packet";
|
|
|
|
|
names[20] = " Team";
|
|
|
|
|
names[21] = " Who hit me";
|
|
|
|
|
names[22] = " HP";
|
|
|
|
|
names[23] = " Rads";
|
|
|
|
|
names[24] = " Poison";
|
|
|
|
|
names[25] = " Proto ID";
|
|
|
|
|
names[26] = " Combat ID";
|
|
|
|
|
names[29] = " Outline flags";
|
|
|
|
|
names[30] = " Script ID";
|
|
|
|
|
names[32] = " Script index";
|
|
|
|
|
strings = EditorWindow.ShowEditor(names, types, strings);
|
|
|
|
|
if (strings != null) {
|
|
|
|
|
MemoryStream ms = new MemoryStream(33 * 4);
|
|
|
|
|
BinaryWriter bw = new BinaryWriter(ms);
|
|
|
|
|
for (int j = 0; j < 33; j++) bw.Write(int.Parse(strings[j]));
|
2015-06-30 00:07:12 +07:00
|
|
|
connection.WriteDataType(DataTypeSend.SetCritter);
|
|
|
|
|
connection.WriteInt(i);
|
2019-04-04 10:22:02 +08:00
|
|
|
connection.WriteBytes(ms.GetBuffer(), 0, 33 * 4);
|
2015-06-30 00:07:12 +07:00
|
|
|
bw.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-04 10:22:02 +08:00
|
|
|
|
|
|
|
|
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
|
|
|
|
|
bEdit.PerformClick();
|
|
|
|
|
}
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
}
|