Skip to content

Commit 221a97c

Browse files
committed
Initial commit
1 parent 2ed2e1e commit 221a97c

File tree

7 files changed

+366
-0
lines changed

7 files changed

+366
-0
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
11
# tModUnpacker
2+
3+
Jus small crappy Terraria tModLoader mod unpacker.
4+
5+
Usage:
6+
```
7+
tModUnpacker.exe /path/to/tmod/file.tmod
8+
9+
tModUnpacker.exe /path/to/tmod/file.tmod /path/to/outputfolder
10+
```
11+
12+
#### Purpose
13+
It just unpacks .tmod files as is. Nothing else.<br>
14+
Even if modder has set flags such as `hideCode` and `hideResources` to true. (tModLoader should load these mods somehow, right?)

tModUnpacker.sln

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.28307.572
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tModUnpacker", "tModUnpacker\tModUnpacker.csproj", "{A120FB8E-7DF8-4D19-84D3-E373D7E63131}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Debug|x86 = Debug|x86
12+
Release|Any CPU = Release|Any CPU
13+
Release|x86 = Release|x86
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{A120FB8E-7DF8-4D19-84D3-E373D7E63131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{A120FB8E-7DF8-4D19-84D3-E373D7E63131}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{A120FB8E-7DF8-4D19-84D3-E373D7E63131}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{A120FB8E-7DF8-4D19-84D3-E373D7E63131}.Release|Any CPU.Build.0 = Release|Any CPU
20+
EndGlobalSection
21+
GlobalSection(SolutionProperties) = preSolution
22+
HideSolutionNode = FALSE
23+
EndGlobalSection
24+
GlobalSection(ExtensibilityGlobals) = postSolution
25+
SolutionGuid = {11EAEC1E-3BF0-482B-9714-4A04BA5EA40D}
26+
EndGlobalSection
27+
EndGlobal

tModUnpacker/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
5+
</startup>
6+
</configuration>

tModUnpacker/main.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace tModUnpacker
5+
{
6+
class main
7+
{
8+
static void Main(string[] args)
9+
{
10+
int nArgs = args.Length;
11+
if (nArgs < 1)
12+
{
13+
string help = "Usage:\n" +
14+
$"\t{AppDomain.CurrentDomain.FriendlyName} \"/path/to/tmod/file.tmod\"\n" +
15+
"\tWill extract mod in the same folder where .tmod file located is.\n" +
16+
"\n" +
17+
$"\t{AppDomain.CurrentDomain.FriendlyName} \"/path/to/tmod/file.tmod\" \"/path/to/outputfolder\"\n" +
18+
"\tWill extract in specified folder.\n";
19+
Console.Write(help);
20+
return;
21+
}
22+
string outputpath;
23+
if (nArgs < 2)
24+
{
25+
outputpath = Path.GetDirectoryName(args[0]);
26+
}
27+
else
28+
{
29+
outputpath = args[1];
30+
}
31+
tMod mod = new tMod(args[0]);
32+
mod.ReadMod();
33+
mod.DumpFiles(outputpath, filename => Console.WriteLine($"\tWriting: {filename}"));
34+
}
35+
}
36+
}

tModUnpacker/tMod.cs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
using System.IO;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.IO.Compression;
5+
using System.Collections;
6+
7+
namespace tModUnpacker
8+
{
9+
struct tModFileInfo
10+
{
11+
public long filestart;
12+
public long filesize;
13+
}
14+
15+
struct tModFile
16+
{
17+
public string path;
18+
public long size;
19+
public byte[] data;
20+
}
21+
22+
struct tModInfo
23+
{
24+
public string modloaderversion;
25+
public string modversion;
26+
public string modname;
27+
public byte[] modhash;
28+
public byte[] modsignature;
29+
public int filecount;
30+
}
31+
32+
class tMod : IEnumerable<tModFile>, IEnumerable
33+
{
34+
public tModInfo info;
35+
36+
public IDictionary<string, tModFileInfo> files = new Dictionary<string, tModFileInfo>();
37+
38+
private string path;
39+
40+
private FileStream tempfile;
41+
private string tempfilepath = Path.GetTempFileName();
42+
43+
internal tMod(string path)
44+
{
45+
this.tempfile = new FileStream(
46+
this.tempfilepath,
47+
FileMode.OpenOrCreate,
48+
FileAccess.ReadWrite,
49+
FileShare.Read,
50+
4096,
51+
FileOptions.DeleteOnClose | FileOptions.RandomAccess
52+
);
53+
this.path = path;
54+
}
55+
56+
~tMod()
57+
{
58+
if (this.tempfile != null)
59+
this.tempfile.Close();
60+
}
61+
62+
public bool HasFile(string path)
63+
{
64+
return this.files.ContainsKey(path.Replace("\\", "/"));
65+
}
66+
67+
public byte[] GetFile(string path)
68+
{
69+
path = path.Replace("\\", "/");
70+
if (HasFile(path))
71+
{
72+
tModFileInfo file = this.files[path];
73+
this.tempfile.Seek(file.filestart, SeekOrigin.Begin);
74+
byte[] data = new byte[file.filesize];
75+
this.tempfile.Read(data, 0, (int)file.filesize);
76+
77+
return data;
78+
}
79+
return null;
80+
}
81+
82+
public void WriteFile(string path, byte[] data)
83+
{
84+
string dirpath = Path.GetDirectoryName(path);
85+
if (!Directory.Exists(dirpath))
86+
{
87+
Directory.CreateDirectory(dirpath);
88+
}
89+
File.WriteAllBytes(path, data);
90+
}
91+
92+
public bool ReadMod()
93+
{
94+
tModInfo info = new tModInfo();
95+
using (FileStream fileStream = File.OpenRead(this.path))
96+
{
97+
BinaryReader binaryReader = new BinaryReader(fileStream);
98+
if (Encoding.ASCII.GetString(binaryReader.ReadBytes(4)) != "TMOD")
99+
return false;
100+
101+
info.modloaderversion = binaryReader.ReadString();
102+
info.modhash = binaryReader.ReadBytes(20);
103+
info.modsignature = binaryReader.ReadBytes(256);
104+
105+
fileStream.Seek(4, SeekOrigin.Current);
106+
107+
DeflateStream inflateStream = new DeflateStream(fileStream, CompressionMode.Decompress);
108+
inflateStream.CopyTo(this.tempfile);
109+
inflateStream.Close();
110+
this.tempfile.Seek(0, SeekOrigin.Begin);
111+
BinaryReader tempFileBinaryReader = new BinaryReader(this.tempfile);
112+
113+
info.modname = tempFileBinaryReader.ReadString();
114+
info.modversion = tempFileBinaryReader.ReadString();
115+
info.filecount = tempFileBinaryReader.ReadInt32();
116+
for (int index = 0; index < info.filecount; index++)
117+
{
118+
tModFileInfo file = new tModFileInfo();
119+
string path = tempFileBinaryReader.ReadString().Replace("\\", "/");
120+
file.filesize = tempFileBinaryReader.ReadInt32();
121+
file.filestart = this.tempfile.Position;
122+
this.tempfile.Seek(file.filesize, SeekOrigin.Current);
123+
this.files.Add(path, file);
124+
}
125+
this.info = info;
126+
return true;
127+
}
128+
}
129+
130+
public bool DumpFile(string outputpath, string filename)
131+
{
132+
string path = Path.Combine(outputpath, this.info.modname, filename);
133+
byte[] data = this.GetFile(filename);
134+
135+
if (data == null)
136+
return false;
137+
138+
WriteFile(path, data);
139+
return true;
140+
}
141+
142+
public void DumpFiles(string outputpath)
143+
{
144+
foreach (string fileName in this.files.Keys)
145+
{
146+
DumpFile(outputpath, fileName);
147+
}
148+
}
149+
150+
public void DumpFiles(string outputpath, System.Action<string> func)
151+
{
152+
foreach (string fileName in this.files.Keys)
153+
{
154+
func(fileName);
155+
DumpFile(outputpath, fileName);
156+
}
157+
}
158+
159+
public void DumpFiles(string outputpath, System.Func<string, bool> func)
160+
{
161+
foreach (string fileName in this.files.Keys)
162+
{
163+
if (!func(fileName))
164+
continue;
165+
DumpFile(outputpath, fileName);
166+
}
167+
}
168+
169+
public IEnumerator<tModFile> GetEnumerator()
170+
{
171+
foreach (string path in this.files.Keys)
172+
{
173+
tModFile file = new tModFile();
174+
file.path = path;
175+
file.data = this.GetFile(path);
176+
file.size = file.data != null ? file.data.Length : 0;
177+
yield return file;
178+
}
179+
}
180+
181+
IEnumerator IEnumerable.GetEnumerator()
182+
{
183+
return this.GetEnumerator();
184+
}
185+
}
186+
}

tModUnpacker/tModUnpacker.csproj

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{A120FB8E-7DF8-4D19-84D3-E373D7E63131}</ProjectGuid>
8+
<OutputType>Exe</OutputType>
9+
<RootNamespace>tModUnpacker</RootNamespace>
10+
<AssemblyName>tModUnpacker</AssemblyName>
11+
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
12+
<FileAlignment>512</FileAlignment>
13+
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
14+
<Deterministic>true</Deterministic>
15+
<PublishUrl>publish\</PublishUrl>
16+
<Install>true</Install>
17+
<InstallFrom>Disk</InstallFrom>
18+
<UpdateEnabled>false</UpdateEnabled>
19+
<UpdateMode>Foreground</UpdateMode>
20+
<UpdateInterval>7</UpdateInterval>
21+
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
22+
<UpdatePeriodically>false</UpdatePeriodically>
23+
<UpdateRequired>false</UpdateRequired>
24+
<MapFileExtensions>true</MapFileExtensions>
25+
<ApplicationRevision>0</ApplicationRevision>
26+
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
27+
<IsWebBootstrapper>false</IsWebBootstrapper>
28+
<UseApplicationTrust>false</UseApplicationTrust>
29+
<BootstrapperEnabled>true</BootstrapperEnabled>
30+
<NuGetPackageImportStamp>
31+
</NuGetPackageImportStamp>
32+
</PropertyGroup>
33+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
34+
<PlatformTarget>AnyCPU</PlatformTarget>
35+
<DebugSymbols>true</DebugSymbols>
36+
<DebugType>full</DebugType>
37+
<Optimize>false</Optimize>
38+
<OutputPath>bin\Debug\</OutputPath>
39+
<DefineConstants>DEBUG;TRACE</DefineConstants>
40+
<ErrorReport>prompt</ErrorReport>
41+
<WarningLevel>4</WarningLevel>
42+
</PropertyGroup>
43+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
44+
<PlatformTarget>AnyCPU</PlatformTarget>
45+
<DebugType>pdbonly</DebugType>
46+
<Optimize>true</Optimize>
47+
<OutputPath>bin\Release\</OutputPath>
48+
<DefineConstants>TRACE</DefineConstants>
49+
<ErrorReport>prompt</ErrorReport>
50+
<WarningLevel>4</WarningLevel>
51+
</PropertyGroup>
52+
<ItemGroup>
53+
<Reference Include="System" />
54+
<Reference Include="System.Core" />
55+
<Reference Include="System.Xml.Linq" />
56+
<Reference Include="System.Data.DataSetExtensions" />
57+
<Reference Include="Microsoft.CSharp" />
58+
<Reference Include="System.Data" />
59+
<Reference Include="System.Net.Http" />
60+
<Reference Include="System.Xml" />
61+
</ItemGroup>
62+
<ItemGroup>
63+
<Compile Include="main.cs" />
64+
<Compile Include="Properties\AssemblyInfo.cs" />
65+
<Compile Include="tMod.cs" />
66+
</ItemGroup>
67+
<ItemGroup>
68+
<None Include="App.config">
69+
<SubType>Designer</SubType>
70+
</None>
71+
</ItemGroup>
72+
<ItemGroup>
73+
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
74+
<Visible>False</Visible>
75+
<ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
76+
<Install>true</Install>
77+
</BootstrapperPackage>
78+
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
79+
<Visible>False</Visible>
80+
<ProductName>.NET Framework 3.5 SP1</ProductName>
81+
<Install>false</Install>
82+
</BootstrapperPackage>
83+
</ItemGroup>
84+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
85+
</Project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<PublishUrlHistory>publish\</PublishUrlHistory>
5+
<InstallUrlHistory />
6+
<SupportUrlHistory />
7+
<UpdateUrlHistory />
8+
<BootstrapperUrlHistory />
9+
<ErrorReportUrlHistory />
10+
<FallbackCulture>en-US</FallbackCulture>
11+
<VerifyUploadedFiles>false</VerifyUploadedFiles>
12+
</PropertyGroup>
13+
</Project>

0 commit comments

Comments
 (0)