Skip to content

Commit 448cf33

Browse files
authored
Merge pull request #119 from Greavesy1899/segfaultd/sdsconfig-parsing
Bin Files Editors
2 parents 5febdeb + 494f0eb commit 448cf33

40 files changed

Lines changed: 4664 additions & 702 deletions

.github/workflows/dotnet.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@ on:
99
jobs:
1010
build:
1111

12-
runs-on: windows-2019
12+
runs-on: windows-latest
1313

1414
steps:
15-
- uses: actions/checkout@v2
15+
- uses: actions/checkout@v4
1616
- name: Setup .NET
17-
uses: actions/setup-dotnet@v1
17+
uses: actions/setup-dotnet@v4
1818
with:
1919
dotnet-version: 7.0.x
2020
- name: Restore dependencies
2121
run: dotnet restore
2222
- name: Build
2323
run: dotnet build --no-restore --output "_out"
2424
- name: Upload artifacts
25-
uses: actions/upload-artifact@v3
25+
uses: actions/upload-artifact@v4
2626
with:
2727
name: MafiaToolkit
2828
path: _out

CLAUDE.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
MafiaToolkit is a Windows .NET modding toolkit for the Mafia game series (Mafia II, Mafia III, Mafia I: DE, Mafia II: DE). It provides file format parsers, editors, and a 3D map editor with DirectX 11 rendering.
8+
9+
### Supported Games
10+
11+
| Game | SDS | Materials | Map Editor | XBin |
12+
|------|-----|-----------|------------|------|
13+
| Mafia II |||| - |
14+
| Mafia II: Definitive Edition |||| - |
15+
| Mafia III ||| - ||
16+
| Mafia I: Definitive Edition ||| - ||
17+
18+
Mafia 1 Classic is **not** supported.
19+
20+
## Build Commands
21+
22+
### Main Toolkit (C# / .NET 7)
23+
```bash
24+
# Build the toolkit
25+
dotnet build MafiaToolkit.sln
26+
27+
# Build with output directory
28+
dotnet build --output "_out"
29+
30+
# Restore dependencies
31+
dotnet restore
32+
```
33+
34+
### M2FBX Native Library (C++ / FBX SDK)
35+
```bash
36+
# Generate VS2022 project files (from M2FBX/M2FBX directory)
37+
cd M2FBX/M2FBX
38+
premake5 vs2022
39+
40+
# Build in Visual Studio or use MSBuild
41+
# Requires: FBX SDK and PhysX 2.8.X installed
42+
```
43+
44+
**Note**: The toolkit is Windows-only and targets x64. Debug builds of M2FBX produce a console app for testing; Release produces a DLL.
45+
46+
## Architecture
47+
48+
### Source Layout
49+
```
50+
Mafia2Libs/ # Main toolkit source
51+
├── Core/IO/ # File abstraction layer (FileBase, FileFactory)
52+
├── ResourceTypes/FileTypes/ # Game file format implementations
53+
│ ├── FrameResource/ # 3D model/skeleton data
54+
│ ├── Materials/ # MTL material formats (V_57, V_58, V_63)
55+
│ ├── Collisions/ # PhysX collision data
56+
│ ├── Actors/ # Game entity definitions
57+
│ ├── Cutscene/ # Cinematic animation with curve parameters
58+
│ ├── Navigation/ # AI/traffic pathfinding (NAV, NHV, NOV)
59+
│ ├── Prefab/ # Prefabricated object templates
60+
│ ├── SDSConfig/ # Hierarchical game configuration
61+
│ ├── GameParams/ # BitStream-encoded game parameters
62+
│ ├── FrameProps/ # Frame properties with FNV64 hashes
63+
│ └── M3.XBin/ # XBin game data containers
64+
├── Gibbed.*/ # Archive serialization (Gibbed's code)
65+
├── Rendering/ # DirectX 11 graphics engine
66+
│ ├── Graphics/ # D3D11, shaders, textures, camera
67+
│ └── Core/ # RenderableFactory, gizmos, spatial grids
68+
├── Forms/ # 21 editor windows (WinForms)
69+
├── Controls/ # Reusable UI components
70+
├── Utils/ # Settings, logging, language, helpers
71+
├── ThirdParty/ # ApexSDK (PhysX), BitStream, OPCODE
72+
└── Shaders/ # HLSL shaders
73+
74+
M2FBX/ # Native C++ FBX conversion library
75+
├── M2FBX/Source/ # FBX wrangler, MT conversion
76+
└── M2PhysX/ # Separate physics library
77+
```
78+
79+
### File Format Handling
80+
81+
Uses **Factory + Strategy pattern** via `FileFactory.ConstructFromFileInfo()`:
82+
- Archives: SDS, PCKG → `FileSDS`, `FilePCKG`
83+
- 3D Data: FR (FrameResource) → model/skeleton
84+
- Materials: MTL → `FileMaterialLibrary` (version-aware)
85+
- Actors: ACT, FXA, FAS → entity definitions
86+
- Navigation: NAV, NHV, NOV, GAME, GSD → pathfinding
87+
- Audio: BNK, PCK → Wwise formats
88+
- Data: XBin → game data containers with sub-types
89+
90+
Each format has a dedicated `File*` class in `Core/IO/` that handles serialization.
91+
92+
### Rendering System
93+
94+
```
95+
GraphicsClass (coordinator)
96+
97+
DirectX11Class (D3D11 wrapper)
98+
99+
RenderableFactory → 14 IRenderer implementations
100+
101+
ShaderManager (6 shader types)
102+
```
103+
104+
Key renderers: `RenderModel`, `RenderInstance`, `RenderAIWorld`, `RenderNav`, `RenderStaticCollision`
105+
106+
### Editor Forms
107+
108+
- **MapEditor**: Main 3D scene editor (most complex, integrates rendering + all resource types)
109+
- **MaterialEditor/Browser**: MTL editing
110+
- **CutsceneEditor**: Cinematic animation
111+
- **ActorEditor**: Game entity definitions
112+
- **XBinEditor**: Game data containers
113+
- **TranslokatorEditor**: Object placement
114+
- 15+ additional specialized editors
115+
116+
Forms use `WeifenLuo.WinFormsUI.Docking` for flexible panel layout.
117+
118+
### Key Dependencies
119+
120+
- **Vortice.Direct3D11**: DirectX 11 bindings
121+
- **SharpGLTF**: GLTF model support
122+
- **DockPanelSuite**: WinForms docking
123+
- **Gibbed.IO**: Binary serialization utilities
124+
- **UnluacNET**: Lua decompilation
125+
- **OodleSharp**: Oodle compression
126+
127+
## Important Patterns
128+
129+
### Adding New File Format Support
130+
1. Create `File<Format>` class extending `FileBase` in `Core/IO/`
131+
2. Register extension in `FileFactory.ConstructFromFileInfo()`
132+
3. Create corresponding resource types in `ResourceTypes/FileTypes/`
133+
4. Optionally add renderer in `Rendering/Graphics/RenderTypes/`
134+
135+
### Resource Serialization
136+
All game resources implement `IResourceType` interface with `Serialize`/`Deserialize` methods. Version-aware loading handles format differences across games.
137+
138+
### Rendering Objects
139+
Implement `IRenderer` interface in `Rendering/Graphics/RenderTypes/`. Use `RenderableFactory` to create instances from resource types.
140+
141+
### Adding New Editor Forms
142+
1. Create `<Name>Editor.cs` form in `Forms/` with TreeView + PropertyGrid layout
143+
2. Add constructor accepting `FileInfo` parameter
144+
3. Register in `FileBin.cs` or `FileFactory` based on file extension/magic
145+
4. Add localization strings in `Utils/Language/` resource files
146+
5. Standard menu structure: File (Save, Reload, Exit), Tools (Export XML, Import XML)

