Campaign support and bitmap to map conversion in application

* Full Campaign reading/writing support
* Convert bitmaps to maps
* Command arguments reordering: input and output are always first
* Adapt usage of utils API
This commit is contained in:
Adrian 2016-02-22 17:02:44 +01:00
parent 48929d1fbf
commit 9cc13f0e8d
10 changed files with 222 additions and 41 deletions

View file

@ -19,15 +19,16 @@
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="src\Program.cs" />
@ -42,6 +43,9 @@
<Compile Include="src\ConvertCommand.cs" />
<Compile Include="src\AddBitmapCommand.cs" />
<Compile Include="src\DelBitmapCommand.cs" />
<Compile Include="src\PackCommand.cs" />
<Compile Include="src\Bmp2MapCommand.cs" />
<Compile Include="src\BitmapHelpers.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

View file

@ -10,8 +10,8 @@ namespace AdrianKousz.GenieEngine
override public void Run()
{
using (var input = File.OpenRead(args[0]))
using (var bmpstream = File.OpenRead(args[1]))
using (var output = File.OpenWrite(args[2]))
using (var output = File.OpenWrite(args[1]))
using (var bmpstream = File.OpenRead(args[2]))
{
var scn = GenieFile.Deserialize<Scenario>(input);
var bmp = (Bitmap)Image.FromStream(bmpstream);
@ -41,7 +41,7 @@ namespace AdrianKousz.GenieEngine
+ "\nAdditionally, a game-specific palette will be used to display the image."
+ "\n"
+ "\nParameters:"
+ "\n<input scenario> <bitmap> <output scenario>"
+ "\n<input scenario> <output scenario> <bitmap>"
;
}
}

View file

@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine
{
public static class BitmapHelpers
{
public static unsafe void FillMap(Scenario scn, Bitmap bmp, Bitmap bmp2)
{
using (var ubmp = new UnsafeBitmap(bmp))
using (var ubmp2 = new UnsafeBitmap(bmp2))
{
var factory = new ScnDefaultFactory();
Check(ubmp);
Check(ubmp2);
var ptr = ubmp.Scan0;
var last = ptr + ubmp.Stride * ubmp.Height;
var ptr2 = ubmp2.Scan0;
var last2 = ptr2 + ubmp2.Stride * ubmp2.Height;
var map = factory.MakeMap();
map.SizeX = ubmp.Width;
map.SizeY = ubmp.Height;
map.LinearTiles = new Scenario.ScnMap.Tile[map.SizeX * map.SizeY];
var gaiaunits = new List<Scenario.ScnUnit>();
var treemapping = new short[256];
treemapping[10] = 411;
treemapping[13] = 351;
treemapping[17] = 414;
treemapping[18] = 348;
treemapping[19] = 350;
treemapping[20] = 349;
var i = 0;
while (ptr < last && ptr2 < last2) {
var treeid = treemapping[*ptr];
if (treeid != 0) {
var unit = factory.MakeUnit();
var posy = i / map.SizeX;
var posx = i - (posy * map.SizeX);
unit.UnitId = treeid;
unit.PosX = posx + 0.5f;
unit.PosY = posy + 0.5f;
unit.Rotation = (short)Util.Math.Rand(0, 13);
gaiaunits.Add(unit);
}
map.LinearTiles[i++] = new Scenario.ScnMap.Tile(*ptr++, (byte)(*ptr2++ / 37), 0);
}
scn.Map = map;
scn.Units[0] = gaiaunits;
}
}
private static void Check(UnsafeBitmap ubmp)
{
if (ubmp.PixelFormat != PixelFormat.Format8bppIndexed)
throw new ArgumentException("Unsupported PixelFormat");
if (ubmp.Stride != ubmp.Width)
throw new NotImplementedException("bmpbit.Stride != bmpbit.Width");
}
}
}

View file

