// ScriptDllSample.cpp : 定义 DLL 的导出函数。
//

#include "framework.h"
#include "ScriptDllSample.h"

// 导入头文件
#include "../SdkInclude/angelscript.h"
#include "../SdkInclude/AsString.h"
#include "../SdkInclude/scriptarray.h"


// 更多AngelScript的用法可以参考AngelScript官网手册
// https://www.angelcode.com/angelscript/sdk/docs/manual/index.html


// 加法
int Plus(int a, int b) {
    return a + b;
}
// 连接两个字符串
AsString ConcatTwoString(const AsString& a, const AsString& b) {
    return a + b;
}

// 连接两个int数组
CScriptArray* ConcatTwoArray(CScriptArray* a, CScriptArray* b) {
    // 获取当前脚本的活动上下文
    auto context = AsGetActiveContext();
    if (!context) return nullptr;
    // 获得内部脚本引擎
    auto engine = context->GetEngine();
    if (!engine) return nullptr;

    // 检查两个数组的类型是否都是int
    if (a->GetElementTypeId() != asTYPEID_INT32) {
        return nullptr;
    }
    if (b->GetElementTypeId() != asTYPEID_INT32) {
        return nullptr;
    }

    // 获得目标数组类型
    static asITypeInfo* t = engine->GetTypeInfoByDecl("int[]");
    if (!t) return nullptr;
    // 根据类型来创建新数组
    auto finalSize = a->GetSize() + b->GetSize();
    CScriptArray* c = CScriptArray::Create(t, unsigned(0));
    for (unsigned i = 0; i < a->GetSize(); i++) {
        int value = *(int*)a->At(i);
        c->InsertLast(&value);
    }
    for (unsigned i = 0; i < b->GetSize(); i++) {
        int value = *(int*)b->At(i);
        c->InsertLast(&value);
    }
    // 返回最终结果
    return c;
}

// 注册脚本Api, 如果不定义这个函数, 脚本引擎就无法加载此Dll文件
extern "C" __declspec(dllexport) void RegisterScriptApi(asIScriptEngine * engine, const AsString& gameVersionText) {
    // 初始化变量r来接收错误值
    // 最佳实践: 在调用engine的方法后, 用 assert(r >= 0); 来判断是否调用成功
    int r = 0;

    // 自定义命名空间, 可以避免跟其他插件API的名称发生冲突
    // 调用API的时候, 在函数名称前面加上 MyScript::
    // 例如: MyScript::Plus
    r = engine->SetDefaultNamespace("MyScript"); assert(r >= 0);

    // 注册全局函数, 函数声明几乎跟C++的一模一样
    // 注册 Plus
    r = engine->RegisterGlobalFunction("int Plus(int a, int b)", asFUNCTION(Plus), asCALL_CDECL); assert(r >= 0);
    // 注册 ConcatTwoString
    // 注意这里的声明, 字符串在C++端是AsString, 而脚本端是string, 不要搞错
    r = engine->RegisterGlobalFunction("string ConcatTwoString(const string& a, const string& b)", asFUNCTION(ConcatTwoString), asCALL_CDECL); assert(r >= 0);
    // 注册 ConcatTwoArray
    r = engine->RegisterGlobalFunction("int[]@ ConcatTwoArray(const int[]@ a, const int[]@ b)", asFUNCTION(ConcatTwoArray), asCALL_CDECL); assert(r >= 0);

    // 恢复默认命名空间
    r = engine->SetDefaultNamespace(""); assert(r >= 0);

    // 结束    
}


/************************/
// 以下是可以直接脚本调用用例
// 可以复制粘贴到游戏内的脚本控制台进行测试

/*
// 1.
Print (MyScript::Plus(1, 2))
// 控制台输出 : 3
*/

/*
// 2.
Print (MyScript::ConcatTwoString("a", "b"))
// 控制台输出 : ab
*/


/*
// 3.
auto arr = MyScript::ConcatTwoArray({1}, {2});
for (uint i = 0 ; i < arr.GetSize(); i++){
    Print(arr[i]);
}
// 控制台输出 : 
    1
    2

*/