Skip to content

Commit

Permalink
WinterPatch update
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmgvol committed Dec 28, 2020
1 parent 5aa6560 commit 1d16c29
Show file tree
Hide file tree
Showing 27 changed files with 513 additions and 67 deletions.
7 changes: 7 additions & 0 deletions GRUnlocker/ByteUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ public static int GetPrevNewLineAnchor(byte[] arr, int current) {
return 0;
}

public static void ReplaceByteRange(ref byte[] bytes, byte[] newRange, int index) {
var lst = bytes.ToList();
lst.RemoveRange(index, newRange.Count());
lst.InsertRange(index, newRange);
bytes = lst.ToArray();
}

public static void ReplaceByteRange(ref byte[] bytes, byte[] newRange, string fromString, string toString, int fromIndex = 0) {

List<byte> lst = bytes.ToList();
Expand Down
94 changes: 80 additions & 14 deletions GRUnlocker/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@ namespace GRUnlocker {
class Config {

// Global settings
public string SaveDirectory { get; private set; } = "";
private string SaveDirectory;
public string GameDirectory { get; private set; } = "";

public bool IsLocalSavePath = true;
public bool ValidGameDirectory = false;
// save file
public bool DisplayPath { get; private set; } = false;
public enum SaveType { None, SteamOrGOG, EGS }
public enum SaveLocation { None, Local, Remote, Auto }

public SaveType saveType = SaveType.None;
public SaveLocation saveLocation = SaveLocation.None;
public string SaveFilePath { get; private set; } = "";


// Private settings
private const string ConfigFileName = "config.json";
private const string FILE_NAME_CONFIG = "config.json";
private const string FILE_NAME_Steam = "Ghostrunner.sav";
private const string FILE_NAME_EGS = "GhostrunnerSave.sav";

// single instance
private static Config Instance;
Expand All @@ -24,18 +33,29 @@ public static Config getInstance() {
}

// Load config file
public void Load() {
if(File.Exists(ConfigFileName)) {
public void Load(string[] args) {
// ARGS
if(args.Contains("-displaypath"))
DisplayPath = true;

// config file found?
if(File.Exists(FILE_NAME_CONFIG)) {
if(!ParseManually()) {
Console.WriteLine("Error: config.json file\n -Invalid/missing directories or corrupted config.json file");
InputHandler.ExitProgram();
}
} else {
// no config file, local path file
SaveDirectory = "";
GameDirectory = "";
IsLocalSavePath = true;
SaveDirectory = Directory.GetCurrentDirectory();
if(DetectFile()) { // file found in same directory, flag as local
saveLocation = SaveLocation.Local;
}
}


// failed to find local + remote(config file), try auto detect
if(saveLocation == SaveLocation.None)
AutoDetect();
}

// Note: creating and parsing manually to avoid 3'rd party .dll dependencies like Newtonsoft-Json,
Expand All @@ -47,15 +67,48 @@ public bool SaveManually() {
$" \"{nameof(SaveDirectory)}\": \"\",\n" +
$" \"{nameof(GameDirectory)}\": \"\"\n" +
"}";
File.WriteAllText(ConfigFileName, str);
File.WriteAllText(FILE_NAME_CONFIG, str);
return true;
} catch(Exception) {}
return false;
}

private bool AutoDetect() {
// attempts to auto find .sav file
string savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Ghostrunner\Saved\SaveGames\");
if(!Directory.Exists(savePath)) return false;


// EGS VERSION
if(File.Exists(Path.Combine(savePath, FILE_NAME_EGS))) {
// found it - EGS
SaveFilePath = Path.Combine(savePath, FILE_NAME_EGS);
saveType = SaveType.EGS;
saveLocation = SaveLocation.Auto;
return true;
}

// STEAM VERSION
var folders = Directory.EnumerateDirectories(savePath).ToList();
for(int i = 0; i < folders.Count(); i++) {
long steamUserID = -1;
if(Path.GetFileName(folders[i]).Length > 15 && Path.GetFileName(folders[i]).Length < 20 && long.TryParse(Path.GetFileName(folders[i]), out steamUserID) && steamUserID > 0) {
savePath = Path.Combine(savePath, "" + steamUserID, FILE_NAME_Steam);
if(File.Exists(savePath)) {
// found it - STEAM/GOG
SaveFilePath = savePath;
saveType = SaveType.SteamOrGOG;
saveLocation = SaveLocation.Auto;
return true;
}
}
}
return false;
}

private bool ParseManually() {
if(!File.Exists(ConfigFileName)) return false;
var result = File.ReadAllText(ConfigFileName)
if(!File.Exists(FILE_NAME_CONFIG)) return false;
var result = File.ReadAllText(FILE_NAME_CONFIG)
.Split(new[] { '\n', '\r', ',', '\"' }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !string.IsNullOrWhiteSpace(x.Trim())).ToArray();

Expand All @@ -68,12 +121,12 @@ private bool ParseManually() {
// check save directory
if(Directory.Exists(result[1])) {
SaveDirectory = result[1];
IsLocalSavePath = false;
saveLocation = SaveLocation.Remote;
DetectFile();
}
// check game directory
if(Directory.Exists(result[3]) && GameDirectoryStructureValid(result[3])) {
GameDirectory = result[3];
ValidGameDirectory = true;
}
return true;
}
Expand All @@ -82,6 +135,19 @@ private bool ParseManually() {
return false;
}

private bool DetectFile() {
if(File.Exists(Path.Combine(SaveDirectory, FILE_NAME_Steam))) {
SaveFilePath = Path.Combine(SaveDirectory, FILE_NAME_Steam);
saveType = SaveType.SteamOrGOG;
return true;
} else if(File.Exists(Path.Combine(SaveDirectory, FILE_NAME_EGS))) {
SaveFilePath = Path.Combine(SaveDirectory, FILE_NAME_EGS);
saveType = SaveType.SteamOrGOG;
return true;
}
return false;
}

private bool GameDirectoryStructureValid(string path) {
// 2 directories "Engine" and "Ghostrunner", 1 file "Ghostrunner.exe"
return (Directory.Exists(Path.Combine(path, "Engine")) && Directory.Exists(Path.Combine(path, "Ghostrunner")) && File.Exists(Path.Combine(path, "Ghostrunner.exe")));
Expand Down
24 changes: 23 additions & 1 deletion GRUnlocker/GRUnlocker.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>icon%281%29.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down Expand Up @@ -98,6 +101,22 @@
<None Include="Resources\defaultLevelDetails.sav" />
<None Include="Resources\defaultLevelDetails_2.sav" />
<None Include="Resources\EmptyUnlockedList.sav" />
<None Include="Resources\Ghostrunner_hc_1.sav" />
<None Include="Resources\Ghostrunner_hc_10.sav" />
<None Include="Resources\Ghostrunner_hc_11.sav" />
<None Include="Resources\Ghostrunner_hc_12.sav" />
<None Include="Resources\Ghostrunner_hc_13.sav" />
<None Include="Resources\Ghostrunner_hc_14.sav" />
<None Include="Resources\Ghostrunner_hc_15.sav" />
<None Include="Resources\Ghostrunner_hc_16.sav" />
<None Include="Resources\Ghostrunner_hc_2.sav" />
<None Include="Resources\Ghostrunner_hc_3.sav" />
<None Include="Resources\Ghostrunner_hc_4.sav" />
<None Include="Resources\Ghostrunner_hc_5.sav" />
<None Include="Resources\Ghostrunner_hc_6.sav" />
<None Include="Resources\Ghostrunner_hc_7.sav" />
<None Include="Resources\Ghostrunner_hc_8.sav" />
<None Include="Resources\Ghostrunner_hc_9.sav" />
<None Include="Resources\Ghostrunner_lvl1.sav" />
<None Include="Resources\Ghostrunner_lvl10.sav" />
<None Include="Resources\Ghostrunner_lvl11.sav" />
Expand All @@ -115,6 +134,7 @@
<None Include="Resources\Ghostrunner_lvl8.sav" />
<None Include="Resources\Ghostrunner_lvl9.sav" />
<None Include="Resources\Hundo.sav" />
<None Include="Resources\hundoHC.sav" />
<None Include="Resources\Levels.sav" />
<None Include="Resources\newgame.sav" />
<None Include="Resources\Newgame_collectiables.sav" />
Expand Down Expand Up @@ -152,6 +172,8 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Content Include="icon%281%29.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
62 changes: 36 additions & 26 deletions GRUnlocker/InputHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,32 @@ public class InputHandler {
public InputHandler() {
// print intro
Console.WriteLine("════Ghostrunner Unlocker [by DmgVol]════");
Console.WriteLine($"Save path: {(Config.getInstance().IsLocalSavePath ? "local(same directory)" : "remote(from config)")}");
Console.WriteLine($"Save Path: {Config.getInstance().saveLocation}\nSave Type: {Config.getInstance().saveType}");
if(Config.getInstance().DisplayPath) Console.WriteLine($"Path: {Config.getInstance().SaveFilePath}");
Console.WriteLine();
bool SavFileFound = CheckSaveExists(false);
if(SavFileFound) Console.WriteLine($"Save version: {(Unlocker.IsSteam ? $"Steam ({Unlocker.FILE_NAME_Steam})" : $"EGS ({Unlocker.FILE_NAME_EGS})")}\n");


if(SavFileFound) {
// ==unlocking==
options.Add(new Option_UnlockAllCollectibles());
options.Add(new Option_UnlockAllLevels());
options.Add(new Option_UnlockEverything());
options.Add(new Option_UnlockUpToLevel());
options.Add(new Option_NewGameCollectibles());
options.Add(new Option_NewGameSword());
options.Add(new Option_ReplaceSelectedSword());
options.Add(new Option_UnlockAllLevelsHC());
options.Add(new Option_UnlockEverything());
options.Add(new Option_UnlockEverythingHC());
options.Add(new Option_UnlockUpToLevel());
options.Add(new Option_UnlockUpToLevelHC());
options.Add(new Option_NewGameCollectibles());
options.Add(new Option_NewGameSword());
options.Add(new Option_ReplaceSelectedSword());
// ==resetting==
options.Add(new Option_ResetLevelDetails());
options.Add(new Option_ResetCollectibles());

// ==game related==
if(!Config.getInstance().IsLocalSavePath)
if(Config.getInstance().saveLocation == Config.SaveLocation.Remote)
options.Add(new Option_ToggleIntros());
options.Add(new Option_RemoveKevin());
options.Add(new Option_WinterDLC());
}

// == GRUnlocker related==
Expand All @@ -45,23 +50,18 @@ public void Handle() {
}
Console.WriteLine("─────────────────────────────────");

// read input or args if any
string input = "";
if(Program.ARGS != null && Program.ARGS.Length == 1) {
input += Program.ARGS[0][0];
Console.WriteLine("Using args: " + input);
} else {
Console.Write("\nOption:\t");
input = Console.ReadLine();
}
// read input
Console.Write("\nOption:\t");
string input = Console.ReadLine();


// valid?
bool successFlag = true;
int optionNumber;
if(Int32.TryParse(input, out optionNumber) && optionNumber > 0 && optionNumber < options.Count + 1) {
int i = optionNumber - 1;
// special case - unlock up to level, requires more input
if(options[i] is Option_UnlockUpToLevel) {
if(options[i] is Option_UnlockUpToLevel || options[i] is Option_UnlockUpToLevelHC) {
Console.WriteLine("Up to which level to unlock? (1-16)");
Console.WriteLine("─────────────────────────────────");
Console.Write(">");
Expand All @@ -85,7 +85,7 @@ public void Handle() {
}

// print results
if(successFlag)
if(successFlag)
Console.WriteLine("Patched successfully!");
else
Console.WriteLine("Error: failed to patch!\n-Something went wrong, missing permissions/files or corrupted .sav file");
Expand All @@ -107,12 +107,22 @@ private int GetOptionNumber(int min, int max) {

public static bool CheckSaveExists(bool exitIfMissing = true) {
if(!Unlocker.FileExists()) {
if(Config.getInstance().IsLocalSavePath)
Console.WriteLine("Error: Missing .sav file!\n-Make sure the save file is in the same directory as the executable");
else
Console.WriteLine("Error: Missing .sav file!\n-Save file is missing from the given path (config file)");
Console.WriteLine("Error: Missing .sav file!");

if(exitIfMissing) ExitProgram();
// error msg based on save location
switch(Config.getInstance().saveLocation) {
case Config.SaveLocation.Local:
Console.WriteLine("-Make sure the save file is in the same directory as the executable.");
break;
case Config.SaveLocation.Remote:
Console.WriteLine("-Save file is missing from the given path (config file).");
break;
case Config.SaveLocation.Auto:
Console.WriteLine("-Can't find save file.");
break;
}

if(exitIfMissing) ExitProgram();
return false;
}
return true;
Expand All @@ -123,4 +133,4 @@ public static void ExitProgram() {
Environment.Exit(0);
}
}
}
}
32 changes: 29 additions & 3 deletions GRUnlocker/OptionCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,36 @@ public Option_UnlockAllCollectibles() : base("Unlock all collectibles") { }
}

public class Option_UnlockAllLevels : OptionCore {
public Option_UnlockAllLevels() : base("Unlock all levels") { }
public Option_UnlockAllLevels() : base("Unlock all levels (classic levels)") { }
public override bool Patch(int index) => unlocker.UnlockLevels();
}

public class Option_UnlockAllLevelsHC : OptionCore {
public Option_UnlockAllLevelsHC() : base("Unlock all levels (classic + hardcore levels)") { }
public override bool Patch(int index) => unlocker.UnlockLevelsHC();
}


public class Option_UnlockEverything : OptionCore {
public Option_UnlockEverything() : base("Unlock everything (100%)") { }
public Option_UnlockEverything() : base("Unlock everything (100%: classic levels)") { }
public override bool Patch(int index) => unlocker.UnlockAll();
}

public class Option_UnlockEverythingHC : OptionCore {
public Option_UnlockEverythingHC() : base("Unlock everything (100%: classic + hardcore levels)") { }
public override bool Patch(int index) => unlocker.UnlockAllHC();
}

public class Option_UnlockUpToLevel : OptionCore {
public Option_UnlockUpToLevel() : base("Unlock up to a specific level (1-16)") { }
public Option_UnlockUpToLevel() : base("Unlock up to a specific level (1-16) (classic)") { }
public override bool Patch(int index) => unlocker.UnlockUpToLevel(index);
}

public class Option_UnlockUpToLevelHC : OptionCore {
public Option_UnlockUpToLevelHC() : base("Unlock up to a specific level (1-16) (hardcore)") { }
public override bool Patch(int index) => unlocker.UnlockUpToLevelHC(index);
}

public class Option_NewGameCollectibles : OptionCore {
public Option_NewGameCollectibles() : base("New-game with collectibles unlocked") { }
public override bool Patch(int index) => unlocker.NewGameCollectiables();
Expand Down Expand Up @@ -73,4 +89,14 @@ public Option_RemoveKevin() : base("Remove Kevin (the drone)") { }
// Don't worry, nothing is being changed, just a silly little easteregg.
public override bool Patch(int index) => true; // 'LOL NOPE'
}

public class Option_WinterDLC : OptionCore {
public Option_WinterDLC() : base("Unlock Winter DLC (sword+gloves)") { }
// You really think I'll unlock the dlc for free!?? NO! go buy and support the devs! ($1.99)
// Don't worry, nothing is being changed.
public override bool Patch(int index) {
System.Console.WriteLine("What did you expect? go buy it!\nhttps://store.steampowered.com/app/1480500/Ghostrunner__Winter_Pack/\n");
return true;
}
}
}
Loading

0 comments on commit 1d16c29

Please sign in to comment.