@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Drawing;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine
{
public class Bmp2MapCommand : BaseCommand
{
override public void Run()
{
using (var srcstream = File.OpenRead(args[0]))
using (var outstream = File.OpenWrite(args[1]))
using (var bmpstream = File.OpenRead(args[2]))
using (var bmp2stream = File.OpenRead(args[3]))
{
var bmp = (Bitmap)Image.FromStream(bmpstream);
var bmp2 = (Bitmap)Image.FromStream(bmp2stream);
var scn = GenieFile.Deserialize<Scenario>(srcstream);
BitmapHelpers.FillMap(scn, bmp, bmp2);
GenieFile.Serialize(scn, outstream);
}
}
override public int GetArgumentCount()
{
return 4;
}
override public string GetDescription()
{
return "Generate a scenario map based on bitmaps";
}
override public string GetHelp()
{
return "Generate a scenario map based on bitmaps with automatic forest generation."
+ "\n"
+ "\nTwo bitmaps need to be specified: One terrain map and one elevation map."
+ "\nBoth bitmaps need to be indexed or grayscale."
+ "\nThe index/gray values of the first bitmap are translated directly to a terrain ID."
+ "\nThe index/gray values of the second bitmap are divided by 37 to generate elevations 0-6."
+ "\n"
+ "\nParameters:"
+ "\n<input scenario> <output scenario> <terrain bitmap> <elevation bitmap>"
;
}
}
}

View file

@ -8,9 +8,9 @@ namespace AdrianKousz.GenieEngine
{
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]))
using (var srcstream = File.OpenRead(args[0]))
using (var outstream = File.OpenWrite(args[1]))
using (var refstream = File.OpenRead(args[2]))
{
var refscn = GenieFile.Deserialize<Scenario>(refstream);
var srcscn = GenieFile.Deserialize<Scenario>(srcstream);
@ -50,7 +50,7 @@ namespace AdrianKousz.GenieEngine
+ "\nThe converter needs an existing AOE2 scenario to start with."
+ "\n"
+ "\nParameters:"
+ "\n<AOE2 reference scenario> <AOE1 scenario> <output scenario>"
+ "\n<AOE1 scenario> <output scenario> <AOE2 reference scenario>"
;
}
}

View file

