-
Notifications
You must be signed in to change notification settings - Fork 106
/
GameLocation.cs
165 lines (140 loc) · 6.03 KB
/
GameLocation.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System;
using System.IO;
using pkNX.Structures;
namespace pkNX.Game;
/// <summary>
/// Environment Data where the Game's Data is located on the user's machine.
/// </summary>
public sealed class GameLocation
{
/// <summary>
/// Location of the RomFS
/// </summary>
public string? RomFS { get; }
/// <summary>
/// Location of the ExeFS.
/// </summary>
public string? ExeFS { get; }
/// <summary>
/// Game version the files belong to.
/// </summary>
public GameVersion Game { get; }
private GameLocation(string? romfs, string? exefs, GameVersion game)
{
Game = game;
RomFS = romfs;
ExeFS = exefs;
}
/// <summary>
/// Determines the <see cref="GameVersion"/> of the input directory and detects the location of files for editing.
/// </summary>
/// <param name="dir">Directory the game data is in</param>
/// <param name="gameOverride">Detected version</param>
/// <returns>New <see cref="GameLocation"/> object with references to file paths.</returns>
public static (GameLocation?, GameLoadResult) GetGame(string? dir, GameVersion gameOverride = GameVersion.Any)
{
if (dir == null || !Directory.Exists(dir))
return (null, GameLoadResult.DirectoryNotFound);
var dirs = Directory.GetDirectories(dir);
var romfs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("rom", StringComparison.CurrentCultureIgnoreCase));
var exefs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("exe", StringComparison.CurrentCultureIgnoreCase));
if (romfs == null)
{
string selectedDir = Path.GetFileName(dir) ?? string.Empty;
if (selectedDir.StartsWith("rom"))
return (null, GameLoadResult.RomfsSelected);
return (null, GameLoadResult.RomfsNotFound);
}
var game = gameOverride != GameVersion.Any ? gameOverride : GetGameFromPath(romfs, exefs);
if (game == GameVersion.Invalid)
return (null, GameLoadResult.InvalidGameVersion);
var result = GameLoadResult.Success;
if (exefs == null) // Add exefs not found result, but don't mark as failure
result |= GameLoadResult.ExefsNotFound;
return (new GameLocation(romfs, exefs, game), result);
}
private static GameVersion GetGameFromPath(string romfs, string? exefs)
{
var files = Directory.GetFiles(romfs, "*", SearchOption.AllDirectories);
return GetGameFromCount(files.Length, romfs, exefs);
}
private const int FILECOUNT_XY = 271;
private const int FILECOUNT_ORASDEMO = 301;
private const int FILECOUNT_ORAS = 299;
private const int FILECOUNT_SMDEMO = 239;
private const int FILECOUNT_SM = 311;
private const int FILECOUNT_USUM = 333;
private const int FILECOUNT_GG = 27818;
private const int FILECOUNT_SWSH = 41702;
private const int FILECOUNT_SWSH_110 = 41951; // Ver. 1.1.0 (Galarian Slowpoke)
private const int FILECOUNT_SWSH_120 = 46867; // Ver. 1.2.0 (Isle of Armor)
private const int FILECOUNT_SWSH_130 = 50494; // Ver. 1.3.0 (Crown Tundra)
private const int FILECOUNT_LA = 18_370;
private const int FILECOUNT_LA_101 = 18_371; // Ver. 1.0.1 (Day 1 Patch)
private const int FILECOUNT_LA_110 = 19_095; // Ver. 1.1.0 (Daybreak)
private const int FILECOUNT_SV = 24;
private const int FILECOUNT_SV_101 = 25; // Ver. 1.0.1 (Day 1 Patch)
private static GameVersion GetGameFromCount(int fileCount, string romfs, string? exefs)
{
string GetTitleID() => BitConverter.ToUInt64(File.ReadAllBytes(Path.Combine(exefs, "main.npdm")), 0x290).ToString("X16");
switch (fileCount)
{
case FILECOUNT_XY: return GameVersion.XY;
case FILECOUNT_ORASDEMO: return GameVersion.ORASDEMO;
case FILECOUNT_ORAS: return GameVersion.ORAS;
case FILECOUNT_SMDEMO: return GameVersion.SMDEMO;
case FILECOUNT_SM:
{
var encdata = Path.Combine(romfs, "a", "0", "8", "2");
if (File.Exists(encdata) && new FileInfo(encdata).Length != 0)
return GameVersion.SN;
return GameVersion.MN;
}
case FILECOUNT_USUM:
{
var encdata = Path.Combine(romfs, "a", "0", "8", "2");
if (File.Exists(encdata) && new FileInfo(encdata).Length != 0)
return GameVersion.US;
return GameVersion.UM;
}
case FILECOUNT_GG:
{
bool eevee = Directory.Exists(Path.Combine(romfs, "bin", "movies", "EEVEE_GO"));
if (eevee)
return GameVersion.GE;
return GameVersion.GP;
}
case FILECOUNT_SWSH:
case FILECOUNT_SWSH_110:
case FILECOUNT_SWSH_120:
case FILECOUNT_SWSH_130:
{
if (exefs == null)
return GameVersion.SWSH;
return GetTitleID() switch
{
"0100ABF008968000" => GameVersion.SW,
"01008DB008C2C000" => GameVersion.SH,
_ => GameVersion.SWSH, // can't figure out Title ID, default to SWSH so that wild editor prompts for version selection
};
}
case FILECOUNT_LA or FILECOUNT_LA_101 or FILECOUNT_LA_110:
return GameVersion.PLA;
case FILECOUNT_SV:
case FILECOUNT_SV_101:
{
if (exefs == null)
return GameVersion.SV;
return GetTitleID() switch
{
// todo sv
"0100ABF008968000" => GameVersion.SL,
"01008DB008C2C000" => GameVersion.VL,
_ => GameVersion.SV, // can't figure out Title ID, default to SWSH so that wild editor prompts for version selection
};
}
default:
return GameVersion.Invalid;
}
}
}