Mafia2Libs/Core/IO/FileBin.cs

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Mafia2Tool;
22
using ResourceTypes.CGame;
33
using ResourceTypes.EntityActivator;
4+
using ResourceTypes.FrameProps;
5+
using ResourceTypes.GameParams;
46
using ResourceTypes.Navigation;
57
using ResourceTypes.SDSConfig;
68
using ResourceTypes.Sound;
@@ -21,6 +23,7 @@ public class FileBin : FileBase
2123
private const uint EntityActivatorMagic = 0x656E7461;
2224
private const uint TyresMagic = 0x12345678;
2325
private const uint CGameMagic = 0x676D7072;
26+
private const uint FramePropsMagic = 0x66726D70;
2427

2528
public FileBin(FileInfo info) : base(info) { }
2629

@@ -80,6 +83,26 @@ public override bool Open()
8083
}
8184
}
8285
else if (CheckFileMagic(file, CGameMagic))
86+
{
87+
CGameEditor editor = new CGameEditor(file);
88+
return true;
89+
}
90+
else if (CheckFileMagic(file, SDSConfigMagic))
91+
{
92+
SdsConfigEditor editor = new SdsConfigEditor(file);
93+
return true;
94+
}
95+
else if (CheckFileMagic(file, FramePropsMagic))
96+
{
97+
FramePropsEditor editor = new FramePropsEditor(file);
98+
return true;
99+
}
100+
else if (IsGameParamsFile(file))
101+
{
102+
GameParamsEditor editor = new GameParamsEditor(file);
103+
return true;
104+
}
105+
else
83106
{
84107
SaveFileDialog saveFile = new SaveFileDialog()
85108
{
@@ -91,49 +114,53 @@ public override bool Open()
91114
if (saveFile.ShowDialog() == DialogResult.OK)
92115
{
93116
// Unsure on how we should handle this. For now we will just try and hope the loader works.
94-
CGame loader = new CGame(file);
117+
SoundSectorResource loader = new SoundSectorResource(file);
95118
loader.ConvertToXML(saveFile.FileName);
96119
}
97120
}
98-
else if (CheckFileMagic(file, SDSConfigMagic))
121+
122+
return false;
123+
}
124+
125+
public override void Save()
126+
{
127+
if (CheckFileMagic(file, TyresMagic))
99128
{
100-
SaveFileDialog saveFile = new SaveFileDialog()
129+
OpenFileDialog openFile = new OpenFileDialog()
101130
{
102131
InitialDirectory = Path.GetDirectoryName(file.FullName),
103132
FileName = Path.GetFileNameWithoutExtension(file.FullName),
104133
Filter = "XML (*.xml)|*.xml"
105134
};
106135

107-
if (saveFile.ShowDialog() == DialogResult.OK)
136+
if (openFile.ShowDialog() == DialogResult.OK)
108137
{
109-
// Unsure on how we should handle this. For now we will just try and hope the loader works.
110-
SdsConfigFile loader = new SdsConfigFile(file);
111-
loader.ConvertToXML(saveFile.FileName);
138+
Tyres loader = new Tyres(file);
139+
loader.ConvertFromXML(openFile.FileName);
140+
141+
File.Copy(file.FullName, file.FullName + "_old", true);
142+
loader.WriteToFile(file.FullName);
112143
}
113144
}
114-
else
145+
else if (CheckFileMagic(file, CGameMagic))
115146
{
116-
SaveFileDialog saveFile = new SaveFileDialog()
147+
OpenFileDialog openFile = new OpenFileDialog()
117148
{
118149
InitialDirectory = Path.GetDirectoryName(file.FullName),
119150
FileName = Path.GetFileNameWithoutExtension(file.FullName),
120151
Filter = "XML (*.xml)|*.xml"
121152
};
122153

123-
if (saveFile.ShowDialog() == DialogResult.OK)
154+
if (openFile.ShowDialog() == DialogResult.OK)
124155
{
125-
// Unsure on how we should handle this. For now we will just try and hope the loader works.
126-
SoundSectorResource loader = new SoundSectorResource(file);
127-
loader.ConvertToXML(saveFile.FileName);
156+
CGame loader = new CGame(file);
157+
loader.ConvertFromXML(openFile.FileName);
158+
159+
File.Copy(file.FullName, file.FullName + "_old", true);
160+
loader.WriteToFile(file.FullName);
128161
}
129162
}
130-
131-
return false;
132-
}
133-
134-
public override void Save()
135-
{
136-
if (CheckFileMagic(file, TyresMagic))
163+
else if (CheckFileMagic(file, SDSConfigMagic))
137164
{
138165
OpenFileDialog openFile = new OpenFileDialog()
139166
{
@@ -144,14 +171,14 @@ public override void Save()
144171

145172
if (openFile.ShowDialog() == DialogResult.OK)
146173
{
147-
Tyres loader = new Tyres(file);
174+
SdsConfigFile loader = new SdsConfigFile(file);
148175
loader.ConvertFromXML(openFile.FileName);
149176

150177
File.Copy(file.FullName, file.FullName + "_old", true);
151178
loader.WriteToFile(file.FullName);
152179
}
153180
}
154-
else if (CheckFileMagic(file, CGameMagic))
181+
else if (CheckFileMagic(file, FramePropsMagic))
155182
{
156183
OpenFileDialog openFile = new OpenFileDialog()
157184
{
@@ -162,14 +189,14 @@ public override void Save()
162189

163190
if (openFile.ShowDialog() == DialogResult.OK)
164191
{
165-
CGame loader = new CGame(file);
192+
FramePropsFile loader = new FramePropsFile(file);
166193
loader.ConvertFromXML(openFile.FileName);
167194

168195
File.Copy(file.FullName, file.FullName + "_old", true);
169196
loader.WriteToFile(file.FullName);
170197
}
171198
}
172-
else if (CheckFileMagic(file, SDSConfigMagic))
199+
else if (IsGameParamsFile(file))
173200
{
174201
OpenFileDialog openFile = new OpenFileDialog()
175202
{
@@ -180,7 +207,7 @@ public override void Save()
180207

181208
if (openFile.ShowDialog() == DialogResult.OK)
182209
{
183-
SdsConfigFile loader = new SdsConfigFile(file);
210+
GameParamsFile loader = new GameParamsFile(file);
184211
loader.ConvertFromXML(openFile.FileName);
185212

186213
File.Copy(file.FullName, file.FullName + "_old", true);
@@ -207,6 +234,11 @@ public override void Save()
207234
}
208235
}
209236

237+
private bool IsGameParamsFile(FileInfo file)
238+
{
239+
return file.Name.Equals("gameparams.bin", System.StringComparison.OrdinalIgnoreCase);
240+
}
241+
210242
private bool CheckFileMagic(FileInfo file, uint Magic)
211243
{
212244
using (BinaryReader reader = new BinaryReader(File.Open(file.FullName, FileMode.Open)))

0 commit comments

Comments
 (0)