From f78243fccb467e7b3b3483289770669f4a89d328 Mon Sep 17 00:00:00 2001 From: Damani Date: Sun, 19 Oct 2014 15:39:28 +0300 Subject: [PATCH] Initial commit --- .gitignore | 8 ++ dub.json | 12 +++ source/app.d | 276 ++++++++++++++++++++++++++++++++++++++++++++++++ source/models.d | 274 +++++++++++++++++++++++++++++++++++++++++++++++ source/util.d | 15 +++ 5 files changed, 585 insertions(+) create mode 100644 .gitignore create mode 100644 dub.json create mode 100644 source/app.d create mode 100644 source/models.d create mode 100644 source/util.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3f9183 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.dub +bin +docs.json +__dummy.html +*.o +*.obj +*.selections.json +*.userprefs diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..0e33a5a --- /dev/null +++ b/dub.json @@ -0,0 +1,12 @@ +{ + "name": "domain2editor", + "description": "PW domain2.data editor", + "copyright": "Copyright © 2014, Beast", + "authors": ["Beast"], + "targetPath": "bin", + "targetType": "executable", + "lflags-windows-dmd": ["/subsystem:windows"], + "dependencies": { + "dfl2": "~master" + } +} diff --git a/source/app.d b/source/app.d new file mode 100644 index 0000000..81f2356 --- /dev/null +++ b/source/app.d @@ -0,0 +1,276 @@ +import std.stdio; +import std.file; +import std.mmfile; +import std.system; +import std.array; +import std.conv; +import std.string; +import std.utf; +import dfl.base; +import dfl.application; +import dfl.drawing; +import dfl.control; +import dfl.event; +import dfl.form; +import dfl.label; +import dfl.button; +import dfl.textbox; +import dfl.combobox; +import dfl.listbox; +import dfl.filedialog; +import dfl.menu; +import models; +import util; + +class MainForm : Form +{ +private: + TextBox _pathText; + ListBox _dataList; + TextBox _nameText; + ComboBox _typeText; + TextBox _pointsText; + TextBox _ownerText; + ComboBox _capitalText; + TextBox _xText; + TextBox _yText; + ContextMenu _saveMenu; + DataStruct _data; + int _selectedIndex = -1; + + public this() + { + text = "Domain2 Editor"; + startPosition = FormStartPosition.CENTER_SCREEN; + formBorderStyle = FormBorderStyle.FIXED_3D; + size = Size(600, 600); + maximizeBox = false; + + _pathText = new TextBox(); + _pathText.bounds = Rect(5, 8, 425, 20); + _pathText.text = "domain2.data"; + _pathText.parent = this; + + auto openButton = new Button(); + openButton.text = ".."; + openButton.bounds = Rect(435, 5, 40, 25); + openButton.click ~= &chooseFile; + openButton.parent = this; + + auto loadButton = new Button(); + loadButton.text = "Load"; + loadButton.bounds = Rect(480, 5, 50, 25); + loadButton.click ~= &loadDataFile; + loadButton.parent = this; + + auto saveButton = new Button(); + saveButton.text = "Save"; + saveButton.bounds = Rect(535, 5, 50, 25); + saveButton.click ~= &showSaveMenu; + saveButton.parent = this; + + _saveMenu = new ContextMenu(); + + auto dataMenu = new MenuItem(); + dataMenu.text = ("Save as data"); + dataMenu.click ~= &saveDataFile; + _saveMenu.menuItems.add(dataMenu); + + auto sevMenu = new MenuItem(); + sevMenu.text = ("Save as sev"); + sevMenu.click ~= &saveSevFile; + _saveMenu.menuItems.add(sevMenu); + + _dataList = new ListBox(); + _dataList.bounds = Rect(5, 35, 270, 530); + _dataList.selectedValueChanged ~= &selectItem; + _dataList.parent = this; + + auto nameLabel = new Label(); + nameLabel.text = "Name:"; + nameLabel.bounds = Rect(290, 45, 50, 25); + nameLabel.parent = this; + + _nameText = new TextBox(); + _nameText.bounds = Rect(340, 40, 240, 20); + _nameText.parent = this; + + auto typeLabel = new Label(); + typeLabel.text = "Type:"; + typeLabel.bounds = Rect(290, 75, 50, 25); + typeLabel.parent = this; + + _typeText = new ComboBox(); + _typeText.dropDownStyle = ComboBoxStyle.DROP_DOWN_LIST; + _typeText.items.add("Flag Battle"); + _typeText.items.add("Bridge"); + _typeText.items.add("Crystals"); + _typeText.bounds = Rect(340, 70, 240, 20); + _typeText.parent = this; + + auto pointsLabel = new Label(); + pointsLabel.text = "Points:"; + pointsLabel.bounds = Rect(290, 105, 50, 25); + pointsLabel.parent = this; + + _pointsText = new TextBox(); + _pointsText.bounds = Rect(340, 100, 240, 20); + _pointsText.parent = this; + + auto ownerLabel = new Label(); + ownerLabel.text = "Owner:"; + ownerLabel.bounds = Rect(290, 135, 50, 25); + ownerLabel.parent = this; + + _ownerText = new TextBox(); + _ownerText.bounds = Rect(340, 130, 240, 20); + _ownerText.parent = this; + + auto capitalLabel = new Label(); + capitalLabel.text = "Capital:"; + capitalLabel.bounds = Rect(290, 165, 50, 25); + capitalLabel.parent = this; + + _capitalText = new ComboBox(); + _capitalText.dropDownStyle = ComboBoxStyle.DROP_DOWN_LIST; + _capitalText.items.add("False"); + _capitalText.items.add("True"); + _capitalText.bounds = Rect(340, 160, 240, 20); + _capitalText.parent = this; + + auto xLabel = new Label(); + xLabel.text = "Center.X:"; + xLabel.bounds = Rect(290, 195, 50, 25); + xLabel.parent = this; + + _xText = new TextBox(); + _xText.bounds = Rect(340, 190, 240, 20); + _xText.parent = this; + + auto yLabel = new Label(); + yLabel.text = "Center.Y:"; + yLabel.bounds = Rect(290, 225, 50, 25); + yLabel.parent = this; + + _yText = new TextBox(); + _yText.bounds = Rect(340, 220, 240, 20); + _yText.parent = this; + + auto applyButton = new Button(); + applyButton.text = "Apply"; + applyButton.bounds = Rect(535, 535, 50, 25); + applyButton.click ~= &apply; + applyButton.parent = this; + } + + void chooseFile(Control sender, EventArgs e) + { + auto dialog = new OpenFileDialog(); + dialog.filter = "Data files(*.data)|*.data|All files(*.*)|*.*"; + if(dialog.showDialog() != DialogResult.OK) + return; + _pathText.text = dialog.fileName; + } + + void showSaveMenu(Control sender, EventArgs e) + { + _saveMenu.show(sender, Point(location.x + sender.location.x + 5, location.y + sender.location.y + 52)); + } + + void loadDataFile(Control sender, EventArgs e) + { + auto filename = _pathText.text; + if(!filename.exists) + return; + _data = loadData(filename); + _dataList.items.clear(); + foreach(domain; _data.domains) + _dataList.items.add(domain.name.text); + } + + void saveDataFile(MenuItem sender, EventArgs e) + { + if(!_data.loaded) + return; + auto filename = _pathText.text; + saveData(filename, _data); + } + + void saveSevFile(MenuItem sender, EventArgs e) + { + if(!_data.loaded) + return; + auto filename = _pathText.text; + auto sev = SevStruct(_data); + saveSev(filename, sev); + } + + void selectItem(Control sender, EventArgs e) + { + _selectedIndex = _dataList.selectedIndex; + if(_selectedIndex == -1) + return; + auto domain = _data.domains[_selectedIndex]; + _nameText.text = domain.name.text; + _typeText.selectedIndex = domain.battleType; + _pointsText.text = domain.points.text; + _ownerText.text = domain.owner.text; + _capitalText.selectedIndex = domain.capital; + _xText.text = domain.x.text; + _yText.text = domain.y.text; + } + + void apply(Control sender, EventArgs e) + { + if(_selectedIndex == -1) + return; + _data.domains[_selectedIndex].name = _nameText.text.to!(wchar[]); + _data.domains[_selectedIndex].battleType = _typeText.selectedIndex; + _data.domains[_selectedIndex].points = _pointsText.text.to!int; + _data.domains[_selectedIndex].owner = _ownerText.text.to!int; + _data.domains[_selectedIndex].capital = _capitalText.selectedIndex; + _data.domains[_selectedIndex].x = _xText.text.to!int; + _data.domains[_selectedIndex].y = _yText.text.to!int; + _dataList.items[_selectedIndex] = _nameText.text; + auto len = _data.domains[_selectedIndex].name.length; + for(auto i = len; i < 16; i++) + _data.domains[_selectedIndex].name ~= "\0"w; + _dataList.selectedIndex = _selectedIndex; + } +} + +void main() +{ + Application.enableVisualStyles(); + Application.run(new MainForm()); +} + +DataStruct loadData(string filename) +{ + auto file = new MmFile(filename); + auto buffer = cast(ubyte[])file[]; + return buffer.readModel!DataStruct(1); +} + +SevStruct loadSev(string filename) +{ + auto file = new MmFile(filename); + auto buffer = cast(ubyte[])file[]; + return buffer.readModel!SevStruct(1); +} + +void saveData(string filename, DataStruct data) +{ + auto file = File(filename, "wb"); + auto buffer = appender!(const ubyte[])(); + buffer.writeModel(data); + file.rawWrite(buffer.data); +} + +void saveSev(string filename, SevStruct data) +{ + auto file = File(filename, "wb"); + auto buffer = appender!(const ubyte[])(); + buffer.writeModel(data); + file.rawWrite(buffer.data); +} \ No newline at end of file diff --git a/source/models.d b/source/models.d new file mode 100644 index 0000000..9eb7118 --- /dev/null +++ b/source/models.d @@ -0,0 +1,274 @@ +module models; + +import std.bitmanip; +import std.system; +import std.range; +import std.math; +import std.algorithm; +import util; + +struct DataStruct +{ + public uint signature; + public float speed; + public Domain[] domains; + public Time[] times; + public int unk; + public bool loaded; + + public void read(ref ubyte[] buffer, int ver = 1) + { + signature = buffer.read!(uint, Endian.littleEndian); + speed = buffer.read!(float, Endian.littleEndian); + auto count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + domains ~= buffer.readModel!Domain(ver); + count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + times ~= buffer.readModel!Time(); + unk = buffer.read!(int, Endian.littleEndian); + loaded = true; + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(uint, Endian.littleEndian)(signature); + buffer.append!(float, Endian.littleEndian)(speed); + buffer.append!(int, Endian.littleEndian)(domains.length); + foreach(domain; domains) + buffer.writeModel(domain, ver); + buffer.append!(int, Endian.littleEndian)(times.length); + foreach(time; times) + buffer.writeModel(time); + buffer.append!(int, Endian.littleEndian)(unk); + } +} + +struct SevStruct +{ + public DomainSev[] domains; + + this(DataStruct data) + { + foreach(domain; data.domains) + domains ~= DomainSev(domain); + calculateTimes(data.speed, data.domains); + } + + public void read(ref ubyte[] buffer, int ver = 1) + { + auto count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + domains ~= buffer.readModel!DomainSev(ver); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(int, Endian.littleEndian)(domains.length); + foreach(domain; domains) + buffer.writeModel(domain, ver); + } + + void calculateTimes(float speed, Domain[] base) + { + foreach(ref domain; domains) + { + foreach(ref touch; domain.touchDomains) + { + auto baseDomain = base.find!((a,b) => a.id == b)(domain.id)[0]; + auto touchDomain = base.find!((a,b) => a.id == b)(touch.id)[0]; + auto dist = sqrt(pow(cast(float)(touchDomain.x - baseDomain.x), 2) + pow(cast(float)(touchDomain.y - baseDomain.y), 2)); + touch.time = cast(int)(dist / speed); + } + } + } +} + +struct Domain +{ + public immutable (wchar)[] name; + public uint id; + public int points; + public int battleType; + public int owner; + public int capital; + public DomainPoint[] spawnPoints; + public int x; + public int y; + public Unk[] unks; + public DomainPoint[] unks2; + public uint[] touchDomains; + + public void read(ref ubyte[] buffer, int ver = 1) + { + for(auto i = 0; i < 16; i++) + name ~= buffer.read!(wchar, Endian.littleEndian); + id = buffer.read!(uint, Endian.littleEndian); + points = buffer.read!(int, Endian.littleEndian); + battleType = buffer.read!(int, Endian.littleEndian); + owner = buffer.read!(int, Endian.littleEndian); + capital = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < 4; i++) + spawnPoints ~= buffer.readModel!DomainPoint(ver); + x = buffer.read!(int, Endian.littleEndian); + y = buffer.read!(int, Endian.littleEndian); + + auto count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + unks ~= buffer.readModel!Unk(ver); + + count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + unks2 ~= buffer.readModel!DomainPoint(ver); + + count = buffer.read!(int, Endian.littleEndian); + for (auto i = 0; i < count; i++) + touchDomains ~= buffer.read!(uint, Endian.littleEndian); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + for(auto i = 0; i < 16; i++) + buffer.append!(wchar, Endian.littleEndian)(name[i]); + buffer.append!(uint, Endian.littleEndian)(id); + buffer.append!(int, Endian.littleEndian)(points); + buffer.append!(int, Endian.littleEndian)(battleType); + buffer.append!(int, Endian.littleEndian)(owner); + buffer.append!(int, Endian.littleEndian)(capital); + foreach(point; spawnPoints) + buffer.writeModel(point, ver); + buffer.append!(int, Endian.littleEndian)(x); + buffer.append!(int, Endian.littleEndian)(y); + buffer.append!(int, Endian.littleEndian)(unks.length); + foreach(point; unks) + buffer.writeModel(point, ver); + buffer.append!(int, Endian.littleEndian)(unks2.length); + foreach(point; unks2) + buffer.writeModel(point, ver); + buffer.append!(int, Endian.littleEndian)(touchDomains.length); + foreach(domain; touchDomains) + buffer.append!(uint, Endian.littleEndian)(domain); + } +} + +struct DomainSev +{ + public uint id; + public int points; + public int battleType; + public int owner; + public int capital; + public DomainPoint[] spawnPoints; + public TouchDomain[] touchDomains; + + this(Domain domain) + { + id = domain.id; + points = domain.points; + battleType = domain.battleType; + owner = domain.owner; + capital = domain.capital; + spawnPoints = domain.spawnPoints; + foreach(id; domain.touchDomains) + touchDomains ~= TouchDomain(id); + } + + public void read(ref ubyte[] buffer, int ver = 1) + { + id = buffer.read!(uint, Endian.littleEndian); + points = buffer.read!(int, Endian.littleEndian); + battleType = buffer.read!(int, Endian.littleEndian); + owner = buffer.read!(int, Endian.littleEndian); + capital = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < 4; i++) + spawnPoints ~= buffer.readModel!DomainPoint(ver); + + auto count = buffer.read!(int, Endian.littleEndian); + for(auto i = 0; i < count; i++) + touchDomains ~= TouchDomain(buffer.read!(uint, Endian.littleEndian)); + for (auto i = 0; i < count; i++) + touchDomains[i].time = buffer.read!(int, Endian.littleEndian); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(uint, Endian.littleEndian)(id); + buffer.append!(int, Endian.littleEndian)(points); + buffer.append!(int, Endian.littleEndian)(battleType); + buffer.append!(int, Endian.littleEndian)(owner); + buffer.append!(int, Endian.littleEndian)(capital); + foreach(point; spawnPoints) + buffer.writeModel(point, ver); + buffer.append!(int, Endian.littleEndian)(touchDomains.length); + foreach(domain; touchDomains) + buffer.append!(uint, Endian.littleEndian)(domain.id); + foreach(domain; touchDomains) + buffer.append!(int, Endian.littleEndian)(domain.time); + } +} + +struct DomainPoint +{ + public float x; + public float y; + public float z; + + public void read(ref ubyte[] buffer, int ver = 1) + { + x = buffer.read!(float, Endian.littleEndian); + y = buffer.read!(float, Endian.littleEndian); + z = buffer.read!(float, Endian.littleEndian); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(float, Endian.littleEndian)(x); + buffer.append!(float, Endian.littleEndian)(y); + buffer.append!(float, Endian.littleEndian)(z); + } +} + +struct TouchDomain +{ + public uint id; + public int time; +} + +struct Unk +{ + public float x; + public float y; + + public void read(ref ubyte[] buffer, int ver = 1) + { + x = buffer.read!(float, Endian.littleEndian); + y = buffer.read!(float, Endian.littleEndian); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(float, Endian.littleEndian)(x); + buffer.append!(float, Endian.littleEndian)(y); + } +} + +struct Time +{ + public int day; + public int hour; + public int minute; + + public void read(ref ubyte[] buffer, int ver = 1) + { + day = buffer.read!(int, Endian.littleEndian); + hour = buffer.read!(int, Endian.littleEndian); + minute = buffer.read!(int, Endian.littleEndian); + } + + public void write(ref Appender!(const(ubyte)[]) buffer, int ver = 1) + { + buffer.append!(int, Endian.littleEndian)(day); + buffer.append!(int, Endian.littleEndian)(hour); + buffer.append!(int, Endian.littleEndian)(minute); + } +} diff --git a/source/util.d b/source/util.d new file mode 100644 index 0000000..d70c972 --- /dev/null +++ b/source/util.d @@ -0,0 +1,15 @@ +module util; + +import std.range; + +T readModel(T)(ref ubyte[] range, int ver = 1) +{ + T res; + res.read(range, ver); + return res; +} + +void writeModel(T)(ref Appender!(const(ubyte)[]) range, T model, int ver = 1) +{ + model.write(range, ver); +}