[Windows] Add FreeSO style dynamic linking of Monogame

DirectX by default in Windows. Use `-dx` and `-gl` to manually switch.
Should make azure build usable.
This commit is contained in:
riperiperi 2019-11-16 14:22:56 +00:00
parent 6057764713
commit 42e8a7785c
6 changed files with 279 additions and 14 deletions

View file

@ -0,0 +1,32 @@
using FSO.Client;
using FSO.LotView;
using FSO.UI;
using Simitone.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Simitone.Windows
{
public class GameStartProxy
{
public void Start(bool useDX)
{
GameFacade.DirectX = useDX;
World.DirectX = useDX;
SimitoneGame game = new SimitoneGame();
var form = (Form)Form.FromHandle(game.Window.Handle);
if (form != null) form.FormClosing += Form_FormClosing;
game.Run();
game.Dispose();
}
private static void Form_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = !(GameFacade.Screens.CurrentUIScreen?.CloseAttempt() ?? true);
}
}
}

View file

@ -3,10 +3,13 @@ using FSO.Common;
using FSO.LotView;
using Simitone.Client;
using Simitone.Windows.GameLocator;
using Simitone.Windows.Utils;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
@ -25,10 +28,22 @@ namespace Simitone.Windows
[STAThread]
static void Main(string[] args)
{
var gameLocator = new WindowsLocator();
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
var useDX = true;
var path = gameLocator.FindTheSimsOnline();
OperatingSystem os = Environment.OSVersion;
PlatformID pid = os.Platform;
ILocator gameLocator;
bool linux = pid == PlatformID.MacOSX || pid == PlatformID.Unix;
if (linux && Directory.Exists("/Users"))
gameLocator = new MacOSLocator();
else if (linux)
gameLocator = new LinuxLocator();
else
gameLocator = new WindowsLocator();
var useDX = !linux;
var path = gameLocator.FindTheSims1();
FSOEnvironment.Enable3D = false;
bool ide = false;
@ -63,12 +78,26 @@ namespace Simitone.Windows
case "jit":
jit = true;
break;
case "dx":
case "dx11":
useDX = true;
break;
case "gl":
case "ogl":
useDX = false;
break;
case "touch":
FSOEnvironment.SoftwareKeyboard = true;
break;
case "nosound":
FSOEnvironment.NoSound = true;
break;
}
}
}
}
#endregion
useDX = MonogameLinker.Link(useDX);
FSO.Files.ImageLoaderHelpers.BitmapFunction = BitmapReader;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
@ -90,16 +119,13 @@ namespace Simitone.Windows
GlobalSettings.Default.StartupPath = path;
GlobalSettings.Default.TS1HybridEnable = true;
GlobalSettings.Default.TS1HybridPath = gameLocator.FindTheSims1();
GlobalSettings.Default.TS1HybridPath = path;
GlobalSettings.Default.ClientVersion = "0";
GlobalSettings.Default.LightingMode = 3;
GlobalSettings.Default.AntiAlias = aa ? 1 : 0;
GlobalSettings.Default.ComplexShaders = true;
GlobalSettings.Default.EnableTransitions = true;
GameFacade.DirectX = useDX;
World.DirectX = useDX;
if (ide) new FSO.IDE.VolcanicStartProxy().InitVolcanic(args);
var assemblies = new FSO.SimAntics.JIT.Runtime.AssemblyStore();
@ -107,11 +133,8 @@ namespace Simitone.Windows
if (jit) assemblies.InitAOT();
FSO.SimAntics.Engine.VMTranslator.INSTANCE = new FSO.SimAntics.JIT.Runtime.VMAOTTranslator(assemblies);
SimitoneGame game = new SimitoneGame();
var form = (Form)Form.FromHandle(game.Window.Handle);
if (form != null) form.FormClosing += Form_FormClosing;
game.Run();
game.Dispose();
var start = new GameStartProxy();
start.Start(useDX);
}
}
@ -120,6 +143,28 @@ namespace Simitone.Windows
e.Cancel = !(GameFacade.Screens.CurrentUIScreen?.CloseAttempt() ?? true);
}
private static System.Reflection.Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
var name = args.Name;
if (name.StartsWith("FSO.Scripts"))
{
return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == name);
}
else
{
var assemblyPath = Path.Combine(MonogameLinker.AssemblyDir, args.Name.Substring(0, name.IndexOf(',')) + ".dll");
var assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
}
catch (Exception e)
{
return null;
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject;

View file

@ -43,8 +43,92 @@
<Compile Include="GameLocator\LinuxLocator.cs" />
<Compile Include="GameLocator\MacOSLocator.cs" />
<Compile Include="GameLocator\WindowsLocator.cs" />
<Compile Include="GameStartProxy.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\MonogameLinker.cs" />
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\obj\Linux\AnyCPU\Release\MonoGame.Framework.dll" Condition="Exists('..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\obj\Linux\AnyCPU\Release\MonoGame.Framework.dll')">
<Link>Monogame\Linux\MonoGame.Framework.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\obj\WindowsGL\AnyCPU\Release\MonoGame.Framework.dll">
<Link>Monogame\WindowsGL\MonoGame.Framework.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\obj\Windows\AnyCPU\Release\MonoGame.Framework.dll">
<Link>Monogame\Windows\MonoGame.Framework.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.D3DCompiler.dll">
<Link>Monogame\Windows\SharpDX.D3DCompiler.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.D3DCompiler.xml">
<Link>Monogame\Windows\SharpDX.D3DCompiler.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.Direct2D1.dll">
<Link>Monogame\Windows\SharpDX.Direct2D1.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.Direct2D1.xml">
<Link>Monogame\Windows\SharpDX.Direct2D1.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.Direct3D11.dll">
<Link>Monogame\Windows\SharpDX.Direct3D11.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.Direct3D11.xml">
<Link>Monogame\Windows\SharpDX.Direct3D11.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.dll">
<Link>Monogame\Windows\SharpDX.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.DXGI.dll">
<Link>Monogame\Windows\SharpDX.DXGI.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\SharpDX.DXGI.xml">
<Link>Monogame\Windows\SharpDX.DXGI.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.MediaFoundation.dll">
<Link>Monogame\Windows\SharpDX.MediaFoundation.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.MediaFoundation.xml">
<Link>Monogame\Windows\SharpDX.MediaFoundation.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.XAudio2.dll">
<Link>Monogame\Windows\SharpDX.XAudio2.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.XAudio2.xml">
<Link>Monogame\Windows\SharpDX.XAudio2.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.XInput.dll">
<Link>Monogame\Windows\SharpDX.XInput.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.XInput.xml">
<Link>Monogame\Windows\SharpDX.XInput.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\ThirdParty\Dependencies\SharpDX\net40\SharpDX.xml">
<Link>Monogame\Windows\SharpDX.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="sdl2.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="soft_oal.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
@ -120,4 +204,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View file

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Windows.Utils
{
class MonogameLinker
{
//detects OS and copies the correct version of monogame into the parent directory.
//there is probably a better way to do this that doesn't mess with multiple clients
public static string AssemblyDir = "./";
public static bool Link(bool preferDX11)
{
OperatingSystem os = Environment.OSVersion;
PlatformID pid = os.Platform;
bool linux = false;
if (pid == PlatformID.MacOSX || pid == PlatformID.Unix) linux = true;
if (linux && preferDX11)
{
Console.WriteLine("DirectX is usually only available on Windows. I hope you know what you're doing...");
}
try
{
string contentDir = "Content/OGL/";
string monogameDir = "Monogame/WindowsGL/";
if (!linux)
{
if (preferDX11)
{
contentDir = "Content/DX/";
monogameDir = "Monogame/Windows/";
}
}
//Check if MacOS by checkking user directory. Because PlatformID.MacOSX is not true on OS X.
else if (Directory.Exists("/Users"))
{
monogameDir = "Monogame/MacOS/";
return false;
}
else
{
monogameDir = "Monogame/Linux/";
return false;
}
if (File.Exists("Monogame.Framework.dll")) File.Delete("Monogame.Framework.dll");
AssemblyDir = monogameDir;
}
catch (Exception e)
{
Console.WriteLine("Unable to link Monogame. Continuing... (" + e.ToString() + ")");
}
return preferDX11;
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, true);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
}

Binary file not shown.

Binary file not shown.