mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-01-27 22:27:58 +03:00
Initial commit.
This commit is contained in:
parent
0a457a47d2
commit
9fe108f7ca
39
README.md
39
README.md
@ -1,2 +1,39 @@
|
||||
# Worms
|
||||
.NET library to load and modify file formats of Team17 Worms games.
|
||||
The goal of this .NET library is to provide managed language access to game specific file formats of the Worms game series by Team17.
|
||||
|
||||
Right now, the following file formats are supported:
|
||||
|
||||
## First Generation (2D)
|
||||
Support for first generation 2D games is planned at a later stage.
|
||||
|
||||
| Description | Extension | Games | Load | Save |
|
||||
|----------------|-----------|:-------:|:----:|:----:|
|
||||
| Color Map | WRM | W1 | No | No |
|
||||
| DIY Terrain | DIY | DC | No | No |
|
||||
| Monochrome Map | GFT | DC | No | No |
|
||||
| Mountain Set | MNT | DC | No | No |
|
||||
| Option Scheme | OPT | DC | No | No |
|
||||
| Team Container | - | DC | No | No |
|
||||
|
||||
## Second Generation (2D)
|
||||
Formats of the second generation 2D games are mostly focused right now.
|
||||
|
||||
| Description | Extension | Games | Load | Save |
|
||||
|-------------------|:---------:|:-----------:|:----:|:----:|
|
||||
| Archive | DIR | W2, WA, WWP | Yes | Yes |
|
||||
| Image | IMG | W2, WA, WWP | No | No |
|
||||
| Mission | DAT | W2 | No | No |
|
||||
| Mission | WAM | WA, WWP | No | No |
|
||||
| Monochrome Map | LEV | W2 | No | No |
|
||||
| Monochrome Map | LEV, BIT | WA, WWP | No | No |
|
||||
| Option Scheme | OPT | W2 | No | No |
|
||||
| Palette | PAL | W2, WA, WWP | No | No |
|
||||
| Project X Library | PXL | WA+PX | No | No |
|
||||
| Project X Scheme | PXS | WA+PX | No | No |
|
||||
| Replay | WAGAME | WA | No | No |
|
||||
| Team Container | ST1 | W2 | No | No |
|
||||
| Team Container | WGT | WA, WWP | No | No |
|
||||
| Weapon Scheme | WEP | W2 | No | No |
|
||||
|
||||
## Third Generation (3D)
|
||||
Third generation file formats used by the 3D games have not yet been looked into.
|
17
src/Syroot.Worms.Test/Program.cs
Normal file
17
src/Syroot.Worms.Test/Program.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using Syroot.Worms.Gen2;
|
||||
|
||||
namespace Syroot.Worms.Test
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Archive archive = new Archive(@"D:\Archive\Games\Worms\Worms Armageddon\DATA\Gfx\Gfx0.dir");
|
||||
archive.Save(@"D:\Pictures\test.dir");
|
||||
Archive archive2 = new Archive(@"D:\Pictures\test.dir");
|
||||
}
|
||||
}
|
||||
}
|
12
src/Syroot.Worms.Test/Syroot.Worms.Test.csproj
Normal file
12
src/Syroot.Worms.Test/Syroot.Worms.Test.csproj
Normal file
@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
28
src/Syroot.Worms.sln
Normal file
28
src/Syroot.Worms.sln
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26403.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms.Test", "Syroot.Worms.Test\Syroot.Worms.Test.csproj", "{9F7486C2-C30E-4457-B528-F4467486E6D8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9F7486C2-C30E-4457-B528-F4467486E6D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9F7486C2-C30E-4457-B528-F4467486E6D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9F7486C2-C30E-4457-B528-F4467486E6D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9F7486C2-C30E-4457-B528-F4467486E6D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
34
src/Syroot.Worms/Core/ByteArrayExtensions.cs
Normal file
34
src/Syroot.Worms/Core/ByteArrayExtensions.cs
Normal file
@ -0,0 +1,34 @@
|
||||
namespace Syroot.Worms.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents extension methods for <see cref="byte[]"/> instances.
|
||||
/// </summary>
|
||||
internal static class ByteArrayExtensions
|
||||
{
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if the current <see cref="byte[]"/> instance holds the same values as the given one.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="byte[]"/> instance.</param>
|
||||
/// <param name="other">The <see cref="byte[]"/> instance to compare with.</param>
|
||||
/// <returns><c>true</c> if both instances hold the same values, otherwise <c>false</c>.</returns>
|
||||
internal static bool Compare(this byte[] self, byte[] other)
|
||||
{
|
||||
if (self.Length != other.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < self.Length; i++)
|
||||
{
|
||||
if (self[i] != other[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
223
src/Syroot.Worms/Gen2/Archive.cs
Normal file
223
src/Syroot.Worms/Gen2/Archive.cs
Normal file
@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.IO;
|
||||
|
||||
namespace Syroot.Worms.Gen2
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a directory of files stored in a DIR file, mostly used to store graphics files. Due to the nowadays
|
||||
/// small size of typical directories, the entries and data are loaded directly into a dictionary to profit from
|
||||
/// optimal performance when accessing and manipulating the directory.
|
||||
/// Used by W2, WA and WWP. S. https://worms2d.info/Graphics_directory.
|
||||
/// </summary>
|
||||
public class Archive : Dictionary<string, byte[]>
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private static readonly int _signature = 0x1A524944;
|
||||
private static readonly int _tocSignature = 0x0000000A;
|
||||
|
||||
private const int _hashBits = 10;
|
||||
private const int _hashSize = 1 << _hashBits;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Archive"/> class, loading the data from the given
|
||||
/// <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
public Archive(Stream stream)
|
||||
{
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Archive"/> class, loading the data from the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
public Archive(string fileName)
|
||||
{
|
||||
Load(fileName);
|
||||
}
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Loads the data from the given <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
public void Load(Stream stream)
|
||||
{
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("Stream requires to be seekable.", nameof(stream));
|
||||
}
|
||||
|
||||
Clear();
|
||||
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
|
||||
{
|
||||
// Read the header.
|
||||
int signature = reader.ReadInt32();
|
||||
if (signature != _signature)
|
||||
{
|
||||
throw new InvalidDataException("Invalid file signature.");
|
||||
}
|
||||
int fileSize = reader.ReadInt32();
|
||||
int tocOffset = reader.ReadInt32();
|
||||
|
||||
// Read the table of contents.
|
||||
reader.Position = tocOffset;
|
||||
int tocSignature = reader.ReadInt32();
|
||||
if (tocSignature != _tocSignature)
|
||||
{
|
||||
throw new InvalidDataException("Invalid table of contents signature.");
|
||||
}
|
||||
// Generate a data dictionary out of the hash table and file entries.
|
||||
int[] hashTable = reader.ReadInt32s(_hashSize);
|
||||
foreach (int entryOffset in hashTable)
|
||||
{
|
||||
// If the hash is not 0, it points to a list of files which have a hash being the hash table index.
|
||||
if (entryOffset > 0)
|
||||
{
|
||||
int nextEntryOffset = entryOffset;
|
||||
do
|
||||
{
|
||||
reader.Position = tocOffset + nextEntryOffset;
|
||||
nextEntryOffset = reader.ReadInt32();
|
||||
int offset = reader.ReadInt32();
|
||||
int length = reader.ReadInt32();
|
||||
string name = reader.ReadString(BinaryStringFormat.ZeroTerminated);
|
||||
using (reader.TemporarySeek(offset, SeekOrigin.Begin))
|
||||
{
|
||||
Add(name, reader.ReadBytes(length));
|
||||
}
|
||||
} while (nextEntryOffset != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the data from the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
public void Load(string fileName)
|
||||
{
|
||||
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
Load(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data into the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to save the data in.</param>
|
||||
public void Save(Stream stream)
|
||||
{
|
||||
using (BinaryDataWriter writer = new BinaryDataWriter(stream))
|
||||
{
|
||||
// Write the header.
|
||||
writer.Write(_signature);
|
||||
Offset fileSizeOffset = writer.ReserveOffset();
|
||||
Offset tocOffset = writer.ReserveOffset();
|
||||
|
||||
// Write the data and build the hash table and file entries.
|
||||
List<HashTableEntry>[] hashTable = new List<HashTableEntry>[_hashSize];
|
||||
foreach (KeyValuePair<string, byte[]> item in this)
|
||||
{
|
||||
HashTableEntry entry = new HashTableEntry()
|
||||
{
|
||||
Name = item.Key,
|
||||
Offset = (int)writer.Position,
|
||||
Length = item.Value.Length
|
||||
};
|
||||
writer.Write(item.Value);
|
||||
|
||||
int hash = CalculateHash(item.Key);
|
||||
if (hashTable[hash] == null)
|
||||
{
|
||||
hashTable[hash] = new List<HashTableEntry>();
|
||||
}
|
||||
hashTable[hash].Add(entry);
|
||||
}
|
||||
|
||||
// Write the hash table and file entries.
|
||||
int tocStart = (int)writer.Position;
|
||||
int fileEntryOffset = sizeof(int) + _hashSize * sizeof(int);
|
||||
tocOffset.Satisfy(tocStart);
|
||||
writer.Write(_tocSignature);
|
||||
for (int i = 0; i < _hashSize; i++)
|
||||
{
|
||||
List<HashTableEntry> entries = hashTable[i];
|
||||
if (entries == null)
|
||||
{
|
||||
writer.Write(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write the entries resolving to the current hash.
|
||||
writer.Write(fileEntryOffset);
|
||||
using (writer.TemporarySeek(tocStart + fileEntryOffset, SeekOrigin.Begin))
|
||||
{
|
||||
for (int j = 0; j < entries.Count; j++)
|
||||
{
|
||||
HashTableEntry entry = entries[j];
|
||||
Offset nextEntryOffset = writer.ReserveOffset();
|
||||
writer.Write(entry.Offset);
|
||||
writer.Write(entry.Length);
|
||||
writer.Write(entry.Name, BinaryStringFormat.ZeroTerminated);
|
||||
writer.Align(4);
|
||||
if (j < entries.Count - 1)
|
||||
{
|
||||
nextEntryOffset.Satisfy((int)writer.Position - tocStart);
|
||||
}
|
||||
}
|
||||
fileEntryOffset = (int)writer.Position - tocStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileSizeOffset.Satisfy(tocStart + fileEntryOffset - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data in the file with the given <paramref name="fileName"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to save the data in.</param>
|
||||
public void Save(string fileName)
|
||||
{
|
||||
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private int CalculateHash(string name)
|
||||
{
|
||||
int hash = 0;
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
hash = ((hash << 1) % _hashSize) | (hash >> (_hashBits - 1) & 1);
|
||||
hash += name[i];
|
||||
hash %= _hashSize;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// ---- STRUCTURES ---------------------------------------------------------------------------------------------
|
||||
|
||||
private struct HashTableEntry
|
||||
{
|
||||
internal string Name;
|
||||
internal int Offset;
|
||||
internal int Length;
|
||||
}
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/GameScheme.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/GameScheme.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class GameScheme
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/Mission.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/Mission.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class Mission
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/MonoMap.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/MonoMap.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class MonoMap
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/Replay.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/Replay.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class Replay
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class TeamContainer
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Image.cs
Normal file
10
src/Syroot.Worms/Gen2/Image.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2
|
||||
{
|
||||
class Image
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Palette.cs
Normal file
10
src/Syroot.Worms/Gen2/Palette.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2
|
||||
{
|
||||
class Palette
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/Mission.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/Mission.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class Mission
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/MonoMap.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/MonoMap.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class MonoMap
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/OptionsScheme.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/OptionsScheme.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class OptionsScheme
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class TeamContainer
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/WeaponsScheme.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/WeaponsScheme.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class WeaponsScheme
|
||||
{
|
||||
}
|
||||
}
|
21
src/Syroot.Worms/Syroot.Worms.csproj
Normal file
21
src/Syroot.Worms/Syroot.Worms.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp1.1\Syroot.Worms.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Gen1\" />
|
||||
<Folder Include="Gen2\Armageddon\ProjectX\" />
|
||||
<Folder Include="Gen3\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Syroot.IO.BinaryData" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user