首页 > 解决方案 > 神秘段故障

问题描述

我的图书馆有一个非常特殊的问题。下面的简单示例完美运行。但更复杂的用例却没有。setStaticField 函数调用给出了段错误。稍后我将显示函数中的位置。

这是工作示例

int main()
{
    Hunter::VM vm;
    Hunter::Script* s = vm.createScript("test.dll");
    Hunter::Class c = s->getClass("", "Entity");
    c.setStaticField("test", vm.newString("YO!!!"));

    return 0;
}

我的库的简短版本是这样的:它用于将 C# 嵌入到单声道框架中,尽管我很确定我的问题与单声道 API 无关。您首先创建一个 VM,我基本上是一个 MonoDomain 的包装器。然后,您从该 VM 中创建脚本。脚本本质上是围绕 MonoAssembly 及其匹配的 MonoImage 的包装器。然后你从一个脚本中得到一个 Class 对象,它是一个 MonoClass 的包装器。setStaticField 符合您的预期,它将 C# 类的静态成员变量设置为提供的值。同样,上面的示例功能完全。但下面的没有。

游戏.h

// includes and other inline variable declarations
inline Hunter::VM csharpVM;
// other includes

#include "../game.h"

// other functions

void loadScript(Scene* const a_scene, Json::Value a_data, entt::entity a_e)
{
    std::string scriptPath = a_scene->path + a_data.asString();

    scriptPath.erase(scriptPath.size() - 2, 2);
    scriptPath += "dll";
    Hunter::Script* s = csharpVM.createScript(scriptPath.c_str());
    a_scene->registry.emplace<Hunter::Script*>(a_e, s);

    Hunter::Class c = s->getClass("", "Part");
    std::cout << "About to push: " << &a_e << std::endl;
    c.setStaticField("partID", static_cast<void*>(&a_e));
    int sceneInt = reinterpret_cast<int>(a_scene);
    c.setStaticField("scenePtr", &sceneInt);
    std::cout << "Scene pointer: " << a_scene << "\nScene int: " << sceneInt << "\nScene Pointer back: " << reinterpret_cast<Scene*>(sceneInt) << std::endl;

    s->getStaticMethod("Part:onCreate()")();
}

这个函数应该使用我的 Hunter 库加载到脚本中,附加到一个 Entt 实体(我使用的 ECS。这里没有导入。),将它的 partID 字段设置为它在 Entt 中的 ID,将它的 scenePtr 成员设置为指向它所属的场景,然后调用它的 onCreate 方法。方法调用有效。但是两个 setStaticField 调用都在函数的最后一行给出了段错误(设置值的实际调用)

void setStaticField(const char* const a_name, void* a_value)
{
     MonoClassField* const field = mono_class_get_field_from_name(this->m_class, a_name);
     if (!field)
    {
        std::cerr << "Field error! Name: " << a_name << std::endl;
    }
    MonoVTable* const vtable = mono_class_vtable(mono_get_root_domain(), this->m_class);
    if (!vtable)
    {
        std::cerr << "VTable error! Name: " << a_name << std::endl;
    }
    std::cout << "About to send: " << a_value << std::endl;
    mono_field_static_set_value(vtable, field, a_value);
}

最后,这是这里使用的两个 C# 脚本。似乎链接在一起并正确继承。

using System;

class Part : Game.PartBasic
{
    public static void onCreate()
    {
        Console.WriteLine("ScenePtr: ");
        Console.WriteLine(scenePtr);

        setPosition(500, 500);
    }

    public static void onUpdate()
    {

    }

    public static void onDestroy()
    {

    }
}
using System;
using System.Runtime.CompilerServices;

namespace Game
{
    public class PartBasic
    {
        public static uint partID;
        public static int scenePtr;

        public static void setPosition(int a_x, int a_y, int a_partID = -1)
        {
            if (a_partID == -1)
            {
                GameInternals.setPosition(a_x, a_y, partID, scenePtr);
            }else{
                GameInternals.setPosition(a_x, a_y, Convert.ToUInt32(a_partID), scenePtr);
            }
        }
    }

    class GameInternals
    {
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern static void setPosition(int a_x, int a_y, uint a_partID, int scenePtr);
    }
}

同样,这一切都适用于顶级示例,但不适用于此处。任何帮助将不胜感激!

标签: c#c++monoc++17game-engine

解决方案


推荐阅读