Add .Net Runtime deployment for cooked game
This commit is contained in:
@@ -13,37 +13,37 @@
|
||||
/// </summary>
|
||||
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API BuildSettings : public SettingsBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(BuildSettings);
|
||||
public:
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(BuildSettings);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// The maximum amount of assets to include into a single assets package. Asset packages will split into several packages if need to.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(10), DefaultValue(4096), Limit(1, ushort.MaxValue), EditorDisplay(\"General\", \"Max assets per package\")")
|
||||
API_FIELD(Attributes="EditorOrder(10), Limit(1, ushort.MaxValue), EditorDisplay(\"General\", \"Max assets per package\")")
|
||||
int32 MaxAssetsPerPackage = 4096;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum size of the single assets package (in megabytes). Asset packages will split into several packages if need to.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(20), DefaultValue(1024), Limit(1, ushort.MaxValue), EditorDisplay(\"General\", \"Max package size (in MB)\")")
|
||||
API_FIELD(Attributes="EditorOrder(20), Limit(1, ushort.MaxValue), EditorDisplay(\"General\", \"Max package size (in MB)\")")
|
||||
int32 MaxPackageSizeMB = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// The game content cooking keycode. Use the same value for a game and DLC packages to support loading them by the build game. Use 0 to randomize it during building.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(30), DefaultValue(0), EditorDisplay(\"General\")")
|
||||
API_FIELD(Attributes="EditorOrder(30), EditorDisplay(\"General\")")
|
||||
int32 ContentKey = 0;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the builds produced by the Game Cooker will be treated as for final game distribution (eg. for game store upload). Builds done this way cannot be tested on console devkits (eg. Xbox One, Xbox Scarlett).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(40), DefaultValue(false), EditorDisplay(\"General\")")
|
||||
API_FIELD(Attributes="EditorOrder(40), EditorDisplay(\"General\")")
|
||||
bool ForDistribution = false;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the output build files won't be packaged for the destination platform. Useful when debugging build from local PC.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(50), DefaultValue(false), EditorDisplay(\"General\")")
|
||||
API_FIELD(Attributes="EditorOrder(50), EditorDisplay(\"General\")")
|
||||
bool SkipPackaging = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Additional Data\")")
|
||||
Array<AssetReference<Asset>> AdditionalAssets;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of additional scenes to include into build (into root assets set).
|
||||
/// </summary>
|
||||
@@ -67,17 +67,22 @@ public:
|
||||
/// <summary>
|
||||
/// Disables shaders compiler optimizations in cooked game. Can be used to debug shaders on a target platform or to speed up the shaders compilation time.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2000), DefaultValue(false), EditorDisplay(\"Content\", \"Shaders No Optimize\")")
|
||||
API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Content\", \"Shaders No Optimize\")")
|
||||
bool ShadersNoOptimize = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enables shader debug data generation for shaders in cooked game (depends on the target platform rendering backend).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2010), DefaultValue(false), EditorDisplay(\"Content\")")
|
||||
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Content\")")
|
||||
bool ShadersGenerateDebugData = false;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// If checked, .NET 7 Runtime won't be packaged with a game and will be required by user to be installed on system upon running game build. Available only on supported platforms such as Windows, Linux and macOS.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(3000), EditorDisplay(\"Scripting\", \"Skip .NET Runtime Packaging\")")
|
||||
bool SkipDotnetPackaging = false;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
|
||||
/// </summary>
|
||||
@@ -95,5 +100,6 @@ public:
|
||||
DESERIALIZE(AdditionalAssetFolders);
|
||||
DESERIALIZE(ShadersNoOptimize);
|
||||
DESERIALIZE(ShadersGenerateDebugData);
|
||||
DESERIALIZE(SkipDotnetPackaging);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "CoreCLR.h"
|
||||
|
||||
#if USE_NETCORE
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include <nethost.h>
|
||||
#include <coreclr_delegates.h>
|
||||
#include <hostfxr.h>
|
||||
@@ -17,12 +19,8 @@
|
||||
#undef LoadLibrary
|
||||
#endif
|
||||
|
||||
static Dictionary<String, void*> cachedFunctions;
|
||||
#if PLATFORM_WINDOWS
|
||||
static const char_t* typeName = TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp");
|
||||
#else
|
||||
static const char_t* typeName = "FlaxEngine.NativeInterop, FlaxEngine.CSharp";
|
||||
#endif
|
||||
static Dictionary<String, void*> CachedFunctions;
|
||||
static const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp");
|
||||
|
||||
hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config;
|
||||
hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line;
|
||||
@@ -42,21 +40,33 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
|
||||
get_hostfxr_parameters get_hostfxr_params;
|
||||
get_hostfxr_params.size = sizeof(hostfxr_initialize_parameters);
|
||||
get_hostfxr_params.assembly_path = library_path.Get();
|
||||
FLAX_CORECLR_STRING dotnetRoot;
|
||||
// TODO: implement proper lookup for dotnet instalation folder and handle standalone build of FlaxGame
|
||||
#if PLATFORM_MAC
|
||||
get_hostfxr_params.dotnet_root = "/usr/local/share/dotnet";
|
||||
#else
|
||||
get_hostfxr_params.dotnet_root = nullptr;
|
||||
#endif
|
||||
#if !USE_EDITOR
|
||||
const String& bundledDotnetPath = Globals::ProjectFolder / TEXT("Dotnet");
|
||||
if (FileSystem::DirectoryExists(bundledDotnetPath))
|
||||
{
|
||||
dotnetRoot = FLAX_CORECLR_STRING(bundledDotnetPath);
|
||||
#if PLATFORM_WINDOWS_FAMILY
|
||||
dotnetRoot.Replace('/', '\\');
|
||||
#endif
|
||||
get_hostfxr_params.dotnet_root = dotnetRoot.Get();
|
||||
}
|
||||
#endif
|
||||
char_t hostfxrPath[1024];
|
||||
size_t hostfxrPathSize = sizeof(hostfxrPath) / sizeof(char_t);
|
||||
int rc = get_hostfxr_path(hostfxrPath, &hostfxrPathSize, &get_hostfxr_params);
|
||||
if (rc != 0)
|
||||
{
|
||||
LOG(Error, "Failed to find hostfxr: {0:x}", (unsigned int)rc);
|
||||
LOG(Error, "Failed to find hostfxr: {0:x} ({1})", (unsigned int)rc, String(get_hostfxr_params.dotnet_root));
|
||||
return true;
|
||||
}
|
||||
const String path(hostfxrPath);
|
||||
String path(hostfxrPath);
|
||||
LOG(Info, "Found hostfxr in {0}", path);
|
||||
|
||||
// Get API from hostfxr library
|
||||
@@ -84,12 +94,15 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
|
||||
hostfxr_initialize_parameters init_params;
|
||||
init_params.size = sizeof(hostfxr_initialize_parameters);
|
||||
init_params.host_path = library_path.Get();
|
||||
init_params.dotnet_root = nullptr;//dotnetRoot.Get(); // This probably must be set
|
||||
path = String(StringUtils::GetDirectoryName(path)) / TEXT("/../../../");
|
||||
StringUtils::PathRemoveRelativeParts(path);
|
||||
dotnetRoot = FLAX_CORECLR_STRING(path);
|
||||
init_params.dotnet_root = dotnetRoot.Get();
|
||||
hostfxr_handle handle = nullptr;
|
||||
rc = hostfxr_initialize_for_dotnet_command_line(ARRAY_COUNT(argv), argv, &init_params, &handle);
|
||||
if (rc != 0 || handle == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to initialize hostfxr: {0:x}", (unsigned int)rc);
|
||||
LOG(Error, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root));
|
||||
hostfxr_close(handle);
|
||||
return true;
|
||||
}
|
||||
@@ -111,15 +124,14 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
|
||||
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
|
||||
{
|
||||
void* fun;
|
||||
if (cachedFunctions.TryGet(methodName, fun))
|
||||
if (CachedFunctions.TryGet(methodName, fun))
|
||||
return fun;
|
||||
|
||||
int rc = get_function_pointer(typeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun);
|
||||
int rc = get_function_pointer(NativeInteropTypeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun);
|
||||
if (rc != 0)
|
||||
LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc);
|
||||
|
||||
cachedFunctions.Add(methodName, fun);
|
||||
|
||||
CachedFunctions.Add(methodName, fun);
|
||||
return fun;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#if defined(_WIN32)
|
||||
#define CORECLR_DELEGATE_CALLTYPE __stdcall
|
||||
#define FLAX_CORECLR_STRING String
|
||||
#define FLAX_CORECLR_TEXT(x) TEXT(x)
|
||||
#else
|
||||
#define CORECLR_DELEGATE_CALLTYPE
|
||||
#define FLAX_CORECLR_STRING StringAnsi
|
||||
#define FLAX_CORECLR_TEXT(x) x
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -56,8 +58,8 @@ public:
|
||||
static void Free(void* ptr);
|
||||
static MGCHandle NewGCHandle(void* obj, bool pinned);
|
||||
static MGCHandle NewGCHandleWeakref(void* obj, bool track_resurrection);
|
||||
static void* GetGCHandleTarget(const MGCHandle& MGCHandle);
|
||||
static void FreeGCHandle(const MGCHandle& MGCHandle);
|
||||
static void* GetGCHandleTarget(const MGCHandle& handle);
|
||||
static void FreeGCHandle(const MGCHandle& handle);
|
||||
|
||||
static bool HasCustomAttribute(void* klass, void* attribClass);
|
||||
static bool HasCustomAttribute(void* klass);
|
||||
|
||||
@@ -606,15 +606,15 @@ MGCHandle CoreCLR::NewGCHandleWeakref(void* obj, bool track_resurrection)
|
||||
return (MGCHandle)CoreCLR::CallStaticMethod<void*, void*, bool>(NewGCHandleWeakrefPtr, obj, track_resurrection);
|
||||
}
|
||||
|
||||
void* CoreCLR::GetGCHandleTarget(const MGCHandle& MGCHandle)
|
||||
void* CoreCLR::GetGCHandleTarget(const MGCHandle& handle)
|
||||
{
|
||||
return (void*)MGCHandle;
|
||||
return (void*)handle;
|
||||
}
|
||||
|
||||
void CoreCLR::FreeGCHandle(const MGCHandle& MGCHandle)
|
||||
void CoreCLR::FreeGCHandle(const MGCHandle& handle)
|
||||
{
|
||||
static void* FreeGCHandlePtr = CoreCLR::GetStaticMethodPointer(TEXT("FreeGCHandle"));
|
||||
CoreCLR::CallStaticMethod<void, void*>(FreeGCHandlePtr, (void*)MGCHandle);
|
||||
CoreCLR::CallStaticMethod<void, void*>(FreeGCHandlePtr, (void*)handle);
|
||||
}
|
||||
|
||||
const char* CoreCLR::GetClassFullname(void* klass)
|
||||
|
||||
Reference in New Issue
Block a user