Skip to content

Commit 177f3bf

Browse files
authored
Merge pull request #1 from europa1400-community/feature/decoder-implementation
Decoder Implementation
2 parents 6ce283a + 87f07e2 commit 177f3bf

47 files changed

Lines changed: 2089 additions & 39 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,69 @@
1-
namespace Europa1400.Tools.Tests;
1+
using Europa1400.Tools.Converter;
2+
using Xunit.Sdk;
3+
4+
namespace Europa1400.Tools.Tests;
25

36
public class Europa1400Test
47
{
58
[Fact]
6-
public void TestFromPath()
9+
public void TestSoundConverter()
710
{
811
var path = EnvVariables.GameDirectoryPath;
9-
var europa1400 = Europa1400.FromPath(path);
1012

11-
Assert.Equal(path, europa1400.GameDirectory.FullName);
13+
var soundConverter = new SoundConverter();
14+
var tempTargetPath = Directory.CreateTempSubdirectory("Sound");
15+
16+
soundConverter.Convert(path, tempTargetPath.FullName);
17+
18+
var tempTargetPathSound = new DirectoryInfo(Path.Combine(tempTargetPath.FullName, "Sound"));
19+
20+
Assert.True(tempTargetPathSound.Exists);
21+
Assert.True(tempTargetPathSound.GetFiles("*.wav", SearchOption.AllDirectories).Length > 0);
22+
23+
tempTargetPath.Delete(true);
1224
}
1325

1426
[Fact]
15-
public void TestFromDirectory()
27+
public void TestGraphicsConverter()
1628
{
1729
var path = EnvVariables.GameDirectoryPath;
18-
var directoryInfo = new DirectoryInfo(path);
19-
var europa1400 = Europa1400.FromDirectory(directoryInfo);
2030

21-
Assert.Equal(path, europa1400.GameDirectory.FullName);
31+
var graphicsConverter = new GraphicsConverter();
32+
var tempTargetPath = Directory.CreateTempSubdirectory("Graphics");
33+
34+
graphicsConverter.Convert(path, tempTargetPath.FullName);
35+
36+
var tempTargetPathGraphics = new DirectoryInfo(Path.Combine(tempTargetPath.FullName, "Graphics"));
37+
38+
Assert.True(tempTargetPathGraphics.Exists);
39+
Assert.True(tempTargetPathGraphics.GetFiles("*.png", SearchOption.AllDirectories).Length > 0);
40+
41+
tempTargetPath.Delete(true);
42+
}
43+
44+
[Fact]
45+
public void TestAgebConverter()
46+
{
47+
var path = EnvVariables.GameDirectoryPath;
48+
var agebConverter = new AgebConverter();
49+
var tempTargetPath = Directory.CreateTempSubdirectory("Ageb");
50+
51+
agebConverter.Convert(path, tempTargetPath.FullName);
52+
53+
Assert.True(tempTargetPath.Exists);
54+
Assert.True(tempTargetPath.GetFiles("*.json", SearchOption.AllDirectories).Length > 0);
55+
}
56+
57+
[Fact]
58+
public void TestAobjConverter()
59+
{
60+
var path = EnvVariables.GameDirectoryPath;
61+
var aobjConverter = new AobjConverter();
62+
var tempTargetPath = Directory.CreateTempSubdirectory("Aobj");
63+
64+
aobjConverter.Convert(path, tempTargetPath.FullName);
65+
66+
Assert.True(tempTargetPath.Exists);
67+
Assert.True(tempTargetPath.GetFiles("*.json", SearchOption.AllDirectories).Length > 0);
2268
}
2369
}

