diff --git a/TShock.4.OTAPI.sln b/TShock.4.OTAPI.sln index f5a0c1eea..65b61b4c7 100644 --- a/TShock.4.OTAPI.sln +++ b/TShock.4.OTAPI.sln @@ -18,7 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documents", "Documents", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShock.Modifications.SSC", "TShock.Modifications.SSC\TShock.Modifications.SSC.csproj", "{23EA4516-79FF-4DE4-AE92-3F3D69A906CA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShock.Modifications.UnicodeInput", "TShock.Modifications.UnicodeInput\TShock.Modifications.UnicodeInput.csproj", "{AC441C8A-EA6B-416F-9961-FA944131AFB6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShock.Modifications.Platform", "TShock.Modifications.Platform\TShock.Modifications.Platform.csproj", "{AC441C8A-EA6B-416F-9961-FA944131AFB6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/TShock.Modifications.Platform/Callbacks/PlatformConstructorCallback.cs b/TShock.Modifications.Platform/Callbacks/PlatformConstructorCallback.cs new file mode 100644 index 000000000..51c6729a3 --- /dev/null +++ b/TShock.Modifications.Platform/Callbacks/PlatformConstructorCallback.cs @@ -0,0 +1,60 @@ +using System; +using System.Runtime.InteropServices; + +namespace Mintaka.Modifications.Platform.Callbacks +{ + internal class PlatformConstructorCallback + { + internal static void ChangePlatform(ref ReLogic.OS.Platform platform) + { + Type type; + + switch (Environment.OSVersion.Platform) + { + case PlatformID.Unix: + type = typeof(ReLogic.OS.Platform).Assembly.GetType(IsRunningOnMac() ? "ReLogic.OS.OsxPlatform" : "ReLogic.OS.LinuxPlatform"); + break; + case PlatformID.Win32NT: + type = typeof(ReLogic.OS.Platform).Assembly.GetType("ReLogic.OS.WindowsPlatform"); + break; + default: + throw new NotSupportedException(); + } + + platform = (ReLogic.OS.Platform) Activator.CreateInstance(type); + } + + [DllImport("libc")] + private static extern int uname(IntPtr buf); + + private static bool IsRunningOnMac() + { + var buf = IntPtr.Zero; + try + { + buf = Marshal.AllocHGlobal(8192); + // This is a hacktastic way of getting sysname from uname () + if (uname(buf) == 0) + { + string os = Marshal.PtrToStringAnsi(buf); + if (os == "Darwin") + { + return true; + } + } + } + catch + { + // ignored + } + finally + { + if (buf != IntPtr.Zero) + { + Marshal.FreeHGlobal(buf); + } + } + return false; + } + } +} diff --git a/TShock.Modifications.Platform/PlatformModification.cs b/TShock.Modifications.Platform/PlatformModification.cs new file mode 100644 index 000000000..49ddc4361 --- /dev/null +++ b/TShock.Modifications.Platform/PlatformModification.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil.Cil; +using OTAPI.Patcher.Engine.Modification; + +namespace Mintaka.Modifications.Platform +{ + /// + /// This modification will make OTAPI initialized with right platform rather than Windows platform. + /// This should fix different world path OTAPI used on macOS + /// In addition, the console input will also be fixed. + /// + public class PlatformModification : ModificationBase + { + public override IEnumerable AssemblyTargets => new[] + { + "OTAPI, Version=1.3.5.3, Culture=neutral, PublicKeyToken=null" + }; + + public override string Description => "Enforcing OTAPI to load right platform..."; + + public override void Run() + { + ReLogic.OS.Platform temp = null; + var changePlatformMethodDefinition = SourceDefinition.MainModule.Import(Method(() => Callbacks.PlatformConstructorCallback.ChangePlatform(ref temp))); + + var field = Field(() => ReLogic.OS.Platform.Current); + var cctor = Type().Methods.Single(m => m.Name == ".cctor"); + var instructions = cctor.Body.Instructions; + + if (instructions?.Count != 3 || instructions[1].OpCode != OpCodes.Stsfld || instructions[1].Operand != field) + { + throw new NotSupportedException("Could not patch Platform..cctor()"); + } + + var processor = cctor.Body.GetILProcessor(); + + processor.Body.Instructions.Clear(); + + processor.Append(Instruction.Create(OpCodes.Ldsflda, field)); + processor.Append(Instruction.Create(OpCodes.Call, changePlatformMethodDefinition)); + processor.Append(Instruction.Create(OpCodes.Ret)); + } + + } +} diff --git a/TShock.Modifications.UnicodeInput/Properties/AssemblyInfo.cs b/TShock.Modifications.Platform/Properties/AssemblyInfo.cs similarity index 76% rename from TShock.Modifications.UnicodeInput/Properties/AssemblyInfo.cs rename to TShock.Modifications.Platform/Properties/AssemblyInfo.cs index 185fd322f..b6f20e964 100644 --- a/TShock.Modifications.UnicodeInput/Properties/AssemblyInfo.cs +++ b/TShock.Modifications.Platform/Properties/AssemblyInfo.cs @@ -1,16 +1,15 @@ using System.Reflection; -using System.Runtime.CompilerServices; 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("Mintaka.Modifications.UnicodeInput")] -[assembly: AssemblyDescription("Modifies the TerrariaServer console I/O to make it compatible with macOS/Linux")] +[assembly: AssemblyTitle("Mintaka.Modifications.Platform")] +[assembly: AssemblyDescription("Enforcing OTAPI to load right platform")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Mintaka.Modifications.UnicodeInput")] -[assembly: AssemblyCopyright("Copyright © Tyler Watson 2017")] +[assembly: AssemblyProduct("Mintaka.Modifications.Platform")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/TShock.Modifications.UnicodeInput/TShock.Modifications.UnicodeInput.csproj b/TShock.Modifications.Platform/TShock.Modifications.Platform.csproj similarity index 94% rename from TShock.Modifications.UnicodeInput/TShock.Modifications.UnicodeInput.csproj rename to TShock.Modifications.Platform/TShock.Modifications.Platform.csproj index d20ba6528..8e54529ce 100644 --- a/TShock.Modifications.UnicodeInput/TShock.Modifications.UnicodeInput.csproj +++ b/TShock.Modifications.Platform/TShock.Modifications.Platform.csproj @@ -8,8 +8,8 @@ {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Library Properties - TShock.Modifications.UnicodeInput - TShock.Modifications.UnicodeInput + Mintaka.Modifications.Platform + TShock.Modifications.Platform v4.5.2 512 6 @@ -64,9 +64,9 @@ - + - + diff --git a/TShock.Modifications.UnicodeInput/packages.config b/TShock.Modifications.Platform/packages.config similarity index 100% rename from TShock.Modifications.UnicodeInput/packages.config rename to TShock.Modifications.Platform/packages.config diff --git a/TShock.Modifications.UnicodeInput/Callbacks/InitializeConsoleOutputCallback.cs b/TShock.Modifications.UnicodeInput/Callbacks/InitializeConsoleOutputCallback.cs deleted file mode 100644 index 5103f10f3..000000000 --- a/TShock.Modifications.UnicodeInput/Callbacks/InitializeConsoleOutputCallback.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Text; - -namespace Mintaka.Modifications.UnicodeInput.Callbacks -{ - internal class InitializeConsoleOutputCallback - { - internal static void InitializeConsoleOutput() - { - if (!Console.IsInputRedirected) - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - Console.InputEncoding = Encoding.Unicode; - } - else - { - Console.InputEncoding = Encoding.UTF8; - } - } - - if (!Console.IsOutputRedirected) - { - Console.OutputEncoding = Encoding.UTF8; - } - } - } -} diff --git a/TShock.Modifications.UnicodeInput/UnicodeInputModification.cs b/TShock.Modifications.UnicodeInput/UnicodeInputModification.cs deleted file mode 100644 index 1bbb6396e..000000000 --- a/TShock.Modifications.UnicodeInput/UnicodeInputModification.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Mono.Cecil.Cil; -using OTAPI.Patcher.Engine.Modification; - -namespace Mintaka.Modifications.UnicodeInput -{ - /// - /// This modification works around the use of System.Text.Encoding.Unicode in the official server which breaks - /// console I/O in macOS and Linux. Setting the encoding to UTF8 should enable the full range of Terraria's - /// localizations, and enable input cross-platform. - /// - public class UnicodeInputModification : ModificationBase - { - public override IEnumerable AssemblyTargets => new[] - { - "OTAPI, Version=1.3.5.3, Culture=neutral, PublicKeyToken=null" - }; - - public override string Description => "Changing Console's Input/Output encoding to UTF-8 for Mono"; - - public override void Run() - { - var consoleInitMethodDefinition = SourceDefinition.MainModule.Import(Method(() => Callbacks.InitializeConsoleOutputCallback.InitializeConsoleOutput())); - var processor = Method(() => Terraria.Program.InitializeConsoleOutput()).Body.GetILProcessor(); - - /* - * There is a .try block in the original code, which means the stack and exception handlers must be - * cleared and reset to 1 - */ - processor.Body.Instructions.Clear(); - processor.Body.Variables.Clear(); - processor.Body.ExceptionHandlers.Clear(); - processor.Body.MaxStackSize = 1; - - processor.Append(Instruction.Create(OpCodes.Call, consoleInitMethodDefinition)); - processor.Append(Instruction.Create(OpCodes.Ret)); - } - - } -}