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
|
||||
[Rr]elease
|
||||
*.userprefs
|
||||
packages
|
||||
|
|
74
README.md
74
README.md
|
@ -1,30 +1,38 @@
|
|||
# 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:
|
||||
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
|
||||
## Features
|
||||
|
||||
The command `copymap` is able convert an AOE1 to an AOE2 scenario.
|
||||
There seem to be some issues with cliffs.
|
||||
* Convert AOE1 Scenario to AOE2 Scenario
|
||||
* 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)
|
||||
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.)
|
||||
|
||||
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
|
||||
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)
|
||||
...
|
||||
|
||||
### 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
|
||||
|
||||
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`.
|
||||
|
||||
## Contributing
|
||||
|
@ -53,12 +85,10 @@ Keep in mind that the API is still very unstable.
|
|||
Suggestions:
|
||||
|
||||
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.
|
||||
3. Ideas how to configure the converter (mapping tables).
|
||||
There are some notes in German:
|
||||
[AOE1](files/units-aoe1.txt),
|
||||
[AOE2](files/units-aoe2.txt)
|
||||
3. The application should be able to generate maps from images
|
||||
in the future. How should units be placed using the image?
|
||||
4. Feedback about the API.
|
||||
3. Feedback about the API.
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
@ -31,14 +31,15 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="src\Program.cs" />
|
||||
<Compile Include="src\DecompressCommand.cs" />
|
||||
<Compile Include="src\BaseCommand.cs" />
|
||||
<Compile Include="src\CompressCommand.cs" />
|
||||
<Compile Include="src\ExtractCommand.cs" />
|
||||
<Compile Include="src\DumpCommand.cs" />
|
||||
<Compile Include="src\CopymapCommand.cs" />
|
||||
<Compile Include="src\ToJsonCommand.cs" />
|
||||
<Compile Include="src\FromJsonCommand.cs" />
|
||||
<Compile Include="src\CompressCommand.cs" />
|
||||
<Compile Include="src\DecompressCommand.cs" />
|
||||
<Compile Include="src\DumpunitsCommand.cs" />
|
||||
<Compile Include="src\CopymapConverter.cs" />
|
||||
<Compile Include="src\ConvertCommand.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -61,5 +62,11 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<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>
|
||||
</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()
|
||||
{
|
||||
using (var file = File.OpenRead(args[0])) {
|
||||
using (var outfile = File.OpenWrite(args[1])) {
|
||||
var reader = new ScnReader(file);
|
||||
var writer = new ScnWriter(outfile);
|
||||
|
||||
var header = reader.ReadScenarioHeader();
|
||||
reader.ReadSeparator("Custom");
|
||||
writer.Write(header);
|
||||
writer.Flush();
|
||||
|
||||
using (var comp = new DeflateStream(outfile, CompressionMode.Compress)) {
|
||||
file.CopyTo(comp);
|
||||
}
|
||||
}
|
||||
using (var input = File.OpenRead(args[0]))
|
||||
using (var output = File.OpenWrite(args[1]))
|
||||
{
|
||||
GenieFile.ScenarioCompression(input, output, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.Collections.Generic;
|
||||
using AdrianKousz.Util;
|
||||
using AdrianKousz.GenieEngine.Data;
|
||||
|
||||
namespace AdrianKousz.GenieEngine
|
||||
{
|
||||
public class CopymapConverter
|
||||
{
|
||||
public void Convert(Scenario dst, Scenario src)
|
||||
public void Convert(Scenario scn)
|
||||
{
|
||||
dst.Map = src.Map;
|
||||
dst.Units = ChangeUnits_AOE1_AOE2(src.Units);
|
||||
MoveUnits_AOE1_AOE2(dst.Units);
|
||||
ChangeTiles_AOE1_AOE2(dst.Units, dst.Map);
|
||||
RandomizeTrees_AOE2(dst.Units);
|
||||
scn.Units = ChangeUnits_AOE1_AOE2(scn.Units);
|
||||
MoveUnits_AOE1_AOE2(scn.Units);
|
||||
ChangeTiles_AOE1_AOE2(scn.Units, scn.Map);
|
||||
RandomizeTrees_AOE2(scn.Units);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some buildings are not the same size.
|
||||
* 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[] {
|
||||
// Towers
|
||||
|
@ -43,7 +41,7 @@ namespace AdrianKousz.GenieEngine
|
|||
/**
|
||||
* 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[] {
|
||||
// Resources
|
||||
|
@ -142,18 +140,17 @@ namespace AdrianKousz.GenieEngine
|
|||
121, 121,
|
||||
129, 129,
|
||||
};
|
||||
var mapping = new Dictionary<int, int>();
|
||||
var mapping = new Dictionary<short, short>();
|
||||
var ai = 0;
|
||||
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];
|
||||
result.Fill();
|
||||
var result = new List<Scenario.ScnUnit>[Scenario.NumPlayerSections].Fill();
|
||||
|
||||
units.ForEach((i, list) => {
|
||||
list.ForEach((j, unit) => {
|
||||
if (mapping.ContainsKey(unit.UnitId)) {
|
||||
unit.UnitId = (short)mapping[unit.UnitId];
|
||||
unit.UnitId = mapping[unit.UnitId];
|
||||
result[i].Add(unit);
|
||||
}
|
||||
});
|
||||
|
@ -165,7 +162,7 @@ namespace AdrianKousz.GenieEngine
|
|||
/**
|
||||
* 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) => {
|
||||
list.ForEach((j, unit) => {
|
||||
|
@ -175,6 +172,7 @@ namespace AdrianKousz.GenieEngine
|
|||
if (false) {
|
||||
// switch
|
||||
} else if (unit.UnitId == 50) {
|
||||
// Farm
|
||||
map.LinearTiles[linearpos].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
|
||||
* without this function
|
||||
*/
|
||||
private void RandomizeTrees_AOE2(IList<UnitInfo>[] units)
|
||||
private void RandomizeTrees_AOE2(IList<Scenario.ScnUnit>[] units)
|
||||
{
|
||||
var treeids = new int[] {
|
||||
411, 351, 414, 350, 348, 349,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace AdrianKousz.GenieEngine
|
||||
{
|
||||
|
@ -7,20 +6,10 @@ namespace AdrianKousz.GenieEngine
|
|||
{
|
||||
override public void Run()
|
||||
{
|
||||
using (var file = File.OpenRead(args[0])) {
|
||||
using (var outfile = File.OpenWrite(args[1])) {
|
||||
var reader = new ScnReader(file);
|
||||
var writer = new ScnWriter(outfile);
|
||||
|
||||
var header = reader.ReadScenarioHeader();
|
||||
writer.Write(header);
|
||||
writer.WriteSeperator("Custom");
|
||||
writer.Flush();
|
||||
|
||||
using (var comp = new DeflateStream(file, CompressionMode.Decompress)) {
|
||||
comp.CopyTo(outfile);
|
||||
}
|
||||
}
|
||||
using (var input = File.OpenRead(args[0]))
|
||||
using (var output = File.OpenWrite(args[1]))
|
||||
{
|
||||
GenieFile.ScenarioCompression(input, output, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.Collections.Generic;
|
||||
using AdrianKousz.Util;
|
||||
using AdrianKousz.GenieEngine.Data;
|
||||
|
||||
namespace AdrianKousz.GenieEngine
|
||||
{
|
||||
|
@ -11,9 +10,9 @@ namespace AdrianKousz.GenieEngine
|
|||
override public void Run()
|
||||
{
|
||||
Scenario scn;
|
||||
using (var stream = File.OpenRead(args[0])) {
|
||||
var aoereader = new ScnReader(stream);
|
||||
scn = aoereader.ReadScenario();
|
||||
using (var input = File.OpenRead(args[0]))
|
||||
{
|
||||
scn = GenieFile.Deserialize<Scenario>(input);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
var result = new Dictionary<string, ICommand<string[]>>();
|
||||
result.Add("copymap", new CopymapCommand());
|
||||
result.Add("convert", new ConvertCommand());
|
||||
result.Add("compress", new CompressCommand());
|
||||
result.Add("decompress", new DecompressCommand());
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
@ -38,8 +39,7 @@ namespace AdrianKousz.GenieEngine
|
|||
{
|
||||
var fn = "";
|
||||
using (var istream = System.IO.File.OpenRead(fn)) {
|
||||
var ireader = new ScnReader(istream);
|
||||
var scn = ireader.ReadScenario();
|
||||
var scn = GenieFile.Deserialize<Scenario>(istream);
|
||||
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 AdrianKousz.Util;
|
||||
using AdrianKousz.GenieEngine.Data;
|
||||
|
||||
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;
|
||||
using AdrianKousz.GenieEngine.Data;
|
||||
|
||||
namespace AdrianKousz.GenieEngine
|
||||
namespace AdrianKousz.GenieEngine
|
||||
{
|
||||
public interface IScnFactory
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace AdrianKousz.GenieEngine
|
|||
public const Int32 Separator = -99;
|
||||
public const Int32 NumPlayers = 16;
|
||||
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 ExpectedUnknown2 = 0;
|
||||
|
@ -117,11 +117,11 @@ namespace AdrianKousz.GenieEngine
|
|||
public Int32 Artifacts;
|
||||
public Int32 Discovery;
|
||||
public Int32 PercentExplored;
|
||||
public Int32 Unknown;
|
||||
public Boolean RequireAllCustom;
|
||||
public Int32 Mode;
|
||||
public Int32 Score;
|
||||
public Int32 Time;
|
||||
public Int32 Unknown;
|
||||
}
|
||||
|
||||
public class ScnResourceCopy
|
||||
|
@ -166,17 +166,17 @@ namespace AdrianKousz.GenieEngine
|
|||
public class ScnUnit
|
||||
{
|
||||
public const Single ExpectedUnknown1 = 1;
|
||||
public const Byte ExpectedUnknown2 = 2;
|
||||
public const SByte ExpectedUnknown2 = 2;
|
||||
|
||||
public Single PosX;
|
||||
public Single PosY;
|
||||
public Single Unknown1;
|
||||
public Int32 Id;
|
||||
public Int16 UnitId;
|
||||
public Byte Unknown2;
|
||||
public Single Rotation;
|
||||
public Int16 InitialFrame;
|
||||
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.SizeX = 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
public class ScnSerializerReader
|
||||
internal class ScnSerializerReader
|
||||
{
|
||||
private IScnFactory factory;
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace AdrianKousz.GenieEngine
|
|||
var Version = 0f;
|
||||
var number = 0;
|
||||
var result = factory is ScnDefaultFactory
|
||||
? factory.MakeScenario(false)
|
||||
? ((ScnDefaultFactory)factory).MakeScenario(false)
|
||||
: factory.MakeScenario();
|
||||
|
||||
// Uncompressed header
|
||||
|
@ -180,7 +180,7 @@ namespace AdrianKousz.GenieEngine
|
|||
// PlayerSettings 3
|
||||
|
||||
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);
|
||||
|
@ -188,7 +188,7 @@ namespace AdrianKousz.GenieEngine
|
|||
ReadSeparator(reader, "Player Environment");
|
||||
|
||||
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*/;
|
||||
|
@ -200,7 +200,7 @@ namespace AdrianKousz.GenieEngine
|
|||
x.StartingAge = reader.ReadInt32();
|
||||
});
|
||||
|
||||
ReadSeparator("Map");
|
||||
ReadSeparator(reader, "Map");
|
||||
|
||||
// Map
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using AdrianKousz.Util;
|
||||
using AdrianKousz.GenieEngine.Data;
|
||||
|
||||
namespace AdrianKousz.GenieEngine
|
||||
{
|
||||
public class ScnSerializerWriter
|
||||
internal class ScnSerializerWriter
|
||||
{
|
||||
public static ScnSerializerWriter CreateDefault()
|
||||
{
|
||||
|
@ -23,7 +22,7 @@ namespace AdrianKousz.GenieEngine
|
|||
|
||||
// Uncompressed header
|
||||
|
||||
writer.Write(value.VersionString);
|
||||
writer.WriteStringRaw(value.VersionString);
|
||||
writer.Write((int)UncompressedHeaderLength);
|
||||
writer.Write(value.Unknown1);
|
||||
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.ScriptCTY));
|
||||
writer.Write((int)writer.GetByteCount(x.ScriptPER));
|
||||
});
|
||||
|
||||
value.PlayerSettings.ForEach(x => {
|
||||
writer.WriteStringRaw(x.ScriptAI);
|
||||
writer.WriteStringRaw(x.ScriptCTY);
|
||||
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>
|
||||
<Compile Include="AdrianKousz.GenieEngine\BitmapUtil.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="AdrianKousz.GenieEngine\ScnConvert.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\ScnDefaultFactory.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\IScnFactory.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerWriter.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\Scenario.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\ScnSerializerReader.cs" />
|
||||
<Compile Include="AdrianKousz.GenieEngine\GenieFile.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Reference in New Issue