Europa1400.Tools.sln

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.0.31903.59
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Europa1400.Tools", "Europa1400.Tools\Europa1400.Tools.csproj", "{4BC2EDEB-CF48-4CC0-B2C0-2326EBAC109D}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Europa1400.Tools", "Europa1400.Tools\Europa1400.Tools.csproj", "{4BC2EDEB-CF48-4CC0-B2C0-2326EBAC109D}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Europa1400.Tools.Tests", "Europa1400.Tools.Tests\Europa1400.Tools.Tests.csproj", "{F2B2AD53-2710-4488-95CE-011F70A9F573}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Europa1400.Tools.Tests", "Europa1400.Tools.Tests\Europa1400.Tools.Tests.csproj", "{F2B2AD53-2710-4488-95CE-011F70A9F573}"
99
EndProject
1010
Global
1111
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1212
Debug|Any CPU = Debug|Any CPU
1313
Release|Any CPU = Release|Any CPU
1414
EndGlobalSection
15-
GlobalSection(SolutionProperties) = preSolution
16-
HideSolutionNode = FALSE
17-
EndGlobalSection
1815
GlobalSection(ProjectConfigurationPlatforms) = postSolution
1916
{4BC2EDEB-CF48-4CC0-B2C0-2326EBAC109D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2017
{4BC2EDEB-CF48-4CC0-B2C0-2326EBAC109D}.Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -25,4 +22,7 @@ Global
2522
{F2B2AD53-2710-4488-95CE-011F70A9F573}.Release|Any CPU.ActiveCfg = Release|Any CPU
2623
{F2B2AD53-2710-4488-95CE-011F70A9F573}.Release|Any CPU.Build.0 = Release|Any CPU
2724
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
2828
EndGlobal
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Europa1400.Tools.Decoder.Ageb;
2+
using Europa1400.Tools.Interfaces;
3+
using System.Text.Json;
4+
5+
namespace Europa1400.Tools.Converter
6+
{
7+
internal class AgebConverter : IConverter
8+
{
9+
public void Convert(string pathToGameFiles, string targetDirectory)
10+
{
11+
var agebFile = new FileInfo(Path.Combine(pathToGameFiles, "Data\\A_Geb.dat"));
12+
var buildingsJson = new FileInfo(Path.Combine(targetDirectory, "buildings.json"));
13+
14+
using var binaryReader = new BinaryReader(File.OpenRead(agebFile.FullName));
15+
using var outputStream = new FileStream(buildingsJson.FullName, FileMode.Create);
16+
var agebStruct = AgebStruct.FromBytes(binaryReader);
17+
18+
var jsonWriterOptions = new JsonWriterOptions
19+
{
20+
Indented = true
21+
};
22+
23+
using var jsonWriter = new Utf8JsonWriter(outputStream, jsonWriterOptions);
24+
25+
jsonWriter.WriteStartObject();
26+
jsonWriter.WriteStartArray("Buildings");
27+
28+
foreach (var building in agebStruct.Buildings)
29+
{
30+
jsonWriter.WriteStartObject();
31+
jsonWriter.WriteNumber("GroupId", building.GroupId);
32+
jsonWriter.WriteString("Name", building.Name);
33+
jsonWriter.WriteNumber("Unknown1", building.Unknown1);
34+
jsonWriter.WriteStartArray("UnkownData1");
35+
foreach (var data in building.UnknownData1)
36+
{
37+
jsonWriter.WriteNumberValue(data);
38+
}
39+
jsonWriter.WriteEndArray();
40+
jsonWriter.WriteStartArray("UnknownData2");
41+
foreach (var data in building.UnknownData2)
42+
{
43+
jsonWriter.WriteNumberValue(data);
44+
}
45+
jsonWriter.WriteEndArray();
46+
jsonWriter.WriteStartArray("UnknownData3");
47+
foreach (var data in building.UnknownData3)
48+
{
49+
jsonWriter.WriteNumberValue(data);
50+
}
51+
jsonWriter.WriteEndArray();
52+
jsonWriter.WriteStartArray("UnknownData4");
53+
foreach (var data in building.UnknownData4)
54+
{
55+
jsonWriter.WriteNumberValue(data);
56+
}
57+
jsonWriter.WriteEndArray();
58+
jsonWriter.WriteStartArray("UnknownData5");
59+
foreach (var data in building.UnknownData5)
60+
{
61+
jsonWriter.WriteNumberValue(data);
62+
}
63+
jsonWriter.WriteEndArray();
64+
jsonWriter.WriteStartObject("Coordinates1");
65+
jsonWriter.WriteNumber("X", building.Coordinates1.X);
66+
jsonWriter.WriteNumber("Y", building.Coordinates1.Y);
67+
jsonWriter.WriteEndObject();
68+
jsonWriter.WriteStartObject("Coordinates2");
69+
jsonWriter.WriteNumber("X", building.Coordinates2.X);
70+
jsonWriter.WriteNumber("Y", building.Coordinates2.Y);
71+
jsonWriter.WriteEndObject();
72+
jsonWriter.WriteNumber("Time", building.Time);
73+
jsonWriter.WriteNumber("Level", building.Level);
74+
jsonWriter.WriteNumber("Unknown2", building.Unknown2);
75+
jsonWriter.WriteNumber("Price", building.Price);
76+
jsonWriter.WriteEndObject();
77+
}
78+
79+
jsonWriter.WriteEndArray();
80+
jsonWriter.WriteEndObject();
81+
}
82+
}
83+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using Europa1400.Tools.Decoder.Aobj;
2+
using Europa1400.Tools.Interfaces;
3+
using System.Text.Json;
4+
5+
namespace Europa1400.Tools.Converter
6+
{
7+
internal class AobjConverter : IConverter
8+
{
9+
public void Convert(string pathToGameFiles, string targetDirectory)
10+
{
11+
var aobjFile = new FileInfo(Path.Combine(pathToGameFiles, "Data\\A_Obj.dat"));
12+
var objectsJson = new FileInfo(Path.Combine(targetDirectory, "objects.json"));
13+
14+
using var binaryReader = new BinaryReader(File.OpenRead(aobjFile.FullName));
15+
using var outputStream = new FileStream(objectsJson.FullName, FileMode.Create);
16+
var aobjStruct = AobjStruct.FromBytes(binaryReader);
17+
18+
var jsonWriterOptions = new JsonWriterOptions
19+
{
20+
Indented = true
21+
};
22+
23+
using var jsonWriter = new Utf8JsonWriter(outputStream, jsonWriterOptions);
24+
25+
jsonWriter.WriteStartObject();
26+
jsonWriter.WriteStartArray("Objects");
27+
28+
foreach (var aobject in aobjStruct.Objects)
29+
{
30+
jsonWriter.WriteStartObject();
31+
jsonWriter.WriteNumber("Type", aobject.Type);
32+
jsonWriter.WriteString("Name", aobject.Name);
33+
jsonWriter.WriteNumber("Level", aobject.Level);
34+
jsonWriter.WriteNumber("Time", aobject.Time);
35+
jsonWriter.WriteStartArray("UnknownData1");
36+
foreach (var data in aobject.UnknownData1)
37+
{
38+
jsonWriter.WriteNumberValue(data);
39+
}
40+
jsonWriter.WriteEndArray();
41+
jsonWriter.WriteStartArray("UnknownData2");
42+
foreach (var data in aobject.UnknownData2)
43+
{
44+
jsonWriter.WriteNumberValue(data);
45+
}
46+
jsonWriter.WriteEndArray();
47+
jsonWriter.WriteNumber("Unknown1", aobject.Unknown1);
48+
jsonWriter.WriteNumber("Price", aobject.Price);
49+
jsonWriter.WriteNumber("Unknown2", aobject.Unknown2);
50+
jsonWriter.WriteEndObject();
51+
}
52+
53+
jsonWriter.WriteEndArray();
54+
jsonWriter.WriteEndObject();
55+
}
56+
}
57+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using Europa1400.Tools.Decoder.Gfx;
2+
using Europa1400.Tools.Interfaces;
3+
using System.Drawing;
4+
using System.Drawing.Imaging;
5+
using System.Runtime.CompilerServices;
6+
7+
[assembly: InternalsVisibleTo("Europa1400.Tools.Tests")]
8+
9+
namespace Europa1400.Tools.Converter;
10+
11+
#pragma warning disable CA1416 // Validate platform compatibility
12+
internal class GraphicsConverter : IConverter
13+
{
14+
public void Convert(string pathToGameFiles, string targetDirectory)
15+
{
16+
var sourceDirectory = new DirectoryInfo(pathToGameFiles);
17+
18+
var outputPath = Path.Combine(targetDirectory, "Graphics");
19+
var graphicsDirectory = new DirectoryInfo(outputPath);
20+
graphicsDirectory.Create();
21+
22+
var graphicsFiles = sourceDirectory.GetFiles("*.gfx", SearchOption.AllDirectories);
23+
24+
foreach (var graphicsFile in graphicsFiles)
25+
{
26+
using var br = new BinaryReader(File.OpenRead(graphicsFile.FullName));
27+
var gfxStruct = GfxStruct.FromBytes(br);
28+
29+
Dictionary<string, Dictionary<string, Image>> shapebankImages = [];
30+
31+
foreach (var shapebankDefinition in gfxStruct.ShapebankDefinitions)
32+
{
33+
if (shapebankDefinition.Shapebank == null)
34+
continue;
35+
36+
var convertedShapebank = ConvertShapebank(shapebankDefinition.Name, shapebankDefinition.Shapebank);
37+
38+
shapebankImages.Add(shapebankDefinition.Name, convertedShapebank);
39+
}
40+
41+
foreach (var shapebank in shapebankImages)
42+
{
43+
var shapebankDirectory = Path.Combine(outputPath, shapebank.Key);
44+
var shapebankDirectoryInfo = new DirectoryInfo(shapebankDirectory);
45+
shapebankDirectoryInfo.Create();
46+
47+
foreach (var image in shapebank.Value)
48+
{
49+
image.Value.Save(Path.Combine(shapebankDirectory, $"{image.Key}.png"), ImageFormat.Png);
50+
}
51+
}
52+
}
53+
}
54+
55+
private Dictionary<string, Image> ConvertShapebank(string baseName, ShapebankStruct shapebank)
56+
{
57+
var result = new Dictionary<string, Image>();
58+
59+
for (var i = 0; i < shapebank.Graphics.Length; i++)
60+
{
61+
var graphic = shapebank.Graphics[i];
62+
var convertedGraphic = ConvertGraphic(graphic);
63+
64+
result.Add($"{baseName}_{i}", convertedGraphic);
65+
}
66+
67+
return result;
68+
}
69+
70+
private Image ConvertGraphic(GraphicStruct graphic)
71+
{
72+
var result = new Bitmap(graphic.Width, graphic.Height);
73+
74+
if (graphic.PixelData != null)
75+
{
76+
var row = 0;
77+
var col = 0;
78+
79+
for (var i = 0; i < graphic.Width * graphic.Height; i += 3)
80+
{
81+
var pixel = Color.FromArgb(255, graphic.PixelData[i], graphic.PixelData[i + 1],
82+
graphic.PixelData[i + 2]);
83+
84+
result.SetPixel(row, col, pixel);
85+
86+
if (row == graphic.Width - 1)
87+
{
88+
row = 0;
89+
col++;
90+
}
91+
else
92+
row++;
93+
}
94+
}
95+
else if (graphic.GraphicRows != null)
96+
{
97+
var transparent = Color.FromArgb(0, 255, 255, 255);
98+
var imageData = new List<Color>();
99+
100+
foreach (var graphicRow in graphic.GraphicRows)
101+
{
102+
foreach (var transparencyBlock in graphicRow.TransparencyBlocks)
103+
{
104+
for (var k = 0; k < transparencyBlock.Size; k += 3)
105+
{
106+
imageData.Add(transparent);
107+
}
108+
109+
for (var k = 0; k < transparencyBlock.Data.Length; k += 3)
110+
{
111+
imageData.Add(Color.FromArgb(255, transparencyBlock.Data[k], transparencyBlock.Data[k + 1],
112+
transparencyBlock.Data[k + 2]));
113+
}
114+
}
115+
}
116+
117+
if (imageData.Count != graphic.Height * graphic.Width)
118+
throw new Exception(
119+
$"Image data does not match graphic dimensions. Expected {graphic.Height * graphic.Width}, got {imageData.Count}");
120+
121+
var row = 0;
122+
var col = 0;
123+
124+
foreach (var pixel in imageData)
125+
{
126+
result.SetPixel(row, col, pixel);
127+
128+
if (row == graphic.Width - 1)
129+
{
130+
row = 0;
131+
col++;
132+
}
133+
else
134+
row++;
135+
}
136+
}
137+
else
138+
throw new ArgumentException("Graphic has no pixel data or graphic rows");
139+
140+
return result;
141+
}
142+
}

0 commit comments

Comments
 (0)