If there are errors in the code, terminology, etc. in the text, please correct me
Article directory
foreword
-
of this program
Use the C# game code as a new workspace project and reference the C# core library project
-
1 C# core library project
-
1 C# script project
The script inside calls the function of the C# core library to realize the script function
Like Unity development, Unity has its own set of dll, we need to write script using UnityEngine;, call the Unity library dll to achieve the corresponding effect
-
-
How to achieve
Use premake5 to make quickly
-
implementation details
-
When the C# game code and the core library code are separated, the C++ loading dll changes from one to two
-
Get the Mono class of the C# dll
It should be distinguished that it is the Mono class that obtains the C# core library assembly
Or get the Mono class of the C# application set
-
Project structure related
new workspace new script project
-
new workspace file path
Under the GameEngine-Editor editor project
-
Premake of the new Sandbox script project
local UnifyRootDir = "../../../.." workspace "Sandbox" architecture "x86_64" startproject "Sandbox" configurations{ "Debug", "Release", "Dist" } flags{ "MultiProcessorCompile" } outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}" project "Sandbox" kind "SharedLib" language "C#" dotnetframework "4.7.2" targetdir ("Binaries") objdir ("Intermediates") files{ "Source/**.cs", "Properies/**.cs" } links{ "GameEngine-ScriptCore" } filter "configurations:Debug" optimize "Off" symbols "Default" filter "configurations:Release" optimize "On" symbols "Default" filter "configurations:Dist" optimize "Full" symbols "Off" group "Unify" include (UnifyRootDir .. "/GameEngine-ScriptCore") group ""
New Sandbox script project structure
- The Sandbox project references the GameEngine-ScriptCore project
- The Sandbox project contains the Player.cs game logic script code moved from the GameEngine-ScriptCore project
New Sanbox script project generates dll
-
build directory set by premake
targetdir ("Binaries") objdir ("Intermediates")
-
Since the Sandbox project references the GameEngine-ScriptCore project
So the generation will not only generate Sandbox.dll but also GameEngine-ScriptCore.dll
project code changes
The changes made to the project code are to load two dlls and reflect different classes according to different dlls
ScriptEngine.h
//ScriptClass(const std::string& classNamespace, const std::string& className);
ScriptClass(const std::string& classNamespace, const std::string& className, bool isCore = false);
static void LoadAppAssembly(const std::filesystem::path& filepath);
//static void LoadAssemblyClasses(MonoAssembly* assembly);
static void LoadAssemblyClasses();
ScriptEngine.cpp
struct ScriptEngineData {
MonoAssembly* CoreAssembly = nullptr;
MonoImage* CoreAssemblyImage = nullptr;
// 新增,因加载脚本dll,需保存这两个
MonoAssembly* AppAssembly = nullptr;
MonoImage* AppAssemblyImage = nullptr;
};
LoadAssembly("Resources/Scripts/Hazel-ScriptCore.dll");
LoadAppAssembly("SandboxProject/Assets/Scripts/Binaries/Sandbox.dll");
s_Data->EntityClass = ScriptClass("Hazel", "Entity", true);
void ScriptEngine::LoadAssemblyClasses()
{
// Entity类在核心库
MonoClass* entityClass = mono_class_from_name(s_Data->CoreAssemblyImage, "Hazel", "Entity");
// 从游戏逻辑脚本库里加载脚本类
const char* nameSpace = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]);
const char* name = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAME]);
MonoClass* monoClass = mono_class_from_name(s_Data->AppAssemblyImage, nameSpace, name);
}
void ScriptEngine::LoadAppAssembly(const std::filesystem::path& filepath)
{
// Move this maybe
s_Data->AppAssembly = Utils::LoadMonoAssembly(filepath);
auto assemb = s_Data->AppAssembly;
s_Data->AppAssemblyImage = mono_assembly_get_image(s_Data->AppAssembly);
auto assembi = s_Data->AppAssemblyImage;
// Utils::PrintAssemblyTypes(s_Data->AppAssembly);
}
ScriptClass::ScriptClass(const std::string& classNamespace, const std::string& className, bool isCore)
: m_ClassNamespace(classNamespace), m_ClassName(className)
{
/*
得到C# dll的Mono类
应该**区分**是获取C#核心库程序集的 Mono类
还是获取C#应用程序集的 Mono类
*/
m_MonoClass = mono_class_from_name(s_Data->CoreAssemblyImage, classNamespace.c_str(), className.c_str());
m_MonoClass = mono_class_from_name(isCore ? s_Data->CoreAssemblyImage : s_Data->AppAssemblyImage, classNamespace.c_str(), className.c_str());
}
Encountered bugs
-
GameEngine-ScriptCore.dll could not be loaded
GameEngine-ScriptCore.dll is generated in the GameEngine-Editor\SandboxProject\Assets\Scripts\Binaries folder
Instead of in the GameEngine-Editor\Resources\Scripts folder
-
reason
The new Sandbox project contains a reference to the GameEngine-ScriptCore project
The generated file path written by Sandbox's premake is
targetdir ("Binaries") objdir ("Intermediates")
And the premake of GameEngine-ScriptCore writes
targetdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts") objdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts/Intermediates")
Pay attention to the code %{wks.location}, it gets the location of **.sln**
-
Originally the GameEngineLightWeight workspace contained it
%{wks.location} = GameEngineLightWeight
So the generated directory is:
GameEngineLightWeight\GameEngine-Editor\Resources\Scripts
-
But the new Sandbox also has its own new workspace , and also contains this GameEngine-ScriptCore project
%{wks.location} = GameEngineLightWeight\GameEngine-Editor\SandboxProject\Assets\Scripts
So this build directory becomes:
GameEngineLightWeight\GameEngine-Editor\SandboxProject\Assets\Scripts\GameEngine-Editor\Resources\Scripts
-
-
The path is generated as follows
The generated path is different from the path where the code loads the dll, so an error will be reported
-
How to solve
Modify the build path in the premake of the GameEngine-ScriptCore project
-- 获取的是.sln所在的位置 --targetdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts") --objdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts/Intermediates") targetdir ("../GameEngine-Editor/Resources/Scripts") objdir ("../GameEngine-Editor/Resources/Scripts/Intermediates")
%{wks.location} replaced by .../
-
regenerate path
-