@ -26,9 +26,9 @@ namespace AdrianKousz.GenieEngine
// Other Buildings
109, 68, 103,
};
units.ForEach((i, list) => {
list.ForEach((j, unit) => {
mapping.ForEach((k, buildingid) => {
units.ForEach(list => {
list.ForEach(unit => {
mapping.ForEach(buildingid => {
if (unit.UnitId == buildingid) {
unit.PosX -= 0.5f;
unit.PosY -= 0.5f;
@ -43,7 +43,7 @@ namespace AdrianKousz.GenieEngine
*/
private List<Scenario.ScnUnit>[] ChangeUnits_AOE1_AOE2(IList<Scenario.ScnUnit>[] units)
{
var array = new int[] {
var mapping = new short[] {
// Resources
66, 66,
59, 59,
@ -139,22 +139,15 @@ namespace AdrianKousz.GenieEngine
114, 114,
121, 121,
129, 129,
};
var mapping = new Dictionary<short, short>();
var ai = 0;
while (ai < array.Length)
mapping.Add((short)array[ai++], (short)array[ai++]);
}.ToDictionary();
var result = new List<Scenario.ScnUnit>[Scenario.NumPlayerSections].Fill();
units.ForEach((i, list) => {
list.ForEach((j, unit) => {
if (mapping.ContainsKey(unit.UnitId)) {
unit.UnitId = mapping[unit.UnitId];
result[i].Add(unit);
}
});
});
var result = units.Map(list => {
return list
.Filter(unit => mapping.ContainsKey(unit.UnitId))
.ForEach(unit => {
unit.UnitId = mapping[unit.UnitId];
}).ToList();
}).ToArray();
return result;
}
@ -164,8 +157,8 @@ namespace AdrianKousz.GenieEngine
*/
private void ChangeTiles_AOE1_AOE2(IList<Scenario.ScnUnit>[] units, Scenario.ScnMap map)
{
units.ForEach((i, list) => {
list.ForEach((j, unit) => {
units.ForEach(list => {
list.ForEach(unit => {
var posx = (int)(unit.PosX - 0.5);
var posy = (int)(unit.PosY - 0.5);
var linearpos = posy * map.SizeX + posx;
@ -203,12 +196,11 @@ namespace AdrianKousz.GenieEngine
var treeids = new int[] {
411, 351, 414, 350, 348, 349,
};
units.ForEach((i, list) => {
list.ForEach((j, unit) => {
treeids.ForEach((k, treeid) => {
units.ForEach(list => {
list.ForEach(unit => {
treeids.ForEach(treeid => {
if (unit.UnitId == treeid) {
unit.InitialFrame = (short)Util.Math.Rand(0, 13); // Whats the maximum?
unit.Rotation = unit.InitialFrame;
unit.Rotation = (short)Util.Math.Rand(0, 13); // Whats the maximum?
}
});
});

View file

@ -17,9 +17,10 @@ namespace AdrianKousz.GenieEngine
Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position");
Console.WriteLine();
scn.Units.ForEach((i, list) => {
Console.WriteLine("Units of player {0}:", i);
list.ForEach((j, unit) => {
var i = 0;
scn.Units.ForEach(list => {
Console.WriteLine("Units of player {0}:", i++);
list.ForEach(unit => {
var tilex = (int)(unit.PosX - 0.5);
var tiley = (int)(unit.PosY - 0.5);
var tile = scn.Map.LinearTiles[tiley * scn.Map.SizeX + tilex];

View file

@ -1,4 +1,6 @@
using System;
using System.IO;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine
{
@ -6,9 +8,17 @@ namespace AdrianKousz.GenieEngine
{
override public void Run()
{
using (var file = File.OpenRead(args[0])) {
var reader = new CpnReader(file);
reader.ExtractFiles();
using (var file = File.OpenRead(args[0]))
{
var cpn = GenieFile.Deserialize<Campaign>(file);
Console.WriteLine("Extracting \"{0}\"...", cpn.Name);
cpn.Files.ForEach(x => {
using (var outfile = File.OpenWrite(x.Filename))
{
Console.WriteLine("Extracting \"{0}\" to \"{1}\"...", x.Name, x.Filename);
outfile.Write(x.RawData);
}
});
}
}
@ -19,7 +29,7 @@ namespace AdrianKousz.GenieEngine
override public string GetDescription()
{
return "Extract scenarios from campaign file";
return "Extract files from campaign file";
}
}
}

View file

@ -0,0 +1,47 @@
using System.IO;
using System.Collections.Generic;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine
{
public class PackCommand : BaseCommand
{
override public void Run()
{
var files = new List<Campaign.CpnFile>();
for (var i = 2; i < args.Length; i++) {
var file = new Campaign.CpnFile();
file.Filename = args[i];
file.Name = Path.GetFileNameWithoutExtension(file.Filename);
using (var stream = File.OpenRead(file.Filename))
using (var memorystream = new MemoryStream())
{
stream.CopyTo(memorystream);
file.RawData = memorystream.ToArray();
}
files.Add(file);
}
var cpn = new Campaign();
cpn.Files = files;
cpn.Name = args[1];
cpn.Version = "1.00";
using (var file = File.OpenWrite(args[0]))
{
GenieFile.Serialize(cpn, file);
}
}
override public int GetArgumentCount()
{
return 3;
}
override public string GetDescription()
{
return "Pack files into a campaign file";
}
}
}

View file

@ -8,6 +8,7 @@ namespace AdrianKousz.GenieEngine
public static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.Name = "main";
Log.SetUncaughtExceptionHandler();
if (System.Diagnostics.Debugger.IsAttached) {
debug();
@ -26,6 +27,7 @@ namespace AdrianKousz.GenieEngine
{
var result = new Dictionary<string, ICommand<string[]>>();
result.Add("convert", new ConvertCommand());
result.Add("bmp2map", new Bmp2MapCommand());
result.Add("addbmp", new AddBitmapCommand());
result.Add("delbmp", new DelBitmapCommand());
result.Add("compress", new CompressCommand());
@ -34,6 +36,7 @@ namespace AdrianKousz.GenieEngine
result.Add("fromjson", new FromJsonCommand());
result.Add("dumpunits", new DumpunitsCommand());
result.Add("extract", new ExtractCommand());
result.Add("pack", new PackCommand());
return result;
}