Compare commits
6 Commits
7694fb0c03
...
15ce34ae19
Author | SHA1 | Date |
---|---|---|
Adrian | 15ce34ae19 | |
Adrian | 900d6df4ee | |
Adrian | e2d3285685 | |
Adrian | e246904835 | |
Adrian | 639ad2b418 | |
Adrian | f71ed9159e |
|
@ -1,3 +1,4 @@
|
||||||
[Dd]ebug
|
[Dd]ebug
|
||||||
[Rr]elease
|
[Rr]elease
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
packages
|
||||||
|
|
74
README.md
74
README.md
|
@ -1,30 +1,38 @@
|
||||||
# Age of Empires Scenario Editor
|
# Age of Empires Scenario Editor
|
||||||
|
|
||||||
Command line application and library to edit scenario and campaign files.
|
Command line application and library to edit Scenario and Campaign files
|
||||||
|
of games powered by the Genie Engine.
|
||||||
|
This includes the *Age of Empires* series and *Star Wars: Galactic Battlegrounds.*
|
||||||
|
|
||||||
**Alpha version**
|
**Beta version**
|
||||||
|
|
||||||
## Usage
|
# Command Line Application
|
||||||
|
|
||||||
Available commands are:
|
## Features
|
||||||
copymap Copy parts of scenarios
|
|
||||||
compress Recompress a decompressed scenario file
|
|
||||||
decompress Decompress a scenario file for hex editing
|
|
||||||
extract Extract scenarios from campaign file
|
|
||||||
dump Dump a scenario file to JSON
|
|
||||||
dumpunits Dump units and map tiles below
|
|
||||||
|
|
||||||
The command `copymap` is able convert an AOE1 to an AOE2 scenario.
|
* Convert AOE1 Scenario to AOE2 Scenario
|
||||||
There seem to be some issues with cliffs.
|
* Convert a Scenario file to JSON and vice-versa
|
||||||
|
* Decompress and recompress compressed Scenario part for hex editing
|
||||||
|
* Dump unit information to easily gather Unit IDs
|
||||||
|
* Extract Scenario files from Campaign file
|
||||||
|
|
||||||
|
## Planned Features
|
||||||
|
|
||||||
|
* Create maps from bitmaps
|
||||||
|
* Trigger implementation
|
||||||
|
* Full conversion between all Scenario versions
|
||||||
|
(mapping of Unit IDs are needed for this, see Section Contributing)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
[OpeningMoves-AOE2.scx](files/OpeningMoves-AOE2.scx)
|
[OpeningMoves-AOE2.scx](files/OpeningMoves-AOE2.scx)
|
||||||
is a fully automated conversion of a scenario from the AOE1 demo version:
|
is a fully automated conversion of a Scenario file from the AOE1 demo version:
|
||||||
|
|
||||||
$ GenieEdit.exe copymap files/examples/aoe2x-Empty.scx "files/examples/aoe1demo-Reigno_1-Opening Moves.scn" files/OpeningMoves-AOE2.scx
|
$ GenieEdit.exe convert files/examples/aoe2x-Empty.scx "files/examples/aoe1demo-Reigno_1-Opening Moves.scn" files/OpeningMoves-AOE2.scx
|
||||||
|
|
||||||
(Stone are set to 100 to be able to build a town center from the beginning.)
|
(Stone are set to 100 to be able to build a town center from the beginning.)
|
||||||
|
|
||||||
It can also be used to dump units from any version of a scenario:
|
A unit dump looks like the following:
|
||||||
|
|
||||||
$ GenieEdit.exe dumpunits Debug2.scx
|
$ GenieEdit.exe dumpunits Debug2.scx
|
||||||
Scenario Editor
|
Scenario Editor
|
||||||
|
@ -36,13 +44,37 @@ It can also be used to dump units from any version of a scenario:
|
||||||
1 69 23 ( 2,5, 11,5)
|
1 69 23 ( 2,5, 11,5)
|
||||||
...
|
...
|
||||||
|
|
||||||
### Code
|
# Library
|
||||||
|
|
||||||
Have a look at the command implementations. They are very short.
|
The namespace `AdrianKousz.GenieEngine` contains classes
|
||||||
|
to read, write, and manipulate Scenario files.
|
||||||
|
|
||||||
|
`Scenario` contains all data structures related to a Scenario file.
|
||||||
|
They are easily understandable.
|
||||||
|
|
||||||
|
The map is stored in linear order.
|
||||||
|
This way, it is easier to process seperate tiles.
|
||||||
|
The code below gets the map tile at (10,5).
|
||||||
|
The map origin (0,0) is in the left corner of the map:
|
||||||
|
|
||||||
|
![Map coordinate system](doc/MapCoord.png)
|
||||||
|
|
||||||
|
Scenario scn;
|
||||||
|
int x = 10;
|
||||||
|
int y = 5;
|
||||||
|
Scenario.ScnMap.Tile tile = scn.Map.LinearTiles[scn.Map.SizeX * y + x];
|
||||||
|
|
||||||
|
`GenieFile` is the starting point for reading and writing:
|
||||||
|
|
||||||
|
Scenario scn = GenieFile.Deserialize<Scenario>(filestream);
|
||||||
|
|
||||||
|
`ScnDefaultFactory` is a class that is able to produce an empty
|
||||||
|
Scenario file. Eventually, it should be able to create a `Scenario`
|
||||||
|
that is usable without any modifications.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Clone my projects MainUtil.cs ExUtil.cs and this repository
|
Clone the projects MainUtil.cs, ExUtil.cs, and this one,
|
||||||
and build `src/GenieEdit.sln`.
|
and build `src/GenieEdit.sln`.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
@ -53,12 +85,10 @@ Keep in mind that the API is still very unstable.
|
||||||
Suggestions:
|
Suggestions:
|
||||||
|
|
||||||
1. Gather UnitIDs of AOE1
|
1. Gather UnitIDs of AOE1
|
||||||
2. Much help is appreciated to figure out ID mappings
|
2. Much help is appreciated to figure out Unit ID mappings
|
||||||
for the conversion process.
|
for the conversion process.
|
||||||
3. Ideas how to configure the converter (mapping tables).
|
3. Ideas how to configure the converter (mapping tables).
|
||||||
There are some notes in German:
|
There are some notes in German:
|
||||||
[AOE1](files/units-aoe1.txt),
|
[AOE1](files/units-aoe1.txt),
|
||||||
[AOE2](files/units-aoe2.txt)
|
[AOE2](files/units-aoe2.txt)
|
||||||
3. The application should be able to generate maps from images
|
3. Feedback about the API.
|
||||||
in the future. How should units be placed using the image?
|
|
||||||
4. Feedback about the API.
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
@ -31,14 +31,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="src\Program.cs" />
|
<Compile Include="src\Program.cs" />
|
||||||
<Compile Include="src\DecompressCommand.cs" />
|
|
||||||
<Compile Include="src\BaseCommand.cs" />
|
<Compile Include="src\BaseCommand.cs" />
|
||||||
<Compile Include="src\CompressCommand.cs" />
|
|
||||||
<Compile Include="src\ExtractCommand.cs" />
|
<Compile Include="src\ExtractCommand.cs" />
|
||||||
<Compile Include="src\DumpCommand.cs" />
|
<Compile Include="src\ToJsonCommand.cs" />
|
||||||
<Compile Include="src\CopymapCommand.cs" />
|
<Compile Include="src\FromJsonCommand.cs" />
|
||||||
|
<Compile Include="src\CompressCommand.cs" />
|
||||||
|
<Compile Include="src\DecompressCommand.cs" />
|
||||||
<Compile Include="src\DumpunitsCommand.cs" />
|
<Compile Include="src\DumpunitsCommand.cs" />
|
||||||
<Compile Include="src\CopymapConverter.cs" />
|
<Compile Include="src\CopymapConverter.cs" />
|
||||||
|
<Compile Include="src\ConvertCommand.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -61,5 +62,11 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Web.Extensions" />
|
<Reference Include="System.Web.Extensions" />
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net45" />
|
||||||
|
</packages>
|
|
@ -7,20 +7,10 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
override public void Run()
|
override public void Run()
|
||||||
{
|
{
|
||||||
using (var file = File.OpenRead(args[0])) {
|
using (var input = File.OpenRead(args[0]))
|
||||||
using (var outfile = File.OpenWrite(args[1])) {
|
using (var output = File.OpenWrite(args[1]))
|
||||||
var reader = new ScnReader(file);
|
{
|
||||||
var writer = new ScnWriter(outfile);
|
GenieFile.ScenarioCompression(input, output, false);
|
||||||
|
|
||||||
var header = reader.ReadScenarioHeader();
|
|
||||||
reader.ReadSeparator("Custom");
|
|
||||||
writer.Write(header);
|
|
||||||
writer.Flush();
|
|
||||||
|
|
||||||
using (var comp = new DeflateStream(outfile, CompressionMode.Compress)) {
|
|
||||||
file.CopyTo(comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class ConvertCommand : BaseCommand
|
||||||
|
{
|
||||||
|
override public void Run()
|
||||||
|
{
|
||||||
|
using (var refstream = File.OpenRead(args[0]))
|
||||||
|
using (var srcstream = File.OpenRead(args[1]))
|
||||||
|
using (var outstream = File.OpenWrite(args[2]))
|
||||||
|
{
|
||||||
|
var refscn = GenieFile.Deserialize<Scenario>(refstream);
|
||||||
|
var srcscn = GenieFile.Deserialize<Scenario>(srcstream);
|
||||||
|
|
||||||
|
srcscn.VersionString = refscn.VersionString;
|
||||||
|
srcscn.VersionNumber = refscn.VersionNumber;
|
||||||
|
srcscn.RawIndividualVictory = refscn.RawIndividualVictory;
|
||||||
|
srcscn.RawDisables = refscn.RawDisables;
|
||||||
|
srcscn.RawRemaining = refscn.RawRemaining;
|
||||||
|
|
||||||
|
srcscn.PlayerSettings.ForEach(x => {
|
||||||
|
x.FilenameAI = "RandomGame";
|
||||||
|
x.FilenameCTY = x.FilenamePER = "";
|
||||||
|
x.ScriptAI = x.ScriptCTY = x.ScriptPER = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
var converter = new CopymapConverter();
|
||||||
|
converter.Convert(srcscn);
|
||||||
|
|
||||||
|
GenieFile.Serialize(srcscn, outstream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public int GetArgumentCount()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetDescription()
|
||||||
|
{
|
||||||
|
return "Convert AOE1 scenario";
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetHelp()
|
||||||
|
{
|
||||||
|
return "Convert AOE1 scenario to AOE2"
|
||||||
|
+ "\n"
|
||||||
|
+ "\nThe converter needs an existing AOE2 scenario to start with. Use the following arguments:"
|
||||||
|
+ "\n<AOE2 reference scenario> <AOE1 scenario> <output scenario>"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,57 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class CopymapCommand : BaseCommand
|
|
||||||
{
|
|
||||||
override public void Run()
|
|
||||||
{
|
|
||||||
Data.Scenario result;
|
|
||||||
using (var dststream = File.OpenRead(args[0]))
|
|
||||||
using (var srcstream = File.OpenRead(args[1]))
|
|
||||||
{
|
|
||||||
var srcreader = new ScnReader(srcstream);
|
|
||||||
var src = srcreader.ReadScenario();
|
|
||||||
var dstreader = new ScnReader(dststream);
|
|
||||||
var dst = dstreader.ReadScenario();
|
|
||||||
var converter = new CopymapConverter();
|
|
||||||
dst.PlayerNames = src.PlayerNames;
|
|
||||||
dst.StringTablePlayerNames = src.StringTablePlayerNames;
|
|
||||||
dst.Players = src.Players;
|
|
||||||
dst.Resources = src.Resources;
|
|
||||||
dst.ResourcesCopy = src.ResourcesCopy;
|
|
||||||
dst.Messages = src.Messages;
|
|
||||||
converter.Convert(dst, src);
|
|
||||||
result = dst;
|
|
||||||
}
|
|
||||||
using (var outstream = File.OpenWrite(args[2])) {
|
|
||||||
var outwriter = new ScnWriter(outstream);
|
|
||||||
outwriter.Write(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public int GetArgumentCount()
|
|
||||||
{
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public string GetDescription()
|
|
||||||
{
|
|
||||||
return "Copy parts of scenarios";
|
|
||||||
}
|
|
||||||
|
|
||||||
override public string GetHelp()
|
|
||||||
{
|
|
||||||
return "Copy the parts below from scenario file 2 into scenario file 1."
|
|
||||||
+ "\nThe result is written to scenario file 3."
|
|
||||||
+ "\n- Messages"
|
|
||||||
+ "\n- Player information"
|
|
||||||
+ "\n- Resources"
|
|
||||||
+ "\n- Map"
|
|
||||||
+ "\n- Units"
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AdrianKousz.Util;
|
using AdrianKousz.Util;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
public class CopymapConverter
|
public class CopymapConverter
|
||||||
{
|
{
|
||||||
public void Convert(Scenario dst, Scenario src)
|
public void Convert(Scenario scn)
|
||||||
{
|
{
|
||||||
dst.Map = src.Map;
|
scn.Units = ChangeUnits_AOE1_AOE2(scn.Units);
|
||||||
dst.Units = ChangeUnits_AOE1_AOE2(src.Units);
|
MoveUnits_AOE1_AOE2(scn.Units);
|
||||||
MoveUnits_AOE1_AOE2(dst.Units);
|
ChangeTiles_AOE1_AOE2(scn.Units, scn.Map);
|
||||||
ChangeTiles_AOE1_AOE2(dst.Units, dst.Map);
|
RandomizeTrees_AOE2(scn.Units);
|
||||||
RandomizeTrees_AOE2(dst.Units);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some buildings are not the same size.
|
* Some buildings are not the same size.
|
||||||
* They need to be moved by half a unit.
|
* They need to be moved by half a unit.
|
||||||
*/
|
*/
|
||||||
private void MoveUnits_AOE1_AOE2(IList<UnitInfo>[] units)
|
private void MoveUnits_AOE1_AOE2(IList<Scenario.ScnUnit>[] units)
|
||||||
{
|
{
|
||||||
var mapping = new int[] {
|
var mapping = new int[] {
|
||||||
// Towers
|
// Towers
|
||||||
|
@ -43,7 +41,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
/**
|
/**
|
||||||
* Simple mapping of unit IDs
|
* Simple mapping of unit IDs
|
||||||
*/
|
*/
|
||||||
private List<UnitInfo>[] ChangeUnits_AOE1_AOE2(IList<UnitInfo>[] units)
|
private List<Scenario.ScnUnit>[] ChangeUnits_AOE1_AOE2(IList<Scenario.ScnUnit>[] units)
|
||||||
{
|
{
|
||||||
var array = new int[] {
|
var array = new int[] {
|
||||||
// Resources
|
// Resources
|
||||||
|
@ -142,18 +140,17 @@ namespace AdrianKousz.GenieEngine
|
||||||
121, 121,
|
121, 121,
|
||||||
129, 129,
|
129, 129,
|
||||||
};
|
};
|
||||||
var mapping = new Dictionary<int, int>();
|
var mapping = new Dictionary<short, short>();
|
||||||
var ai = 0;
|
var ai = 0;
|
||||||
while (ai < array.Length)
|
while (ai < array.Length)
|
||||||
mapping.Add(array[ai++], array[ai++]);
|
mapping.Add((short)array[ai++], (short)array[ai++]);
|
||||||
|
|
||||||
var result = new List<UnitInfo>[Scenario.NumPlayerSections];
|
var result = new List<Scenario.ScnUnit>[Scenario.NumPlayerSections].Fill();
|
||||||
result.Fill();
|
|
||||||
|
|
||||||
units.ForEach((i, list) => {
|
units.ForEach((i, list) => {
|
||||||
list.ForEach((j, unit) => {
|
list.ForEach((j, unit) => {
|
||||||
if (mapping.ContainsKey(unit.UnitId)) {
|
if (mapping.ContainsKey(unit.UnitId)) {
|
||||||
unit.UnitId = (short)mapping[unit.UnitId];
|
unit.UnitId = mapping[unit.UnitId];
|
||||||
result[i].Add(unit);
|
result[i].Add(unit);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -165,7 +162,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
/**
|
/**
|
||||||
* Farms need to be converted including the underlying terrain.
|
* Farms need to be converted including the underlying terrain.
|
||||||
*/
|
*/
|
||||||
private void ChangeTiles_AOE1_AOE2(IList<UnitInfo>[] units, Map map)
|
private void ChangeTiles_AOE1_AOE2(IList<Scenario.ScnUnit>[] units, Scenario.ScnMap map)
|
||||||
{
|
{
|
||||||
units.ForEach((i, list) => {
|
units.ForEach((i, list) => {
|
||||||
list.ForEach((j, unit) => {
|
list.ForEach((j, unit) => {
|
||||||
|
@ -175,6 +172,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
if (false) {
|
if (false) {
|
||||||
// switch
|
// switch
|
||||||
} else if (unit.UnitId == 50) {
|
} else if (unit.UnitId == 50) {
|
||||||
|
// Farm
|
||||||
map.LinearTiles[linearpos].Id = 7;
|
map.LinearTiles[linearpos].Id = 7;
|
||||||
map.LinearTiles[linearpos - 1].Id = 7;
|
map.LinearTiles[linearpos - 1].Id = 7;
|
||||||
map.LinearTiles[linearpos + 1].Id = 7;
|
map.LinearTiles[linearpos + 1].Id = 7;
|
||||||
|
@ -200,7 +198,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
* Forests would contain the same tree graphic
|
* Forests would contain the same tree graphic
|
||||||
* without this function
|
* without this function
|
||||||
*/
|
*/
|
||||||
private void RandomizeTrees_AOE2(IList<UnitInfo>[] units)
|
private void RandomizeTrees_AOE2(IList<Scenario.ScnUnit>[] units)
|
||||||
{
|
{
|
||||||
var treeids = new int[] {
|
var treeids = new int[] {
|
||||||
411, 351, 414, 350, 348, 349,
|
411, 351, 414, 350, 348, 349,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
|
@ -7,20 +6,10 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
override public void Run()
|
override public void Run()
|
||||||
{
|
{
|
||||||
using (var file = File.OpenRead(args[0])) {
|
using (var input = File.OpenRead(args[0]))
|
||||||
using (var outfile = File.OpenWrite(args[1])) {
|
using (var output = File.OpenWrite(args[1]))
|
||||||
var reader = new ScnReader(file);
|
{
|
||||||
var writer = new ScnWriter(outfile);
|
GenieFile.ScenarioCompression(input, output, true);
|
||||||
|
|
||||||
var header = reader.ReadScenarioHeader();
|
|
||||||
writer.Write(header);
|
|
||||||
writer.WriteSeperator("Custom");
|
|
||||||
writer.Flush();
|
|
||||||
|
|
||||||
using (var comp = new DeflateStream(file, CompressionMode.Decompress)) {
|
|
||||||
comp.CopyTo(outfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class DumpCommand : BaseCommand
|
|
||||||
{
|
|
||||||
override public void Run()
|
|
||||||
{
|
|
||||||
using (var stream = File.OpenRead(args[0])) {
|
|
||||||
var aoereader = new ScnReader(stream);
|
|
||||||
var scn = aoereader.ReadScenario();
|
|
||||||
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
|
|
||||||
var result = ser.Serialize(scn);
|
|
||||||
Console.WriteLine(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public int GetArgumentCount()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public string GetDescription()
|
|
||||||
{
|
|
||||||
return "Dump a scenario file to JSON";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AdrianKousz.Util;
|
using AdrianKousz.Util;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
|
@ -11,9 +10,9 @@ namespace AdrianKousz.GenieEngine
|
||||||
override public void Run()
|
override public void Run()
|
||||||
{
|
{
|
||||||
Scenario scn;
|
Scenario scn;
|
||||||
using (var stream = File.OpenRead(args[0])) {
|
using (var input = File.OpenRead(args[0]))
|
||||||
var aoereader = new ScnReader(stream);
|
{
|
||||||
scn = aoereader.ReadScenario();
|
scn = GenieFile.Deserialize<Scenario>(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position");
|
Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position");
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class FromJsonCommand : BaseCommand
|
||||||
|
{
|
||||||
|
override public void Run()
|
||||||
|
{
|
||||||
|
using (var input = File.OpenRead(args[0]))
|
||||||
|
using (var reader = input.GetReader())
|
||||||
|
using (var output = File.OpenWrite(args[1]))
|
||||||
|
{
|
||||||
|
var str = reader.ReadToEnd();
|
||||||
|
var scn = JsonConvert.DeserializeObject<Scenario>(str);
|
||||||
|
GenieFile.Serialize(scn, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public int GetArgumentCount()
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetDescription()
|
||||||
|
{
|
||||||
|
return "Read a JSON file and save as scenario";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,11 +25,12 @@ namespace AdrianKousz.GenieEngine
|
||||||
public IDictionary<string, ICommand<string[]>> GetCommands()
|
public IDictionary<string, ICommand<string[]>> GetCommands()
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, ICommand<string[]>>();
|
var result = new Dictionary<string, ICommand<string[]>>();
|
||||||
result.Add("copymap", new CopymapCommand());
|
result.Add("convert", new ConvertCommand());
|
||||||
result.Add("compress", new CompressCommand());
|
result.Add("compress", new CompressCommand());
|
||||||
result.Add("decompress", new DecompressCommand());
|
result.Add("decompress", new DecompressCommand());
|
||||||
result.Add("extract", new ExtractCommand());
|
result.Add("extract", new ExtractCommand());
|
||||||
result.Add("dump", new DumpCommand());
|
result.Add("tojson", new ToJsonCommand());
|
||||||
|
result.Add("fromjson", new FromJsonCommand());
|
||||||
result.Add("dumpunits", new DumpunitsCommand());
|
result.Add("dumpunits", new DumpunitsCommand());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -38,8 +39,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
var fn = "";
|
var fn = "";
|
||||||
using (var istream = System.IO.File.OpenRead(fn)) {
|
using (var istream = System.IO.File.OpenRead(fn)) {
|
||||||
var ireader = new ScnReader(istream);
|
var scn = GenieFile.Deserialize<Scenario>(istream);
|
||||||
var scn = ireader.ReadScenario();
|
|
||||||
System.Diagnostics.Debugger.Break(); // Great to inspect scn
|
System.Diagnostics.Debugger.Break(); // Great to inspect scn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class ToJsonCommand : BaseCommand
|
||||||
|
{
|
||||||
|
override public void Run()
|
||||||
|
{
|
||||||
|
using (var input = File.OpenRead(args[0]))
|
||||||
|
using (var output = File.OpenWrite(args[1]))
|
||||||
|
using (var writer = output.GetWriter())
|
||||||
|
{
|
||||||
|
var scn = GenieFile.Deserialize<Scenario>(input);
|
||||||
|
var result = JsonConvert.SerializeObject(scn, Formatting.Indented);
|
||||||
|
writer.WriteLine(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public int GetArgumentCount()
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetDescription()
|
||||||
|
{
|
||||||
|
return "Dump a scenario file to JSON";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using AdrianKousz.Util;
|
using AdrianKousz.Util;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public static class GenieFile
|
||||||
|
{
|
||||||
|
#region Serialization
|
||||||
|
|
||||||
|
public static byte[] Serialize<T>(T value)
|
||||||
|
{
|
||||||
|
byte[] result;
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
Serialize(value, stream);
|
||||||
|
result = stream.ToArray();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Serialize<T>(T value, Stream output)
|
||||||
|
{
|
||||||
|
var scenarioValue = value as Scenario;
|
||||||
|
if (scenarioValue != null) {
|
||||||
|
var scnwriter = ScnSerializerWriter.CreateDefault();
|
||||||
|
using (var stream = new NonDisposingStreamWrapper(output))
|
||||||
|
using (var writer = GetWriter(stream))
|
||||||
|
{
|
||||||
|
scnwriter.Write(writer, scenarioValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new System.ArgumentException("Unsupported Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Deserialization
|
||||||
|
|
||||||
|
public static T Deserialize<T>(byte[] array)
|
||||||
|
{
|
||||||
|
return (T)Deserialize(array, typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Deserialize<T>(Stream input)
|
||||||
|
{
|
||||||
|
return (T)Deserialize(input, typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object Deserialize(byte[] array, System.Type type)
|
||||||
|
{
|
||||||
|
using (var stream = new MemoryStream(array))
|
||||||
|
{
|
||||||
|
return Deserialize(stream, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object Deserialize(Stream input, System.Type type)
|
||||||
|
{
|
||||||
|
if (type == typeof(Scenario)) {
|
||||||
|
var scnreader = ScnSerializerReader.CreateDefault();
|
||||||
|
using (var stream = new NonDisposingStreamWrapper(input))
|
||||||
|
using (var reader = GetReader(stream))
|
||||||
|
{
|
||||||
|
return scnreader.ReadScenario(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new System.ArgumentException("Unsupported Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Low Level Methods
|
||||||
|
|
||||||
|
public static ExtendedBinaryReader GetReader(Stream stream)
|
||||||
|
{
|
||||||
|
return new ExtendedBinaryReader(stream, Scenario.Encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExtendedBinaryWriter GetWriter(Stream stream)
|
||||||
|
{
|
||||||
|
return new ExtendedBinaryWriter(stream, Scenario.Encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ScenarioCompression(Stream input, Stream output, bool decompress)
|
||||||
|
{
|
||||||
|
var mode = decompress ? CompressionMode.Decompress : CompressionMode.Compress;
|
||||||
|
|
||||||
|
byte[] buffer;
|
||||||
|
|
||||||
|
buffer = input.ReadBytes(8);
|
||||||
|
output.Write(buffer);
|
||||||
|
|
||||||
|
var headerLength = buffer[4]
|
||||||
|
| buffer[5] << 8
|
||||||
|
| buffer[6] << 16
|
||||||
|
| buffer[7] << 24
|
||||||
|
;
|
||||||
|
|
||||||
|
buffer = input.ReadBytes(headerLength);
|
||||||
|
output.Write(buffer);
|
||||||
|
|
||||||
|
using (var comp = new DeflateStream(input, mode))
|
||||||
|
{
|
||||||
|
comp.CopyTo(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System;
|
namespace AdrianKousz.GenieEngine
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
{
|
||||||
public interface IScnFactory
|
public interface IScnFactory
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
public const Int32 Separator = -99;
|
public const Int32 Separator = -99;
|
||||||
public const Int32 NumPlayers = 16;
|
public const Int32 NumPlayers = 16;
|
||||||
public const Int32 NumPlayerSections = 9;
|
public const Int32 NumPlayerSections = 9;
|
||||||
public const Encoding Encoding = Encoding.GetEncoding(1252);
|
public static readonly Encoding Encoding = Encoding.GetEncoding(1252);
|
||||||
|
|
||||||
public const Int32 ExpectedUnknown1 = 2;
|
public const Int32 ExpectedUnknown1 = 2;
|
||||||
public const Int32 ExpectedUnknown2 = 0;
|
public const Int32 ExpectedUnknown2 = 0;
|
||||||
|
@ -117,11 +117,11 @@ namespace AdrianKousz.GenieEngine
|
||||||
public Int32 Artifacts;
|
public Int32 Artifacts;
|
||||||
public Int32 Discovery;
|
public Int32 Discovery;
|
||||||
public Int32 PercentExplored;
|
public Int32 PercentExplored;
|
||||||
public Int32 Unknown;
|
|
||||||
public Boolean RequireAllCustom;
|
public Boolean RequireAllCustom;
|
||||||
public Int32 Mode;
|
public Int32 Mode;
|
||||||
public Int32 Score;
|
public Int32 Score;
|
||||||
public Int32 Time;
|
public Int32 Time;
|
||||||
|
public Int32 Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ScnResourceCopy
|
public class ScnResourceCopy
|
||||||
|
@ -166,17 +166,17 @@ namespace AdrianKousz.GenieEngine
|
||||||
public class ScnUnit
|
public class ScnUnit
|
||||||
{
|
{
|
||||||
public const Single ExpectedUnknown1 = 1;
|
public const Single ExpectedUnknown1 = 1;
|
||||||
public const Byte ExpectedUnknown2 = 2;
|
public const SByte ExpectedUnknown2 = 2;
|
||||||
|
|
||||||
public Single PosX;
|
public Single PosX;
|
||||||
public Single PosY;
|
public Single PosY;
|
||||||
public Single Unknown1;
|
|
||||||
public Int32 Id;
|
public Int32 Id;
|
||||||
public Int16 UnitId;
|
public Int16 UnitId;
|
||||||
public Byte Unknown2;
|
|
||||||
public Single Rotation;
|
public Single Rotation;
|
||||||
public Int16 InitialFrame;
|
public Int16 InitialFrame;
|
||||||
public Int32 GarrisonnedInId;
|
public Int32 GarrisonnedInId;
|
||||||
|
public Single Unknown1;
|
||||||
|
public SByte Unknown2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
using System;
|
|
||||||
using AdrianKousz.Util;
|
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class ScnConvert
|
|
||||||
{
|
|
||||||
public void Convert(Scenario value, float version)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public void Convert(UnitInfo value, float from, float to)
|
|
||||||
{
|
|
||||||
if (from < 1.18f && to >= 1.18f) {
|
|
||||||
value.InitialFrame = 0;
|
|
||||||
value.GarrisonnedInId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
result.GeneratorId = 2;
|
result.GeneratorId = 2;
|
||||||
result.SizeX = size;
|
result.SizeX = size;
|
||||||
result.SizeY = size;
|
result.SizeY = size;
|
||||||
result.LinearTiles = new Map.Tile[size*size].Fill(() => new Map.Tile(0, 1, 0));
|
result.LinearTiles = new Scenario.ScnMap.Tile[size*size].Fill(() => new Scenario.ScnMap.Tile(0, 1, 0));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,327 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using AdrianKousz.Util;
|
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class ScnReader
|
|
||||||
{
|
|
||||||
public float Version = 0;
|
|
||||||
|
|
||||||
private ExtendedBinaryReader reader;
|
|
||||||
private IScnFactory factory;
|
|
||||||
|
|
||||||
public ScnReader(Stream input) : this (input, new ScnDefaultFactory())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScnReader(Stream input, IScnFactory factory)
|
|
||||||
{
|
|
||||||
reader = new ExtendedBinaryReader(input, Scenario.Encoding);
|
|
||||||
this.factory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Reader Methods
|
|
||||||
|
|
||||||
public Scenario ReadScenario()
|
|
||||||
{
|
|
||||||
var result = factory.MakeScenario(false);
|
|
||||||
int number = 0;
|
|
||||||
|
|
||||||
result.Header = ReadScenarioHeader();
|
|
||||||
|
|
||||||
var comp = new DeflateStream(reader.BaseStream, CompressionMode.Decompress);
|
|
||||||
reader = new ExtendedBinaryReader(comp, Scenario.Encoding);
|
|
||||||
|
|
||||||
result.NextId = reader.ReadInt32();
|
|
||||||
|
|
||||||
Version = reader.ReadSingle();
|
|
||||||
result.OriginalVersion = Version;
|
|
||||||
|
|
||||||
result.PlayerNames = FillArray(() => reader.ReadZString(256), result.PlayerNames, Scenario.NumPlayers);
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.StringTablePlayerNames = FillArray(reader.ReadInt32, result.StringTablePlayerNames, Scenario.NumPlayers);
|
|
||||||
}
|
|
||||||
result.Players = FillArray(ReadPlayerInfo, result.Players, Scenario.NumPlayers);
|
|
||||||
result.Messages = ReadMessages();
|
|
||||||
result.Cinematics = ReadCinematics();
|
|
||||||
result.AIData = ReadAIData();
|
|
||||||
|
|
||||||
ReadSeparator("Resources");
|
|
||||||
|
|
||||||
result.Resources = FillArray(ReadResourceInfo, result.Resources, Scenario.NumPlayers);
|
|
||||||
|
|
||||||
ReadSeparator("Victory");
|
|
||||||
|
|
||||||
result.GlobalVictory = ReadGlobalVictoryInfo();
|
|
||||||
result.LinearDiplomacy = FillArray(reader.ReadInt32, result.LinearDiplomacy, Scenario.NumPlayers * Scenario.NumPlayers);
|
|
||||||
result.RawIndividualVictory = reader.ReadBytes(11520);
|
|
||||||
|
|
||||||
ReadSeparator("Player Settings");
|
|
||||||
|
|
||||||
result.AlliedVictory = FillArray(reader.ReadInt32, result.AlliedVictory, Scenario.NumPlayers);
|
|
||||||
|
|
||||||
if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
|
||||||
if (Version >= 1.18f) number = (Scenario.NumPlayers * (3 /*Lengths*/ + 80 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
|
||||||
if (Version >= 1.30f) number = (Scenario.NumPlayers * (3 /*Lengths*/ + 180 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
|
||||||
result.RawDisables = reader.ReadBytes(number);
|
|
||||||
|
|
||||||
result.StartingAges = FillArray(reader.ReadInt32, result.StartingAges, Scenario.NumPlayers);
|
|
||||||
|
|
||||||
ReadSeparator("Map");
|
|
||||||
|
|
||||||
result.Map = ReadMap();
|
|
||||||
|
|
||||||
number = reader.ReadInt32();
|
|
||||||
result.ResourcesCopy = FillArray(ReadResourceInfoCopy, result.ResourcesCopy, number - 1);
|
|
||||||
|
|
||||||
result.Units = FillArray(ReadUnitInfoList, result.Units, number);
|
|
||||||
|
|
||||||
var bytestream = new MemoryStream();
|
|
||||||
reader.BaseStream.CopyTo(bytestream);
|
|
||||||
result.RawRemaining = bytestream.ToArray();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScenarioHeader ReadScenarioHeader()
|
|
||||||
{
|
|
||||||
var result = factory.MakeScenarioHeader();
|
|
||||||
|
|
||||||
result.OriginalVersion = reader.ReadString(4);
|
|
||||||
reader.ReadInt32(); // Header Length
|
|
||||||
result.Unknown1 = reader.ReadInt32();
|
|
||||||
result.Timestamp = DateTimes.FromUnixTime(reader.ReadInt32());
|
|
||||||
result.Instructions = reader.ReadZStringInt32();
|
|
||||||
result.Unknown2 = reader.ReadInt32();
|
|
||||||
result.PlayerCount = reader.ReadInt32();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerInfo ReadPlayerInfo()
|
|
||||||
{
|
|
||||||
var result = factory.MakePlayerInfo();
|
|
||||||
|
|
||||||
result.Active = reader.ReadBoolean();
|
|
||||||
result.Human = reader.ReadBoolean();
|
|
||||||
result.Civ = reader.ReadInt32();
|
|
||||||
result.Unknown = reader.ReadInt32();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Messages ReadMessages()
|
|
||||||
{
|
|
||||||
var result = factory.MakeMessages();
|
|
||||||
|
|
||||||
result.Unknown1 = reader.ReadInt32();
|
|
||||||
result.Unknown2 = reader.ReadByte();
|
|
||||||
result.Unknown3 = reader.ReadSingle();
|
|
||||||
result.OriginalFilename = reader.ReadStringInt16();
|
|
||||||
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.StringTableInstructions = reader.ReadInt32();
|
|
||||||
result.StringTableHints = reader.ReadInt32();
|
|
||||||
result.StringTableVictory = reader.ReadInt32();
|
|
||||||
result.StringTableLoss = reader.ReadInt32();
|
|
||||||
result.StringTableHistory = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
result.StringTableScouts = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.TextInstructions = reader.ReadZStringInt16();
|
|
||||||
result.TextHints = reader.ReadZStringInt16();
|
|
||||||
result.TextVictory = reader.ReadZStringInt16();
|
|
||||||
result.TextLoss = reader.ReadZStringInt16();
|
|
||||||
result.TextHistory = reader.ReadZStringInt16();
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
result.TextScouts = reader.ReadZStringInt16();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cinematics ReadCinematics()
|
|
||||||
{
|
|
||||||
var result = factory.MakeCinematics();
|
|
||||||
|
|
||||||
result.CinemaPregameFn = reader.ReadStringInt16();
|
|
||||||
result.CinemaVictoryFn = reader.ReadStringInt16();
|
|
||||||
result.CinemaLossFn = reader.ReadStringInt16();
|
|
||||||
result.BackgroundFn = reader.ReadStringInt16();
|
|
||||||
|
|
||||||
var hasBitmap = reader.ReadBoolean();
|
|
||||||
|
|
||||||
result.BitmapWidth = reader.ReadInt32();
|
|
||||||
result.BitmapHeight = reader.ReadInt32();
|
|
||||||
result.BitmapUnknown = reader.ReadInt16();
|
|
||||||
|
|
||||||
if (hasBitmap) {
|
|
||||||
result.RawBitmap = BitmapUtil.ReadRawBitmap(reader.BaseStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AIData ReadAIData()
|
|
||||||
{
|
|
||||||
var result = factory.MakeAIData();
|
|
||||||
|
|
||||||
result.PlayerAIs = FillArray(reader.ReadStringInt16, result.PlayerAIs, Scenario.NumPlayers);
|
|
||||||
result.PlayerCTYs = FillArray(reader.ReadStringInt16, result.PlayerCTYs, Scenario.NumPlayers);
|
|
||||||
result.PlayerPERs = FillArray(reader.ReadStringInt16, result.PlayerPERs, Scenario.NumPlayers);
|
|
||||||
|
|
||||||
result.PlayerCustomAIs = new string[Scenario.NumPlayers];
|
|
||||||
result.PlayerCustomCTYs = new string[Scenario.NumPlayers];
|
|
||||||
result.PlayerCustomPERs = new string[Scenario.NumPlayers];
|
|
||||||
|
|
||||||
int l1, l2, l3;
|
|
||||||
for (var i = 0; i < Scenario.NumPlayers; ++i) {
|
|
||||||
l1 = reader.ReadInt32();
|
|
||||||
l2 = reader.ReadInt32();
|
|
||||||
l3 = reader.ReadInt32();
|
|
||||||
result.PlayerCustomAIs[i] = reader.ReadString(l1);
|
|
||||||
result.PlayerCustomCTYs[i] = reader.ReadString(l2);
|
|
||||||
result.PlayerCustomPERs[i] = reader.ReadString(l3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.AITypes = FillArray(reader.ReadByte, result.AITypes, Scenario.NumPlayers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceInfo ReadResourceInfo()
|
|
||||||
{
|
|
||||||
var result = factory.MakeResourceInfo();
|
|
||||||
|
|
||||||
result.Gold = reader.ReadInt32();
|
|
||||||
result.Wood = reader.ReadInt32();
|
|
||||||
result.Food = reader.ReadInt32();
|
|
||||||
result.Stone = reader.ReadInt32();
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.Ore = reader.ReadInt32();
|
|
||||||
if (Version < 1.3f) {
|
|
||||||
result.Unknown = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceInfoCopy ReadResourceInfoCopy()
|
|
||||||
{
|
|
||||||
var result = factory.MakeResourceInfoCopy();
|
|
||||||
|
|
||||||
result.Food = reader.ReadSingle();
|
|
||||||
result.Wood = reader.ReadSingle();
|
|
||||||
result.Gold = reader.ReadSingle();
|
|
||||||
result.Stone = reader.ReadSingle();
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.Ore = reader.ReadInt32();
|
|
||||||
if (Version < 1.3f) {
|
|
||||||
result.Unknown = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
result.PopulationLimit = reader.ReadSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlobalVictoryInfo ReadGlobalVictoryInfo()
|
|
||||||
{
|
|
||||||
var result = factory.MakeGlobalVictoryInfo();
|
|
||||||
|
|
||||||
result.RequireConquest = reader.ReadBoolean();
|
|
||||||
result.Ruins = reader.ReadInt32();
|
|
||||||
result.Artifacts = reader.ReadInt32();
|
|
||||||
result.Discovery = reader.ReadInt32();
|
|
||||||
result.PercentExplored = reader.ReadInt32();
|
|
||||||
result.Unknown = reader.ReadInt32();
|
|
||||||
result.RequireAllCustom = reader.ReadBoolean();
|
|
||||||
result.Mode = reader.ReadInt32();
|
|
||||||
result.Score = reader.ReadInt32();
|
|
||||||
result.Time = reader.ReadInt32();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map ReadMap()
|
|
||||||
{
|
|
||||||
var result = factory.MakeMap();
|
|
||||||
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.CameraX = reader.ReadInt32();
|
|
||||||
result.CameraY = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
result.GeneratorId = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.SizeX = reader.ReadInt32();
|
|
||||||
result.SizeY = reader.ReadInt32();
|
|
||||||
|
|
||||||
result.LinearTiles = new Map.Tile[result.SizeX * result.SizeY]
|
|
||||||
.Fill(() => new Map.Tile(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<UnitInfo> ReadUnitInfoList()
|
|
||||||
{
|
|
||||||
var count = reader.ReadInt32();
|
|
||||||
var result = new List<UnitInfo>().Fill(ReadUnitInfo, count);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnitInfo ReadUnitInfo()
|
|
||||||
{
|
|
||||||
var result = factory.MakeUnitInfo();
|
|
||||||
|
|
||||||
result.PosX = reader.ReadSingle();
|
|
||||||
result.PosY = reader.ReadSingle();
|
|
||||||
result.Unknown1 = reader.ReadSingle();
|
|
||||||
result.Id = reader.ReadInt32();
|
|
||||||
result.UnitId = reader.ReadInt16();
|
|
||||||
result.Unknown2 = reader.ReadByte();
|
|
||||||
result.Rotation = reader.ReadSingle();
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
result.InitialFrame = reader.ReadInt16();
|
|
||||||
result.GarrisonnedInId = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReadSeparator(string name) {
|
|
||||||
int v = reader.ReadInt32();
|
|
||||||
if (v != Scenario.Separator) {
|
|
||||||
var msg = "Separator \"{0}\" = {1}";
|
|
||||||
msg = string.Format(msg, name, v);
|
|
||||||
throw new InvalidDataException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Debug Methods
|
|
||||||
|
|
||||||
private T[] FillArray<T>(System.Func<T> f, T[] array, int length)
|
|
||||||
{
|
|
||||||
if (array == null || array.Length != length)
|
|
||||||
array = new T[length];
|
|
||||||
array.Fill(f);
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ using AdrianKousz.Util;
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
public class ScnSerializerReader
|
internal class ScnSerializerReader
|
||||||
{
|
{
|
||||||
private IScnFactory factory;
|
private IScnFactory factory;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
var Version = 0f;
|
var Version = 0f;
|
||||||
var number = 0;
|
var number = 0;
|
||||||
var result = factory is ScnDefaultFactory
|
var result = factory is ScnDefaultFactory
|
||||||
? factory.MakeScenario(false)
|
? ((ScnDefaultFactory)factory).MakeScenario(false)
|
||||||
: factory.MakeScenario();
|
: factory.MakeScenario();
|
||||||
|
|
||||||
// Uncompressed header
|
// Uncompressed header
|
||||||
|
@ -180,7 +180,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
// PlayerSettings 3
|
// PlayerSettings 3
|
||||||
|
|
||||||
result.PlayerSettings.ForEach(x => {
|
result.PlayerSettings.ForEach(x => {
|
||||||
x.Diplomacy = new int[Scenario.NumPlayers].Fill(reader.ReadInt32());
|
x.Diplomacy = new int[Scenario.NumPlayers].Fill(reader.ReadInt32);
|
||||||
});
|
});
|
||||||
|
|
||||||
result.RawIndividualVictory = reader.ReadBytes(11520);
|
result.RawIndividualVictory = reader.ReadBytes(11520);
|
||||||
|
@ -188,7 +188,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
ReadSeparator(reader, "Player Environment");
|
ReadSeparator(reader, "Player Environment");
|
||||||
|
|
||||||
result.PlayerSettings.ForEach(x => {
|
result.PlayerSettings.ForEach(x => {
|
||||||
x.AlliedVictory = reader.ReadInt32();
|
x.AlliedVictory = reader.ReadBoolean();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
||||||
|
@ -200,7 +200,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
x.StartingAge = reader.ReadInt32();
|
x.StartingAge = reader.ReadInt32();
|
||||||
});
|
});
|
||||||
|
|
||||||
ReadSeparator("Map");
|
ReadSeparator(reader, "Map");
|
||||||
|
|
||||||
// Map
|
// Map
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using AdrianKousz.Util;
|
using AdrianKousz.Util;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
public class ScnSerializerWriter
|
internal class ScnSerializerWriter
|
||||||
{
|
{
|
||||||
public static ScnSerializerWriter CreateDefault()
|
public static ScnSerializerWriter CreateDefault()
|
||||||
{
|
{
|
||||||
|
@ -23,7 +22,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
// Uncompressed header
|
// Uncompressed header
|
||||||
|
|
||||||
writer.Write(value.VersionString);
|
writer.WriteStringRaw(value.VersionString);
|
||||||
writer.Write((int)UncompressedHeaderLength);
|
writer.Write((int)UncompressedHeaderLength);
|
||||||
writer.Write(value.Unknown1);
|
writer.Write(value.Unknown1);
|
||||||
writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp));
|
writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp));
|
||||||
|
@ -117,9 +116,6 @@ namespace AdrianKousz.GenieEngine
|
||||||
writer.Write((int)writer.GetByteCount(x.ScriptAI));
|
writer.Write((int)writer.GetByteCount(x.ScriptAI));
|
||||||
writer.Write((int)writer.GetByteCount(x.ScriptCTY));
|
writer.Write((int)writer.GetByteCount(x.ScriptCTY));
|
||||||
writer.Write((int)writer.GetByteCount(x.ScriptPER));
|
writer.Write((int)writer.GetByteCount(x.ScriptPER));
|
||||||
});
|
|
||||||
|
|
||||||
value.PlayerSettings.ForEach(x => {
|
|
||||||
writer.WriteStringRaw(x.ScriptAI);
|
writer.WriteStringRaw(x.ScriptAI);
|
||||||
writer.WriteStringRaw(x.ScriptCTY);
|
writer.WriteStringRaw(x.ScriptCTY);
|
||||||
writer.WriteStringRaw(x.ScriptPER);
|
writer.WriteStringRaw(x.ScriptPER);
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class ScnValidator
|
|
||||||
{
|
|
||||||
public ScnValidator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Validate(Scenario value)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ValidationError<T>
|
|
||||||
{
|
|
||||||
public T actualValue;
|
|
||||||
public T expectedValue;
|
|
||||||
public string message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,266 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using AdrianKousz.Util;
|
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class ScnWriter
|
|
||||||
{
|
|
||||||
public float Version = 0;
|
|
||||||
|
|
||||||
private ExtendedBinaryWriter writer;
|
|
||||||
|
|
||||||
public ScnWriter(Stream output)
|
|
||||||
{
|
|
||||||
writer = new ExtendedBinaryWriter(output, Scenario.Encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(Scenario value)
|
|
||||||
{
|
|
||||||
Version = Version == 0 ? value.OriginalVersion : Version;
|
|
||||||
|
|
||||||
Write(value.Header);
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
// TODO: Make wrapper.
|
|
||||||
// This is a workaround for now. A wrapper for the reader and writer will be created.
|
|
||||||
var originalWriter = writer;
|
|
||||||
var compressedPart = new MemoryStream();
|
|
||||||
var comp = new DeflateStream(compressedPart, CompressionMode.Compress);
|
|
||||||
writer = new ExtendedBinaryWriter(comp, Scenario.Encoding);
|
|
||||||
|
|
||||||
writer.Write(value.NextId);
|
|
||||||
writer.Write(Version);
|
|
||||||
|
|
||||||
value.PlayerNames.ForEach((x) => writer.WriteStringPadded(x, 256));
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
value.StringTablePlayerNames.ForEach(writer.Write);
|
|
||||||
}
|
|
||||||
value.Players.ForEach(Write);
|
|
||||||
Write(value.Messages);
|
|
||||||
Write(value.Cinematics);
|
|
||||||
Write(value.AIData);
|
|
||||||
|
|
||||||
WriteSeperator("Resources");
|
|
||||||
|
|
||||||
value.Resources.ForEach(Write);
|
|
||||||
|
|
||||||
WriteSeperator("Victory");
|
|
||||||
|
|
||||||
Write(value.GlobalVictory);
|
|
||||||
value.LinearDiplomacy.ForEach(writer.Write);
|
|
||||||
writer.Write(value.RawIndividualVictory);
|
|
||||||
|
|
||||||
WriteSeperator("Player Settings");
|
|
||||||
|
|
||||||
value.AlliedVictory.ForEach(writer.Write);
|
|
||||||
writer.Write(value.RawDisables);
|
|
||||||
value.StartingAges.ForEach(writer.Write);
|
|
||||||
|
|
||||||
WriteSeperator("Map");
|
|
||||||
|
|
||||||
Write(value.Map);
|
|
||||||
|
|
||||||
writer.Write((int)value.Units.Length);
|
|
||||||
value.ResourcesCopy.ForEach(Write);
|
|
||||||
value.Units.ForEach(Write);
|
|
||||||
|
|
||||||
writer.Write(value.RawRemaining);
|
|
||||||
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
comp.Dispose();
|
|
||||||
originalWriter.Write(compressedPart.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(ScenarioHeader value)
|
|
||||||
{
|
|
||||||
var instructionlength = writer.GetZByteCount(value.Instructions);
|
|
||||||
writer.WriteStringRaw(value.OriginalVersion);
|
|
||||||
writer.Write(20 + instructionlength);
|
|
||||||
writer.Write(value.Unknown1);
|
|
||||||
writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp));
|
|
||||||
writer.WriteZStringInt32(value.Instructions);
|
|
||||||
writer.Write(value.Unknown2);
|
|
||||||
writer.Write(value.PlayerCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(PlayerInfo value)
|
|
||||||
{
|
|
||||||
writer.Write(value.Active);
|
|
||||||
writer.Write(value.Human);
|
|
||||||
writer.Write(value.Civ);
|
|
||||||
writer.Write(value.Unknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(Messages value)
|
|
||||||
{
|
|
||||||
writer.Write(value.Unknown1);
|
|
||||||
writer.Write(value.Unknown2);
|
|
||||||
writer.Write(value.Unknown3);
|
|
||||||
writer.WriteStringInt16(value.OriginalFilename);
|
|
||||||
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
writer.Write(value.StringTableInstructions);
|
|
||||||
writer.Write(value.StringTableHints);
|
|
||||||
writer.Write(value.StringTableVictory);
|
|
||||||
writer.Write(value.StringTableLoss);
|
|
||||||
writer.Write(value.StringTableHistory);
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
writer.Write(value.StringTableScouts);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteZStringInt16(value.TextInstructions);
|
|
||||||
writer.WriteZStringInt16(value.TextHints);
|
|
||||||
writer.WriteZStringInt16(value.TextVictory);
|
|
||||||
writer.WriteZStringInt16(value.TextLoss);
|
|
||||||
writer.WriteZStringInt16(value.TextHistory);
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
writer.WriteZStringInt16(value.TextScouts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(Cinematics value)
|
|
||||||
{
|
|
||||||
writer.WriteStringInt16(value.CinemaPregameFn);
|
|
||||||
writer.WriteStringInt16(value.CinemaVictoryFn);
|
|
||||||
writer.WriteStringInt16(value.CinemaLossFn);
|
|
||||||
writer.WriteStringInt16(value.BackgroundFn);
|
|
||||||
|
|
||||||
var hasBitmap = value.RawBitmap.Length > 0;
|
|
||||||
|
|
||||||
writer.Write(hasBitmap);
|
|
||||||
writer.Write(value.BitmapWidth);
|
|
||||||
writer.Write(value.BitmapHeight);
|
|
||||||
writer.Write(value.BitmapUnknown);
|
|
||||||
|
|
||||||
if (hasBitmap)
|
|
||||||
writer.Write(value.RawBitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(AIData value)
|
|
||||||
{
|
|
||||||
value.PlayerAIs.ForEach(writer.WriteStringInt16);
|
|
||||||
value.PlayerCTYs.ForEach(writer.WriteStringInt16);
|
|
||||||
value.PlayerPERs.ForEach(writer.WriteStringInt16);
|
|
||||||
|
|
||||||
for (var i = 0; i < Scenario.NumPlayers; ++i) {
|
|
||||||
var str1 = value.PlayerCustomAIs[i];
|
|
||||||
var str2 = value.PlayerCustomCTYs[i];
|
|
||||||
var str3 = value.PlayerCustomPERs[i];
|
|
||||||
writer.Write(writer.GetByteCount(str1));
|
|
||||||
writer.Write(writer.GetByteCount(str2));
|
|
||||||
writer.Write(writer.GetByteCount(str3));
|
|
||||||
writer.WriteStringRaw(str1);
|
|
||||||
writer.WriteStringRaw(str2);
|
|
||||||
writer.WriteStringRaw(str3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
value.AITypes.ForEach(writer.Write);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(ResourceInfo value)
|
|
||||||
{
|
|
||||||
writer.Write(value.Gold);
|
|
||||||
writer.Write(value.Wood);
|
|
||||||
writer.Write(value.Food);
|
|
||||||
writer.Write(value.Stone);
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
writer.Write(value.Ore);
|
|
||||||
if (Version < 1.3f) {
|
|
||||||
writer.Write(value.Unknown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(ResourceInfoCopy value)
|
|
||||||
{
|
|
||||||
writer.Write(value.Food);
|
|
||||||
writer.Write(value.Wood);
|
|
||||||
writer.Write(value.Gold);
|
|
||||||
writer.Write(value.Stone);
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
writer.Write(value.Ore);
|
|
||||||
if (Version < 1.3f) {
|
|
||||||
writer.Write(value.Unknown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
writer.Write(value.PopulationLimit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(GlobalVictoryInfo value)
|
|
||||||
{
|
|
||||||
writer.Write(value.RequireConquest);
|
|
||||||
writer.Write(value.Ruins);
|
|
||||||
writer.Write(value.Artifacts);
|
|
||||||
writer.Write(value.Discovery);
|
|
||||||
writer.Write(value.PercentExplored);
|
|
||||||
writer.Write(value.Unknown);
|
|
||||||
writer.Write(value.RequireAllCustom);
|
|
||||||
writer.Write(value.Mode);
|
|
||||||
writer.Write(value.Score);
|
|
||||||
writer.Write(value.Time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(Map value)
|
|
||||||
{
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
writer.Write(value.CameraX);
|
|
||||||
writer.Write(value.CameraY);
|
|
||||||
}
|
|
||||||
if (Version >= 1.22f) {
|
|
||||||
writer.Write(value.GeneratorId);
|
|
||||||
}
|
|
||||||
writer.Write(value.SizeX);
|
|
||||||
writer.Write(value.SizeY);
|
|
||||||
|
|
||||||
value.LinearTiles.ForEach(x => { writer.Write(x.Id); writer.Write(x.Elevation); writer.Write(x.Unknown); });
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(IList<UnitInfo> value)
|
|
||||||
{
|
|
||||||
int number = value.Count;
|
|
||||||
writer.Write(number);
|
|
||||||
value.ForEach(Write);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(UnitInfo value)
|
|
||||||
{
|
|
||||||
writer.Write(value.PosX);
|
|
||||||
writer.Write(value.PosY);
|
|
||||||
writer.Write(value.Unknown1);
|
|
||||||
writer.Write(value.Id);
|
|
||||||
writer.Write(value.UnitId);
|
|
||||||
writer.Write(value.Unknown2);
|
|
||||||
writer.Write(value.Rotation);
|
|
||||||
if (Version >= 1.18f) {
|
|
||||||
writer.Write(value.InitialFrame);
|
|
||||||
writer.Write(value.GarrisonnedInId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteSeperator(string name)
|
|
||||||
{
|
|
||||||
writer.Write(Scenario.Separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Flush()
|
|
||||||
{
|
|
||||||
writer.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureSetVersion()
|
|
||||||
{
|
|
||||||
if (Version <= 1)
|
|
||||||
throw new System.InvalidOperationException("Set output version");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,16 +34,13 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AdrianKousz.GenieEngine\BitmapUtil.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\BitmapUtil.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\CpnReader.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\CpnReader.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnReader.cs" />
|
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnValidator.cs" />
|
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnWriter.cs" />
|
|
||||||
<Compile Include="AssemblyInfo.cs" />
|
<Compile Include="AssemblyInfo.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnConvert.cs" />
|
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnDefaultFactory.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnDefaultFactory.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\IScnFactory.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\IScnFactory.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerWriter.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerWriter.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\Scenario.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\Scenario.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerReader.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerReader.cs" />
|
||||||
|
<Compile Include="AdrianKousz.GenieEngine\GenieFile.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue