diff --git a/DMAPI/server_tools.dm b/DMAPI/server_tools.dm index 9ff5b4ee28..f9e5024933 100644 --- a/DMAPI/server_tools.dm +++ b/DMAPI/server_tools.dm @@ -73,7 +73,7 @@ #define SERVICE_VERSION_PARAM "server_service_version" #define SERVICE_INSTANCE_PARAM "server_instance" #define SERVICE_PR_TEST_JSON "prtestjob.json" -#define SERVICE_INTERFACE_DLL "TGServiceInterface.dll" +#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll" #define SERVICE_INTERFACE_FUNCTION "DDEntryPoint" #define SERVICE_CMD_HARD_REBOOT "hard_reboot" diff --git a/TGCommandLine/Program.cs b/TGCommandLine/Program.cs index b455578e7c..1772582cc5 100644 --- a/TGCommandLine/Program.cs +++ b/TGCommandLine/Program.cs @@ -157,7 +157,7 @@ namespace TGCommandLine /// /// The name of the to test /// If , does not output on success - /// if a was achieved with , otherwise + /// if a was achieved with , otherwise static bool CheckInstanceConnectivity(string instanceName, bool silentSuccess) { var res = currentInterface.ConnectToInstance(instanceName); diff --git a/TGCommandLine/TGCommandLine.csproj b/TGCommandLine/TGCommandLine.csproj index aa3d32e639..0c299ad037 100644 --- a/TGCommandLine/TGCommandLine.csproj +++ b/TGCommandLine/TGCommandLine.csproj @@ -18,27 +18,27 @@ tgs.ico - + true - bin\x86\Debug\ + bin\Debug\ DEBUG;TRACE full - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - - bin\x86\Release\ + + bin\Release\ TRACE + bin\x86\Release\TGCommandLine.xml true + true pdbonly - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - true - bin\x86\Release\TGCommandLine.xml diff --git a/TGControlPanel/ControlPanel/ControlPanel.cs b/TGControlPanel/ControlPanel/ControlPanel.cs index f273c62a05..d047906de6 100644 --- a/TGControlPanel/ControlPanel/ControlPanel.cs +++ b/TGControlPanel/ControlPanel/ControlPanel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using TGServiceInterface; +using TGServiceInterface.Components; namespace TGControlPanel { @@ -29,6 +30,11 @@ namespace TGControlPanel { InitializeComponent(); Interface = I; + if (Interface.IsRemoteConnection) + { + var splits = Interface.GetComponent().Version().Split(' '); + Text = String.Format("TGS {0}: {1}:{2}", splits[splits.Length - 1], Interface.HTTPSURL, Interface.HTTPSPort); + } Text += " Instance: " + I.InstanceName; if (Interface.VersionMismatch(out string error) && MessageBox.Show(error, "Warning", MessageBoxButtons.OKCancel) == DialogResult.Cancel) { diff --git a/TGControlPanel/TGControlPanel.csproj b/TGControlPanel/TGControlPanel.csproj index 70c8a110c2..d1b390395f 100644 --- a/TGControlPanel/TGControlPanel.csproj +++ b/TGControlPanel/TGControlPanel.csproj @@ -17,27 +17,27 @@ tgs.ico - + true - bin\x86\Debug\ + bin\Debug\ DEBUG;TRACE full - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - - bin\x86\Release\ + + bin\Release\ TRACE + bin\x86\Release\TGControlPanel.xml true + true pdbonly - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - true - bin\x86\Release\TGControlPanel.xml diff --git a/TGServiceInterface/DreamDaemonBridge.cs b/TGDreamDaemonBridge/DreamDaemonBridge.cs similarity index 84% rename from TGServiceInterface/DreamDaemonBridge.cs rename to TGDreamDaemonBridge/DreamDaemonBridge.cs index 1b09192bb2..c6f401fb89 100644 --- a/TGServiceInterface/DreamDaemonBridge.cs +++ b/TGDreamDaemonBridge/DreamDaemonBridge.cs @@ -2,14 +2,15 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using TGServiceInterface; using TGServiceInterface.Components; -namespace TGServiceInterface +namespace TGDreamDaemonBridge { /// /// Holds the proc that DD calls to access /// - public sealed class DreamDaemonBridge + public static class DreamDaemonBridge { /// /// The proc that DD calls to access @@ -26,7 +27,7 @@ namespace TGServiceInterface parsedArgs.AddRange(args); parsedArgs.RemoveAt(0); using (var I = new Interface()) - if(I.ConnectToInstanceImpl(parsedArgs[0], true).HasFlag(ConnectivityLevel.Connected)) + if(I.ConnectToInstance(parsedArgs[0], true).HasFlag(ConnectivityLevel.Connected)) I.GetComponent().InteropMessage(String.Join(" ", parsedArgs)); } catch { } diff --git a/TGDreamDaemonBridge/FodyWeavers.xml b/TGDreamDaemonBridge/FodyWeavers.xml new file mode 100644 index 0000000000..43fc6a6308 --- /dev/null +++ b/TGDreamDaemonBridge/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/TGDreamDaemonBridge/Properties/AssemblyInfo.cs b/TGDreamDaemonBridge/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..7195e9f298 --- /dev/null +++ b/TGDreamDaemonBridge/Properties/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TGStation Server Service DreamDaemon Bridge")] +[assembly: AssemblyDescription("Used by DreamDaemon to call into the TGStation Server Service")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9a01ef03-8eae-45cb-8b87-4a17bd904557")] diff --git a/TGDreamDaemonBridge/TGDreamDaemonBridge.csproj b/TGDreamDaemonBridge/TGDreamDaemonBridge.csproj new file mode 100644 index 0000000000..99acc47c27 --- /dev/null +++ b/TGDreamDaemonBridge/TGDreamDaemonBridge.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {9A01EF03-8EAE-45CB-8B87-4A17BD904557} + Library + Properties + TGDreamDaemonBridge + TGDreamDaemonBridge + v4.5.2 + 512 + x86 + + + + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + ..\packages\Costura.Fody.1.6.2\lib\dotnet\Costura.dll + False + + + ..\packages\UnmanagedExports.1.2.7\lib\net\RGiesecke.DllExport.Metadata.dll + False + + + + + + + + + + + {ac4e7e8b-f83a-481c-a8b0-8fa4e8ae59ab} + TGServiceInterface + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/TGDreamDaemonBridge/packages.config b/TGDreamDaemonBridge/packages.config new file mode 100644 index 0000000000..3d97405485 --- /dev/null +++ b/TGDreamDaemonBridge/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TGInstallerWrapper/Main.Designer.cs b/TGInstallerWrapper/Main.Designer.cs index 88b82a06a3..885db27148 100644 --- a/TGInstallerWrapper/Main.Designer.cs +++ b/TGInstallerWrapper/Main.Designer.cs @@ -20,6 +20,7 @@ namespace TGInstallerWrapper if (disposing && (components != null)) { components.Dispose(); + CleanTempDir(); } base.Dispose(disposing); } diff --git a/TGInstallerWrapper/Main.cs b/TGInstallerWrapper/Main.cs index 2d941c519a..ab339ad63e 100644 --- a/TGInstallerWrapper/Main.cs +++ b/TGInstallerWrapper/Main.cs @@ -3,10 +3,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using TGServiceInterface; +using TGServiceInterface.Components; namespace TGInstallerWrapper { @@ -14,27 +15,13 @@ namespace TGInstallerWrapper { const string DefaultInstallDir = "TG Station Server"; //keep this in sync with the msi installer - //reflection shit, make sure it matches - const string InterfaceDLL = "TGServiceInterface.dll"; - const string InterfaceNamespace = "TGServiceInterface"; - const string InterfaceComponentsNamespace = InterfaceNamespace + ".Components"; - const string InterfaceClass = InterfaceNamespace + ".Interface"; - const string InterfaceServiceInterface = InterfaceComponentsNamespace + ".ITGSService"; //fuck this typo - const string InterfaceClassVerifyConnection = "VerifyConnection"; - const string InterfaceClassGetComponent = "GetComponent"; - const string InterfaceServiceInterfaceVersion = "Version"; - const string InterfaceServiceInterfacePrepareForUpdate = "PrepareForUpdate"; - - Assembly InterfaceAssembly; - object InterfaceObject; - Type Server, ITGSService; - MethodInfo VerifyConnection, GetComponentITGSService, Version, PrepareForUpdate; - string tempDir; bool installing = false; bool cancelled = false; bool pathIsDefault = true; + Interface Interface; + /// /// Construct an installer form /// @@ -42,7 +29,6 @@ namespace TGInstallerWrapper { InitializeComponent(); SetupTempDir(); - LoadInterfaceFromReflection(); CheckForExistingVersion(); PathTextBox.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), DefaultInstallDir); } @@ -55,7 +41,7 @@ namespace TGInstallerWrapper if (File.Exists(tempDir)) File.Delete(tempDir); else if (Directory.Exists(tempDir)) - Directory.Delete(tempDir); + Directory.Delete(tempDir, true); } catch { } if (File.Exists(tempDir) || Directory.Exists(tempDir)) @@ -63,42 +49,37 @@ namespace TGInstallerWrapper tempDir = Path.GetTempFileName(); File.Delete(tempDir); //we want a dir not a file } - Directory.CreateDirectory(tempDir); - } - - void LoadInterfaceFromReflection() - { - //so this is where we expect to find the interface dll try { - var tmppath = Path.Combine(tempDir, InterfaceDLL); - File.WriteAllBytes(tmppath, Properties.Resources.TGServiceInterface); - InterfaceAssembly = Assembly.LoadFrom(tmppath); //we can't link to it, or load the bytes directly because the thing will complain about mixing the DLLExport code and IL code - Server = InterfaceAssembly.GetType(InterfaceClass); - InterfaceObject = Activator.CreateInstance(Server); - ITGSService = InterfaceAssembly.GetType(InterfaceServiceInterface); - VerifyConnection = Server.GetMethod(InterfaceClassVerifyConnection); - GetComponentITGSService = Server.GetMethod(InterfaceClassGetComponent).MakeGenericMethod(ITGSService); - Version = ITGSService.GetMethod(InterfaceServiceInterfaceVersion); - PrepareForUpdate = ITGSService.GetMethod(InterfaceServiceInterfacePrepareForUpdate); + Directory.CreateDirectory(tempDir); } - catch (Exception e) + catch { - InterfaceAssembly = null; - VersionLabel.Text = "Error: (Could not load interface dll)"; - MessageBox.Show(String.Format("An error occurred while loading {0} (This is an easily preventable bug, please report it)! Error: {1}", InterfaceDLL, e.ToString())); + tempDir = null; } } + void CleanTempDir() { + if(tempDir != null) + try + { + Directory.Delete(tempDir, true); + } + catch { } + } + void CheckForExistingVersion() { - if (InterfaceAssembly == null) - return; - var verifiedConnection = VerifyConnection.Invoke(InterfaceObject, null) == null; + Interface = new Interface(); + var verifiedConnection = Interface.ConnectionStatus().HasFlag(ConnectivityLevel.Administrator); try { - VersionLabel.Text = (string)Version.Invoke(GetComponentITGSService.Invoke(InterfaceObject, null), null); - if (VersionLabel.Text.Contains("v3.0")) //OH GOD!!!! - MessageBox.Show("Warning! Upgrading from version 3.0 may trigger a bug that can delete /config and /data. IT IS STRONGLY RECCOMMENDED THAT YOU BACKUP THESE FOLDERS BEFORE UPDATING!"); + VersionLabel.Text = Interface.GetComponent().Version(); + var isV0 = VersionLabel.Text.Contains("v3.0"); + if (isV0) //OH GOD!!!! + MessageBox.Show("Upgrading from version 3.0 may trigger a bug that can delete /config and /data. IT IS STRONGLY RECCOMMENDED THAT YOU BACKUP THESE FOLDERS BEFORE UPDATING!", "Warning"); + if (isV0 || VersionLabel.Text.Contains("v3.1")) + //Friendly reminger + MessageBox.Show("Upgrading to service version 3.2 will break the 3.1 DMAPI. It is recommended you update your game to the 3.2 API before updating the servive to avoid having to trigger hard restarts.", "Note"); } catch { @@ -114,12 +95,10 @@ namespace TGInstallerWrapper bool TellServiceWereComingForThem() { - if (InterfaceAssembly == null) - return ConfirmDangerousUpgrade(); - var connectionVerified = VerifyConnection.Invoke(InterfaceObject, null) == null; + var connectionVerified = Interface.ConnectionStatus().HasFlag(ConnectivityLevel.Administrator); try { - PrepareForUpdate.Invoke(GetComponentITGSService.Invoke(InterfaceObject, null), null); + Interface.GetComponent().PrepareForUpdate(); Thread.Sleep(3000); //chat messages return true; } diff --git a/TGInstallerWrapper/Properties/Resources.Designer.cs b/TGInstallerWrapper/Properties/Resources.Designer.cs index e3858daec9..cd95f1bb4f 100644 --- a/TGInstallerWrapper/Properties/Resources.Designer.cs +++ b/TGInstallerWrapper/Properties/Resources.Designer.cs @@ -79,15 +79,5 @@ namespace TGInstallerWrapper.Properties { return ((byte[])(obj)); } } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] TGServiceInterface { - get { - object obj = ResourceManager.GetObject("TGServiceInterface", resourceCulture); - return ((byte[])(obj)); - } - } } } diff --git a/TGInstallerWrapper/Properties/Resources.resx b/TGInstallerWrapper/Properties/Resources.resx index daa2b3cb0c..223c76093a 100644 --- a/TGInstallerWrapper/Properties/Resources.resx +++ b/TGInstallerWrapper/Properties/Resources.resx @@ -124,7 +124,4 @@ ..\..\TGServiceInstaller\bin\Release\TGServiceInstaller.msi;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\..\TGServiceInterface\bin\x86\Release\TGServiceInterface.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - \ No newline at end of file diff --git a/TGInstallerWrapper/TGInstallerWrapper.csproj b/TGInstallerWrapper/TGInstallerWrapper.csproj index 7b9fa7692a..ffee3114b1 100644 --- a/TGInstallerWrapper/TGInstallerWrapper.csproj +++ b/TGInstallerWrapper/TGInstallerWrapper.csproj @@ -20,27 +20,27 @@ tgs.ico - + true - bin\x86\Debug\ + bin\Debug\ DEBUG;TRACE full - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - - bin\x86\Release\ + + bin\Release\ TRACE + bin\x86\Release\TG Station Server Installer.xml true + true pdbonly - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - true - bin\x86\Release\TG Station Server Installer.xml @@ -85,6 +85,12 @@ + + + {ac4e7e8b-f83a-481c-a8b0-8fa4e8ae59ab} + TGServiceInterface + + diff --git a/TGServerService/EventID.cs b/TGServerService/EventID.cs index 9562de35aa..c36abca48d 100644 --- a/TGServerService/EventID.cs +++ b/TGServerService/EventID.cs @@ -251,11 +251,11 @@ namespace TGServerService /// /// Info: When the dll is updated for the /// - InterfaceDLLUpdated = 5800, + BridgeDLLUpdated = 5800, /// /// Error: An error occurred while updating the dll for the /// - InterfaceDLLUpdateFail = 5900, + BridgeDLLUpdateFail = 5900, /// /// Error: An error occurred while starting the /// diff --git a/TGServerService/ProcessExtension.cs b/TGServerService/ProcessExtension.cs index 74758b40f3..ecf336a9a0 100644 --- a/TGServerService/ProcessExtension.cs +++ b/TGServerService/ProcessExtension.cs @@ -7,7 +7,7 @@ namespace TGServerService /// /// Helpers to ing and a . Lightly massaged code from https://stackoverflow.com/a/13109774. Documentation linked from MSDN on 20/10/2017 /// - public static class ProcessExtension + static class ProcessExtension { /// /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx diff --git a/TGServerService/ProjectInstaller.cs b/TGServerService/ProjectInstaller.cs index 2f4d75524d..f5c0f1a911 100644 --- a/TGServerService/ProjectInstaller.cs +++ b/TGServerService/ProjectInstaller.cs @@ -8,7 +8,7 @@ namespace TGServerService /// This tells the .msi there is a Windows in this that needs installation /// [RunInstaller(true)] - public partial class ProjectInstaller : Installer + public sealed class ProjectInstaller : Installer { /// /// Construct a diff --git a/TGServerService/ServerInstance/Compiler.cs b/TGServerService/ServerInstance/Compiler.cs index 06fe225266..e7432e0d17 100644 --- a/TGServerService/ServerInstance/Compiler.cs +++ b/TGServerService/ServerInstance/Compiler.cs @@ -35,12 +35,10 @@ namespace TGServerService const string BDirTest = GameDirB + LiveFile; const string LiveDirTest = GameDirLive + LiveFile; - const string InterfaceDLLName = "TGServiceInterface.dll"; - object CompilerLock = new object(); CompilerStatus compilerCurrentStatus; string lastCompilerError; - + Thread CompilerThread; bool compilationCancellationRequestation = false; bool canCancelCompilation = false; @@ -85,7 +83,7 @@ namespace TGServerService if (CompilerThread == null || !CompilerThread.IsAlive) return; CompilerThread.Abort(); //this will safely kill dm - InitCompiler(); //also cleanup + InitCompiler(); //also cleanup } } @@ -101,7 +99,7 @@ namespace TGServerService { return compilerCurrentStatus == CompilerStatus.Uninitialized || compilerCurrentStatus == CompilerStatus.Initialized; } - + /// public bool Initialize() { @@ -120,7 +118,7 @@ namespace TGServerService //what is says on the tin CompilerStatus IsInitialized() { - if (File.Exists(RelativePath(Path.Combine(GameDirLive, InterfaceDLLName)))) //its a good tell, jim + if (File.Exists(RelativePath(Path.Combine(GameDirLive, BridgeDLLName)))) //its a good tell, jim return CompilerStatus.Initialized; return CompilerStatus.Uninitialized; } @@ -128,13 +126,13 @@ namespace TGServerService //we need to remove symlinks before we can recursively delete void CleanGameFolder() { - var GameDirAInterface = RelativePath(Path.Combine(GameDirA, InterfaceDLLName)); - if (Directory.Exists(GameDirAInterface)) - Directory.Delete(GameDirAInterface); + var GameDirABridge = RelativePath(Path.Combine(GameDirA, BridgeDLLName)); + if (Directory.Exists(GameDirABridge)) + Directory.Delete(GameDirABridge); - var GameDirBInterface = RelativePath(Path.Combine(GameDirB, InterfaceDLLName)); - if (Directory.Exists(GameDirBInterface)) - Directory.Delete(GameDirBInterface); + var GameDirBBridge = RelativePath(Path.Combine(GameDirB, BridgeDLLName)); + if (Directory.Exists(GameDirBBridge)) + Directory.Delete(GameDirBBridge); var rgdl = RelativePath(GameDirLive); if (Directory.Exists(rgdl)) @@ -193,9 +191,9 @@ namespace TGServerService CreateSymlink(RelativePath(Path.Combine(GameDirA, I)), RelativePath(Path.Combine(StaticDirs, I))); } - var ridlln = RelativePath(InterfaceDLLName); - CreateSymlink(RelativePath(Path.Combine(GameDirA, InterfaceDLLName)), ridlln); - CreateSymlink(RelativePath(Path.Combine(GameDirB, InterfaceDLLName)), ridlln); + var rbdlln = RelativePath(BridgeDLLName); + CreateSymlink(RelativePath(Path.Combine(GameDirA, BridgeDLLName)), rbdlln); + CreateSymlink(RelativePath(Path.Combine(GameDirB, BridgeDLLName)), rbdlln); CreateSymlink(RelativePath(GameDirLive), RelativePath(GameDirA)); @@ -226,7 +224,7 @@ namespace TGServerService return; } CompileImpl(); - } + } //Returns the A or B dir in which the game is NOT running string GetStagingDir() @@ -265,7 +263,7 @@ namespace TGServerService { File.Delete(rsclock); } - catch //held open by byond + catch //held open by byond { //This means there is a staged update waiting to be applied, we have to unstage it before we can work Directory.Delete(RelativePath(GameDirLive)); @@ -348,7 +346,7 @@ namespace TGServerService resurrectee = GetStagingDir(); //non-relative var Config = GetCachedRepoConfig(); - var deleteExcludeList = new List { InterfaceDLLName }; + var deleteExcludeList = new List { BridgeDLLName }; deleteExcludeList.AddRange(Config.StaticDirectoryPaths); deleteExcludeList.AddRange(Config.DLLPaths); Program.DeleteDirectory(resurrectee, true, deleteExcludeList); @@ -369,8 +367,8 @@ namespace TGServerService CreateSymlink(the_path, RelativePath(Path.Combine(StaticDirs, I))); } - if (!File.Exists(Path.Combine(resurrectee, InterfaceDLLName))) - CreateSymlink(Path.Combine(resurrectee, InterfaceDLLName), RelativePath(InterfaceDLLName)); + if (!File.Exists(Path.Combine(resurrectee, BridgeDLLName))) + CreateSymlink(Path.Combine(resurrectee, BridgeDLLName), RelativePath(BridgeDLLName)); deleteExcludeList.Add(".git"); Program.CopyDirectory(RelativePath(RepoPath), resurrectee, deleteExcludeList); diff --git a/TGServerService/ServerInstance/DreamDaemon.cs b/TGServerService/ServerInstance/DreamDaemon.cs index efc48fc4dd..6f14cf5376 100644 --- a/TGServerService/ServerInstance/DreamDaemon.cs +++ b/TGServerService/ServerInstance/DreamDaemon.cs @@ -151,7 +151,7 @@ namespace TGServerService //autostart the server if (Config.Autostart) //break this off so we don't hold up starting the service - ThreadPool.QueueUserWorkItem( _ => { Start(); }); + ThreadPool.QueueUserWorkItem(_ => { Start(); }); } /// @@ -178,7 +178,7 @@ namespace TGServerService else if (Detach) Config.ReattachRequired = false; Stop(); - if(pcpu != null) + if (pcpu != null) pcpu.Dispose(); if (RenameLog) try @@ -267,7 +267,7 @@ namespace TGServerService { if (DaemonStatus() == DreamDaemonStatus.Offline) return Start(); - lock(restartLock) + lock (restartLock) { if (RestartInProgress) return "Restart already in progress"; @@ -276,8 +276,8 @@ namespace TGServerService SendMessage("DD: Hard restart triggered", MessageType.WatchdogInfo); Stop(); var res = Start(); - if(res != null) - lock(restartLock) + if (res != null) + lock (restartLock) { RestartInProgress = false; } @@ -496,7 +496,7 @@ namespace TGServerService } return StartImpl(false); } - + /// /// Translate the configured level into a byond command line param /// @@ -519,28 +519,47 @@ namespace TGServerService } /// - /// Copies from the program directory to the the directory + /// Copies from the program directory to the the directory /// /// If , overwrites the 's current interface .dll if it exists - void UpdateInterfaceDll(bool overwrite) + void UpdateBridgeDll(bool overwrite) { - var ridlln = RelativePath(InterfaceDLLName); - var FileExists = File.Exists(ridlln); + var rbdlln = RelativePath(BridgeDLLName); + var FileExists = File.Exists(rbdlln); if (FileExists && !overwrite) return; //Copy the interface dll to the static dir - var InterfacePath = Assembly.GetAssembly(typeof(DreamDaemonBridge)).Location; + + var InterfacePath = Assembly.GetAssembly(typeof(Interface)).Location; + //bridge is installed next to the interface + var BridgePath = Path.Combine(Path.GetDirectoryName(InterfacePath), BridgeDLLName); +#if DEBUG + //We could be debugging from the project directory + if (!File.Exists(BridgePath)) + //A little hackish debug mode doctoring never hurt anyone + BridgePath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(InterfacePath)))), "TGDreamDaemonBridge/bin/x86/Debug", BridgeDLLName); +#endif + try + { + //Use reflection to ensure these are the droids we're looking for + Assembly.ReflectionOnlyLoadFrom(BridgePath).GetType(DreamDaemonBridgeType, true); + } + catch (Exception e) + { + WriteError(String.Format("Unable to locate {0}! Error: {1}", BridgeDLLName, e.ToString()), EventID.BridgeDLLUpdateFail); + return; + } + try { if (FileExists) { - var Old = File.ReadAllBytes(ridlln); - var New = File.ReadAllBytes(InterfacePath); + var Old = File.ReadAllBytes(rbdlln); + var New = File.ReadAllBytes(BridgePath); if (Old.SequenceEqual(New)) return; //no need } - File.Copy(InterfacePath, ridlln, overwrite); - WriteInfo("Updated interface DLL", EventID.InterfaceDLLUpdated); + File.Copy(BridgePath, rbdlln, overwrite); } catch { @@ -548,18 +567,20 @@ namespace TGServerService { //ok the things being stupid and hasn't released the dll yet, try ONCE more Thread.Sleep(1000); - File.Copy(InterfacePath, ridlln, overwrite); + File.Copy(InterfacePath, rbdlln, overwrite); } catch (Exception e) { //intentionally using the fi - WriteError("Failed to update interface DLL! Error: " + e.ToString(), EventID.InterfaceDLLUpdateFail); + WriteError("Failed to update bridge DLL! Error: " + e.ToString(), EventID.BridgeDLLUpdateFail); + return; } } + WriteInfo("Updated interface DLL", EventID.BridgeDLLUpdated); } /// - /// Clears the current , calls with a parameter, and attempts to start the DreamDaemon + /// Clears the current , calls with a parameter, and attempts to start the DreamDaemon /// /// If , sets to a new pointing to and starts it /// on success, error message on failure @@ -578,7 +599,7 @@ namespace TGServerService GenCommsKey(); StartingSecurity = Config.Security; Proc.StartInfo.Arguments = String.Format("{0} -port {1} {5}-close -verbose -params \"server_service={3}&server_service_version={4}&{6}={7}\" -{2} -public", DMB, Config.Port, SecurityWord(), serviceCommsKey, Version(), Config.Webclient ? "-webclient " : "", SPInstanceName, Config.Name); - UpdateInterfaceDll(true); + UpdateBridgeDll(true); lock (topicLock) { GameAPIVersion = null; //needs updating @@ -715,7 +736,8 @@ namespace TGServerService /// public void SetWebclient(bool on) { - lock (watchdogLock) { + lock (watchdogLock) + { var diff = on != Config.Webclient; if (diff) { diff --git a/TGServerService/ServerInstance/Interop.cs b/TGServerService/ServerInstance/Interop.cs index 3ce9a2cd96..ba64d4a372 100644 --- a/TGServerService/ServerInstance/Interop.cs +++ b/TGServerService/ServerInstance/Interop.cs @@ -49,6 +49,19 @@ namespace TGServerService const string CCPAdminOnly = "admin_only"; const string CCPRequiredParameters = "required_parameters"; + /// + /// The file name of the .dll that contains the bridge class + /// + const string BridgeDLLName = "TGDreamDaemonBridge.dll"; + /// + /// The namespace that contains the bridge class. Used for reflection + /// + const string DreamDaemonBridgeNamespace = "TGDreamDaemonBridge"; + /// + /// The bridge class. Used for reflection + /// + const string DreamDaemonBridgeType = DreamDaemonBridgeNamespace + ".DreamDaemonBridge"; + List ServerChatCommands; void LoadServerChatCommands() @@ -172,34 +185,33 @@ namespace TGServerService lock (topicLock) { if (!CheckAPIVersionConstraints()) return "Incompatible API!"; + + StringBuilder stringPacket = new StringBuilder(); + stringPacket.Append((char)'\x00', 8); + stringPacket.Append('?' + topicdata); + stringPacket.Append((char)'\x00'); + string fullString = stringPacket.ToString(); + var packet = Encoding.ASCII.GetBytes(fullString); + packet[1] = 0x83; + var FinalLength = packet.Length - 4; + if (FinalLength > UInt16.MaxValue) + return "Error: Topic too long"; + + var lengthBytes = BitConverter.GetBytes((ushort)FinalLength); + + packet[2] = lengthBytes[1]; //fucking endianess + packet[3] = lengthBytes[0]; + + var returnedString = "NULL"; + var returnedData = new byte[UInt16.MaxValue]; using (var topicSender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = 5000, ReceiveTimeout = 5000 }) - { try { topicSender.Connect(IPAddress.Loopback, port); - - StringBuilder stringPacket = new StringBuilder(); - stringPacket.Append((char)'\x00', 8); - stringPacket.Append('?' + topicdata); - stringPacket.Append((char)'\x00'); - string fullString = stringPacket.ToString(); - var packet = Encoding.ASCII.GetBytes(fullString); - packet[1] = 0x83; - var FinalLength = packet.Length - 4; - if (FinalLength > UInt16.MaxValue) - return "Error: Topic too long"; - - var lengthBytes = BitConverter.GetBytes((ushort)FinalLength); - - packet[2] = lengthBytes[1]; //fucking endianess - packet[3] = lengthBytes[0]; - topicSender.Send(packet); - string returnedString = "NULL"; try { - var returnedData = new byte[UInt16.MaxValue]; topicSender.Receive(returnedData); var raw_string = Encoding.ASCII.GetString(returnedData).TrimEnd(new char[] { (char)0 }).Trim(); if (raw_string.Length > 6) @@ -213,14 +225,13 @@ namespace TGServerService { topicSender.Shutdown(SocketShutdown.Both); } - - return returnedString; } catch { return "Topic delivery failed!"; } - } + + return returnedString; } } diff --git a/TGServerService/ServerInstance/Repository.cs b/TGServerService/ServerInstance/Repository.cs index 1f6368355a..b39e697567 100644 --- a/TGServerService/ServerInstance/Repository.cs +++ b/TGServerService/ServerInstance/Repository.cs @@ -96,7 +96,7 @@ namespace TGServerService { Directory.CreateDirectory(RelativePath(RepoKeyDir)); if(Exists()) - UpdateInterfaceDll(false); + UpdateBridgeDll(false); if(LoadRepo() == null) DisableGarbageCollectionNoLock(); //start the autoupdate timer @@ -338,7 +338,7 @@ namespace TGServerService void InitialConfigureRepository() { Directory.CreateDirectory(RelativePath(StaticDirs)); - UpdateInterfaceDll(false); + UpdateBridgeDll(false); UpdateTGS3Json(); var Config = GetCachedRepoConfig(); //RepoBusy is set if we're here foreach(var I in Config.StaticDirectoryPaths) diff --git a/TGServerService/TGServerService.csproj b/TGServerService/TGServerService.csproj index 4e5f0cd8c2..375c542010 100644 --- a/TGServerService/TGServerService.csproj +++ b/TGServerService/TGServerService.csproj @@ -19,27 +19,27 @@ tgs.ico - + true - bin\x86\Debug\ + bin\Debug\ DEBUG;TRACE full - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - - bin\x86\Release\ + + bin\Release\ TRACE + bin\x86\Release\TGServerService.xml true + true pdbonly - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset true - true - bin\x86\Release\TGServerService.xml diff --git a/TGServiceInstaller/Product.wxs b/TGServiceInstaller/Product.wxs index a43f25374b..0a917fac53 100644 --- a/TGServiceInstaller/Product.wxs +++ b/TGServiceInstaller/Product.wxs @@ -119,6 +119,9 @@ + + + diff --git a/TGServiceInstaller/TGServiceInstaller.wixproj b/TGServiceInstaller/TGServiceInstaller.wixproj index fd47e7c7f5..dbe628e0fd 100644 --- a/TGServiceInstaller/TGServiceInstaller.wixproj +++ b/TGServiceInstaller/TGServiceInstaller.wixproj @@ -40,6 +40,14 @@ Binaries;Content;Satellites INSTALLFOLDER + + TGDreamDaemonBridge + {9a01ef03-8eae-45cb-8b87-4a17bd904557} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + TGServerService {f32eda25-0855-411c-af5e-f0d042917e2d} diff --git a/TGServiceInterface/Interface.cs b/TGServiceInterface/Interface.cs index 1d3cb74ad5..57e024527e 100644 --- a/TGServiceInterface/Interface.cs +++ b/TGServiceInterface/Interface.cs @@ -49,12 +49,12 @@ namespace TGServiceInterface /// /// If this is set, we will try and connect to an HTTPS server running at this address /// - readonly string HTTPSURL; + public readonly string HTTPSURL; /// /// The port used by the service /// - readonly ushort HTTPSPort; + public readonly ushort HTTPSPort; /// /// Username for remote operations @@ -149,29 +149,19 @@ namespace TGServiceInterface /// Targets as the instance to use with . Closes all connections to any previous instance /// /// The name of the instance to connect to + /// If set to , skips the connectivity and authentication checks, sets , and returns /// The apporopriate - public ConnectivityLevel ConnectToInstance(string instanceName = null) + public ConnectivityLevel ConnectToInstance(string instanceName = null, bool skipChecks = false) { if (instanceName == null) instanceName = InstanceName; - return ConnectToInstanceImpl(instanceName, false); - } - - /// - /// Targets as the instance to use with . Closes all connections to any previous instance. Sets - /// - /// The name of the instance to connect to - /// If set to , skips the connectivity and authentication checks and returns - /// The apporopriate - internal ConnectivityLevel ConnectToInstanceImpl(string instanceName, bool skipAuthChecks) - { - if (!ConnectionStatus().HasFlag(ConnectivityLevel.Connected)) + if (!skipChecks && !ConnectionStatus().HasFlag(ConnectivityLevel.Connected)) return ConnectivityLevel.None; var prevInstance = InstanceName; if (prevInstance != instanceName) CloseAllChannels(false); InstanceName = instanceName; - if (skipAuthChecks) + if (skipChecks) return ConnectivityLevel.Connected; try { @@ -201,6 +191,11 @@ namespace TGServiceInterface } } + /// + /// Checks if the is setup for a remote connection + /// + public bool IsRemoteConnection { get { return HTTPSURL != null; } } + /// /// Closes all s stored in and clears it /// @@ -322,7 +317,7 @@ namespace TGServiceInterface var accessPath = instanceName == null ? MasterInterfaceName : String.Format("{0}/{1}", InstanceInterfaceName, instanceName); var InterfaceName = typeof(T).Name; - if (HTTPSURL == null) + if (!IsRemoteConnection) { var res2 = new ChannelFactory( new NetNamedPipeBinding { SendTimeout = new TimeSpan(0, 0, 30), MaxReceivedMessageSize = TransferLimitLocal }, new EndpointAddress(String.Format("net.pipe://localhost/{0}/{1}", accessPath, InterfaceName))); //10 megs diff --git a/TGServiceInterface/TGServiceInterface.csproj b/TGServiceInterface/TGServiceInterface.csproj index dc0ee574d4..5e9befc3be 100644 --- a/TGServiceInterface/TGServiceInterface.csproj +++ b/TGServiceInterface/TGServiceInterface.csproj @@ -15,31 +15,28 @@ tgs.ico - + true - bin\x86\Debug\ + bin\Debug\ DEBUG;TRACE full - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset - - bin\x86\Release\ + + bin\Release\ TRACE + bin\x86\Release\TGServiceInterface.xml true + true pdbonly - x86 + AnyCPU prompt MinimumRecommendedRules.ruleset - true - bin\x86\Release\TGServiceInterface.xml + false - - ..\packages\UnmanagedExports.1.2.7\lib\net\RGiesecke.DllExport.Metadata.dll - False - @@ -57,7 +54,6 @@ - @@ -75,8 +71,6 @@ - - \ No newline at end of file diff --git a/TGServiceInterface/packages.config b/TGServiceInterface/packages.config deleted file mode 100644 index cb56911aa6..0000000000 --- a/TGServiceInterface/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/TGStationServer3.sln b/TGStationServer3.sln index 346a49d8d1..00d427c311 100644 --- a/TGStationServer3.sln +++ b/TGStationServer3.sln @@ -86,34 +86,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{287B .github\CONTRIBUTING.md = .github\CONTRIBUTING.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TGDreamDaemonBridge", "TGDreamDaemonBridge\TGDreamDaemonBridge.csproj", "{9A01EF03-8EAE-45CB-8B87-4A17BD904557}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Debug|x86.ActiveCfg = Debug|x86 - {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Debug|x86.Build.0 = Debug|x86 - {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Release|x86.ActiveCfg = Release|x86 - {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Release|x86.Build.0 = Release|x86 - {394E7643-6B8C-416F-AB18-95AC12648CDC}.Debug|x86.ActiveCfg = Debug|x86 - {394E7643-6B8C-416F-AB18-95AC12648CDC}.Debug|x86.Build.0 = Debug|x86 - {394E7643-6B8C-416F-AB18-95AC12648CDC}.Release|x86.ActiveCfg = Release|x86 - {394E7643-6B8C-416F-AB18-95AC12648CDC}.Release|x86.Build.0 = Release|x86 - {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Debug|x86.ActiveCfg = Debug|x86 - {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Debug|x86.Build.0 = Debug|x86 - {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Release|x86.ActiveCfg = Release|x86 - {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Release|x86.Build.0 = Release|x86 - {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Debug|x86.ActiveCfg = Debug|x86 - {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Debug|x86.Build.0 = Debug|x86 - {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Release|x86.ActiveCfg = Release|x86 - {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Release|x86.Build.0 = Release|x86 - {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Debug|x86.ActiveCfg = Debug|x86 - {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Release|x86.ActiveCfg = Release|x86 - {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Release|x86.Build.0 = Release|x86 - {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Debug|x86.ActiveCfg = Debug|x86 - {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Release|x86.ActiveCfg = Release|x86 - {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Release|x86.Build.0 = Release|x86 + {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F32EDA25-0855-411C-AF5E-F0D042917E2D}.Release|Any CPU.Build.0 = Release|Any CPU + {394E7643-6B8C-416F-AB18-95AC12648CDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {394E7643-6B8C-416F-AB18-95AC12648CDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {394E7643-6B8C-416F-AB18-95AC12648CDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {394E7643-6B8C-416F-AB18-95AC12648CDC}.Release|Any CPU.Build.0 = Release|Any CPU + {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89191F69-B18E-4B59-B72E-E12F9B6811A0}.Release|Any CPU.Build.0 = Release|Any CPU + {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC4E7E8B-F83A-481C-A8B0-8FA4E8AE59AB}.Release|Any CPU.Build.0 = Release|Any CPU + {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Release|Any CPU.ActiveCfg = Release|x86 + {154435F6-0890-42D4-9AEC-B743D4FBC1CB}.Release|Any CPU.Build.0 = Release|x86 + {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8956D4C3-BFB9-448E-BF5F-EE7E6F9996F9}.Release|Any CPU.Build.0 = Release|Any CPU + {9A01EF03-8EAE-45CB-8B87-4A17BD904557}.Debug|Any CPU.ActiveCfg = Debug|x86 + {9A01EF03-8EAE-45CB-8B87-4A17BD904557}.Debug|Any CPU.Build.0 = Debug|x86 + {9A01EF03-8EAE-45CB-8B87-4A17BD904557}.Release|Any CPU.ActiveCfg = Release|x86 + {9A01EF03-8EAE-45CB-8B87-4A17BD904557}.Release|Any CPU.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tools/TGS3Build.ps1 b/Tools/TGS3Build.ps1 index 9b845ad567..911789d56e 100644 --- a/Tools/TGS3Build.ps1 +++ b/Tools/TGS3Build.ps1 @@ -1,5 +1,5 @@ $bf = $Env:APPVEYOR_BUILD_FOLDER -$src = "$bf\TGInstallerWrapper\bin\x86\Release" +$src = "$bf\TGInstallerWrapper\bin\Release" $version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$src\TG Station Server Installer.exe").FileVersion $doxdir = "C:\tgsdox" @@ -43,9 +43,9 @@ $destination_md5sha = "$bf\MD5-SHA1-Server-v$version.txt" $src2 = "$bf\ClientApps" [system.io.directory]::CreateDirectory($src2) -Copy-Item "$bf\TGCommandLine\bin\x86\Release\TGCommandLine.exe" "$src2\TGCommandLine.exe" -Copy-Item "$bf\TGControlPanel\bin\x86\Release\TGControlPanel.exe" "$src2\TGControlPanel.exe" -Copy-Item "$bf\TGServiceInterface\bin\x86\Release\TGServiceInterface.dll" "$src2\TGServiceInterface.dll" +Copy-Item "$bf\TGCommandLine\bin\Release\TGCommandLine.exe" "$src2\TGCommandLine.exe" +Copy-Item "$bf\TGControlPanel\bin\Release\TGControlPanel.exe" "$src2\TGControlPanel.exe" +Copy-Item "$bf\TGServiceInterface\bin\Release\TGServiceInterface.dll" "$src2\TGServiceInterface.dll" $dest2 = "$bf\TGS3-Client-v$version.zip" diff --git a/Version.cs b/Version.cs index 8255119c01..fba77566f8 100644 --- a/Version.cs +++ b/Version.cs @@ -12,6 +12,6 @@ using System.Reflection; // [assembly: AssemblyVersion("1.0.*")] //It's impossible to make these a define, don't say I didn't warn you -[assembly: AssemblyVersion("3.1.6.5")] -[assembly: AssemblyFileVersion("3.1.6.5")] -[assembly: AssemblyInformationalVersion("3.1.6.5")] +[assembly: AssemblyVersion("3.1.6.6")] +[assembly: AssemblyFileVersion("3.1.6.6")] +[assembly: AssemblyInformationalVersion("3.1.6.6")] diff --git a/appveyor.yml b/appveyor.yml index 11c3ad0381..a7785a0bf0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,6 +18,8 @@ artifacts: name: MD5SHA1Client cache: - packages -> **\packages.config + - C:\ProgramData\chocolatey\bin -> appveyor.yml + - C:\ProgramData\chocolatey\lib -> appveyor.yml install: - choco install fciv doxygen.portable graphviz.portable before_build: @@ -30,7 +32,7 @@ build: after_build: - ps: .\Tools\TGS3Build.ps1 - ps: if($env:APPVEYOR_REPO_COMMIT_MESSAGE -match "\[TGSDeploy\]"){$env:TGSDeploy = "Do it."} - - ps: $env:TGSVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$env:APPVEYOR_BUILD_FOLDER/TGServerService/bin/x86/Release/TGServerService.exe").FileVersion + - ps: $env:TGSVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$env:APPVEYOR_BUILD_FOLDER/TGServerService/bin/Release/TGServerService.exe").FileVersion deploy: - provider: GitHub release: "tgstation-server-v$(TGSVersion)"