Created
February 19, 2019 23:20
-
-
Save ZaneDubya/76bd8faadbb4ffbe09fc964424f9240d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace MacTranslocator { | |
class TranslocateHandler { | |
/// <summary> | |
/// This is the name of the game, the name of the folder in local storage where the game will be run from, | |
/// and the name of the .app folder that contains the game. | |
/// It is not the name of the executable file, use Platform_FilenameExecutable for that. | |
/// </summary> | |
public const string APPLICATION_NAME = "MacTranslocator"; | |
private readonly Action<string> _ShowMessage; | |
private readonly Action _OnFail; | |
private readonly Action _OnSuccess; | |
/// <summary> | |
/// This mode will show an update screen while it checks for patches and then downloads any updates. | |
/// Normally this will only run on compiled versions, not in the debugger. | |
/// Pass parameter forceUpdate==true to force an update regardless of what exe is running. | |
/// </summary> | |
public TranslocateHandler(Action<string> writeDebug, Action onSuccess, Action onFail) { | |
_ShowMessage = writeDebug; | |
_OnSuccess = onSuccess; | |
_OnFail = onFail; | |
} | |
public void Initialize() { | |
ShowMessage($"ModeLoading initializing."); | |
ShowMessage($" Platform is: {PlatformType}"); | |
ShowMessage($" Running in: {Platform_PathCurrentRunningDirectory}"); | |
ShowMessage($" PathExeDir: {Platform_PathExeDirectory}"); | |
ShowMessage($" FilenameExe: {Platform_FilenameExecutable}"); | |
Task.Factory.StartNew(() => { | |
if (!RunUpdateFunctions()) { | |
_OnFail?.Invoke(); | |
} | |
else { | |
_OnSuccess?.Invoke(); | |
} | |
}); | |
} | |
private void ShowMessage(string msg, int waitMS = 0) { | |
_ShowMessage?.Invoke(msg); | |
if (waitMS > 0) { | |
Thread.Sleep(waitMS); | |
} | |
} | |
// === Patch / Update routines live here ===================================================================== | |
// ============================================================================================================ | |
private bool RunUpdateFunctions() { | |
if (!VerifyRunningInClientAppFolder()) { | |
// don't continue with update, allow called method to end program. | |
return false; | |
} | |
return true; | |
} | |
private bool VerifyRunningInClientAppFolder() { | |
string currentDirectory = Platform_PathCurrentRunningDirectory; | |
if (!currentDirectory.Contains(Platform_PathClientApp)) { | |
ShowMessage("Application must be restarted in correct location.", 2000); | |
if (!VerifyDirectoryContents(currentDirectory, Platform_PathClientApp)) { | |
// delete client.app folder, copy in all files in this folder | |
ShowMessage($"Copying application to {Platform_PathClientApp}"); | |
CopyAndReplace(currentDirectory, Platform_PathClientApp); | |
} | |
if (Platform_IsRunningInDebugger) { | |
ShowMessage("Debugger: will not restart."); | |
} | |
else { | |
string pathToExe = Path.Combine(Platform_PathExeDirectory, Platform_FilenameExecutable); | |
Process.Start(pathToExe); | |
return false; | |
} | |
} | |
return true; | |
} | |
private bool VerifyDirectoryContents(string pathSource, string pathDestination, string specificFilenameToCheck = null) { | |
string filePattern = specificFilenameToCheck ?? "*.exe"; | |
ShowMessage($" Verifying files with pattern '{filePattern}':"); | |
ShowMessage($" {pathSource} vs"); | |
ShowMessage($" {pathDestination}"); | |
foreach (string filePath in Directory.GetFiles(pathSource, filePattern, SearchOption.AllDirectories)) { | |
string fileLocalPath = filePath.Remove(0, pathSource.Length); | |
if (fileLocalPath.Length > 0 && fileLocalPath[0] == Path.DirectorySeparatorChar) { | |
fileLocalPath = fileLocalPath.Remove(0, 1); | |
} | |
if (IgnoreLogsAndPbds(fileLocalPath)) { | |
continue; | |
} | |
string fileWeWant = Path.Combine(pathDestination, fileLocalPath); | |
if (File.Exists(fileWeWant)) { | |
ShowMessage($" Path exists: {Platform_RemoveUserPath(fileWeWant)}"); | |
// We should replace files that are older than the current version... | |
// but I haven't written that code yet. | |
} | |
else { | |
ShowMessage($" Path missing: {fileLocalPath}"); | |
return false; | |
} | |
} | |
return true; | |
} | |
private bool IgnoreLogsAndPbds(string filename) { | |
if (Path.GetFileName(filename).StartsWith("log") && Path.GetFileName(filename).EndsWith(".txt")) | |
return true; | |
if (Path.GetExtension(filename) == ".pdb") { | |
return true; | |
} | |
return false; | |
} | |
private void CopyAndReplace(string pathSource, string pathDestination) { | |
if (Directory.Exists(pathDestination)) { | |
Directory.Delete(pathDestination, true); | |
} | |
if (!pathDestination.EndsWith(Path.DirectorySeparatorChar.ToString())) { | |
pathDestination += Path.DirectorySeparatorChar; | |
} | |
//Now Create all of the directories | |
foreach (string dirPath in Directory.GetDirectories(pathSource, "*", SearchOption.AllDirectories)) { | |
Directory.CreateDirectory(dirPath.Replace(pathSource, pathDestination)); | |
} | |
//Copy all the files & Replaces any files with the same name | |
foreach (string newPath in Directory.GetFiles(pathSource, "*.*", SearchOption.AllDirectories)) { | |
if (IgnoreLogsAndPbds(newPath)) { | |
continue; | |
} | |
File.Copy(newPath, newPath.Replace(pathSource, pathDestination), true); | |
} | |
} | |
// === Platform code lives here =============================================================================== | |
// ============================================================================================================ | |
private const int NOT_SET = 0; | |
public const int WINDOWS = 1; | |
public const int MACOS = 2; | |
public const int LINUX = 3; | |
private int _PlatformType = NOT_SET; | |
/// <summary> | |
/// Returns an integer corresponding to the platform type we are running on. | |
/// Possible values are Platform.WINDOWS, Platform.MACOS, and Platform.LINUX. | |
/// Will throw a critical error if it cannot determine the platform. | |
/// </summary> | |
public int PlatformType { | |
get { | |
if (_PlatformType == NOT_SET) { | |
#if SDL | |
string platform = SDL.SDL_GetPlatform(); | |
if (platform.Equals("Windows")) { | |
_PlatformType = WINDOWS; | |
} | |
else if (platform.Equals("Mac OS X")) { | |
_PlatformType = MACOS; | |
} | |
else if (platform.Equals("Linux")) { | |
_PlatformType = LINUX; | |
} | |
else { | |
Tracer.Critical($"Could not determine platform type (unknown type '{platform}')."); | |
} | |
#else | |
_PlatformType = WINDOWS; | |
#endif | |
} | |
return _PlatformType; | |
} | |
} | |
/// <summary> | |
/// Path to the client application folder in the local storage. | |
/// This is not necessarily the path to the folder containing the exectuable file and resources. | |
/// Use PathExeDirectory for that. | |
/// </summary> | |
public string Platform_PathClientApp => Platform_GetPlatformSubDirectory($"{APPLICATION_NAME}.app"); | |
/// <summary> | |
/// This will be true if we are running in the Visual Studio debugger. | |
/// </summary> | |
public bool Platform_IsRunningInDebugger => Debugger.IsAttached; | |
/// <summary> | |
/// This is the filename that is used to start the game. | |
/// On Windows, it will be the name of the client executable. | |
/// On mac, it will be the kickstart binary. | |
/// </summary> | |
public string Platform_FilenameExecutable { | |
get { | |
switch (PlatformType) { | |
case WINDOWS: | |
return AppDomain.CurrentDomain.FriendlyName; | |
case MACOS: | |
return "CommunityClient"; // this is the kickstart script | |
default: | |
return "NoExeFile"; | |
} | |
} | |
} | |
/// <summary> | |
/// This is the directory the application is currently running in. It is not necessarily local storage. | |
/// If it is not local storage, then the application should be copied to local storage and run from there. | |
/// </summary> | |
public string Platform_PathCurrentRunningDirectory { | |
get { | |
switch (PlatformType) { | |
case WINDOWS: | |
return AppDomain.CurrentDomain.BaseDirectory; | |
case MACOS: | |
DirectoryInfo basePath = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent; | |
return basePath.ToString(); | |
default: | |
return "NoPathBaseDirectory"; | |
} | |
} | |
} | |
/// <summary> | |
/// Path to the folder in local storage containing the executable file. | |
/// This is where all the resource/dll/etc. files will be found. | |
/// </summary> | |
public string Platform_PathExeDirectory { | |
get { | |
#if SERVER | |
return PathCurrentRunningDirectory; | |
#else | |
switch (PlatformType) { | |
case WINDOWS: | |
return Platform_PathClientApp; | |
case MACOS: | |
return $"{Platform_PathClientApp}/Contents/MacOS"; | |
default: | |
return "NoPathExeDirectory"; | |
} | |
#endif | |
} | |
} | |
private string Platform_GetPlatformSubDirectory(string subDirectory) { | |
return Path.Combine(Platform_GetPlatformDirectory(), subDirectory); | |
} | |
private string Platform_GetPlatformDirectory() { | |
switch (PlatformType) { | |
case WINDOWS: | |
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Games", APPLICATION_NAME); | |
case MACOS: { | |
string osConfigDir = Environment.GetEnvironmentVariable("HOME"); | |
if (string.IsNullOrEmpty(osConfigDir)) { | |
return "."; // Oh well. | |
} | |
return Path.Combine(osConfigDir, "Library", "Application Support", APPLICATION_NAME); | |
} | |
case LINUX: { | |
string osConfigDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); | |
if (string.IsNullOrEmpty(osConfigDir)) { | |
osConfigDir = Environment.GetEnvironmentVariable("HOME"); | |
if (string.IsNullOrEmpty(osConfigDir)) { | |
return "."; // Oh well. | |
} | |
osConfigDir += "/.local/share"; | |
} | |
return Path.Combine(osConfigDir, APPLICATION_NAME); | |
} | |
default: | |
return "NoPlatformDirectory"; | |
} | |
} | |
/// <summary> | |
/// This is the user path. | |
/// </summary> | |
private readonly string Platform_PathUser = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | |
private string Platform_RemoveUserPath(string path) => path.Replace(Platform_PathUser, "."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment