Null pointer access

Started by
5 comments, last by Flurreh Kitsune Flufftail 10 years, 6 months ago

Hey,

I'm currently having trouble calling object methods in AngelScript. Those problems began when I started re-writing the script engine but as of now I was unable to proceed with the development of my project because I couldn't find out what actually causes my error.

As soon as I try calling the methods of an object, I'm getting a "Null pointer access" error.


bool hBot2::as_engine::__call_func(asIScriptFunction* func, const std::string& params, char rt, void** ret, va_list args)
{
    asIScriptContext* ctx = this->m_engine->CreateContext();
    if(ctx == nullptr) {
        hBot2::syserr("%s","Can not create script context!");
        return false;
    }
    if(ctx->Prepare(func)<0) {
        hBot2::syserr("%s","Can not prepare script context!");
        ctx->Release();
        return false;
    }

    std::vector<std::string*> strings;

    for(uint32_t i = 0; i < params.size(); ++i) {
        switch(params[i])
        {
            case 'u':
            case 'i':
            {
                ctx->SetArgDWord(i,va_arg(args,uint32_t));
            } break;
            case 'b':
            case 'x':
            {
                ctx->SetArgByte(i,va_arg(args,uint32_t));
            } break;
            case 'w':
            {
                ctx->SetArgWord(i,va_arg(args,uint32_t));
            } break;
            case 'q':
            {
                ctx->SetArgQWord(i,va_arg(args,uint64_t));
            } break;
            case 's':
            {
                std::string* s = new std::string(va_arg(args,char*));
                strings.push_back(s);
                ctx->SetArgObject(i,s);
            } break;
            case 'p':
            case 'o':
            {
                ctx->SetArgObject(i,va_arg(args,void*));
            } break;
            case 'a':
            {
                ctx->SetArgAddress(i,va_arg(args,void*));
            } break;
            default:
                hBot2::syserr("Unknown parameter type '%c'!",params[i]);

                for(uint32_t i = 0; i < strings.size(); ++i)
                    delete strings[i];

                return false;
        }
    }

    int r = ctx->Execute();

    for(uint32_t i = 0; i < strings.size(); ++i)
        delete strings[i];

    if(r != asEXECUTION_FINISHED) {
        if(r == asEXECUTION_EXCEPTION)
            hBot2::syserr("AS Error: %s (%s)",ctx->GetExceptionString(),ctx->GetExceptionFunction()->GetName());
        ctx->Release();
        return false;
    }

    if(ret != nullptr) {
        switch(rt)
        {
        	case 'u':
            case 'i':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnDWord());
            } break;
            case 'b':
            case 'x':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnByte());
            } break;
            case 'w':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnWord());
            } break;
            case 'q':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnQWord());
            } break;
            case 's':
            case 'p':
            case 'o':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnObject());
            } break;
            case 'a':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnAddress());
            } break;
            default:
                hBot2::syserr("Unknown return type '%c'!",rt);
                ctx->Release();
                return false;
        }
	}
    ctx->Release();

    return true;
};

The error occurs on calling ctx->Execute(), which only happens when I call object methods - it doesn't happen when I call my other functions.

Does anyone have an idea about how to fix it? I'm searching the bug since a whole lot of time now..

Thanks in advance, Nico

Advertisement

You need to use ctx->SetObject() to pass the context a pointer to the object which owns the method. The method doesn't own the object itself; it needs to know which instance to be called on.

Thanks for your reply. I've been trying to do that but I don't have any idea how to implement this in my script engine.


#ifndef __HBOT2__AS_ENGINE__H__
#define __HBOT2__AS_ENGINE__H__

class asIScriptEngine;
class asIScriptModule;
class asIScriptFunction;
class CScriptBuilder;

namespace hBot2
{
    class client;
    class config;

    class as_engine : public threadsafe
    {
    private:
        client* m_client;
        asIScriptEngine* m_engine;
        CScriptBuilder* m_builder;

    public:
        as_engine(client* c);
        ~as_engine();

        client* get_client();
        asIScriptEngine* get_engine();
        asIScriptModule* get_module();
        CScriptBuilder* get_builder();

        bool init();

        bool load_script(const std::string& name, const std::string& code);
        bool load_script(const std::string& filename);

        bool call_callback(std::string callback, const std::string& params, ...);
        bool call_function(const std::string& function, const std::string& params, char rt, void** ret, ...);

        bool build();

    private:
        bool __register_class(const std::string& name);
        bool __register_class_method(const std::string& name, const std::string& funcdecl, asSFuncPtr funcptr);

        bool __call_func(asIScriptFunction* func, const std::string& params, char rt, void** ret, va_list args);

        void message_callback(const asSMessageInfo &msg);
    };
}

#endif


#include "../os.h"
#include "../std.h"

#include <angelscript.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptbuilder/scriptbuilder.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptany/scriptany.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptarray/scriptarray.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptdictionary/scriptdictionary.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptmath/scriptmath.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptmath/scriptmathcomplex.h"
#include "../../3rdparty/angelscript_2.26.2_sdk/add_on/scriptstdstring/scriptstdstring.h"

#include "threadsafe.h"
#include "thread.h"
#include "config.h"
#include "as_engine.h"
#include "../network/network_stream.h"
#include "client.h"
#include "../m2/entity_type.h"
#include "../m2/entity.h"
#include "../m2/item.h"

#include "syserr.h"
#include "syslog.h"
#include "devlog.h"

#include "../network/simple_player.h"

hBot2::config* asCreateConfig(const std::string& str)
{
	boost::property_tree::ptree pt;
	std::string fname = str, path = "./script/";

	std::size_t pathpos = fname.find_last_of("\\/");
	if(pathpos != std::string::npos)
		fname.erase(0,pathpos+1);

	path += fname;

	try {
		read_json(path,pt);
	} catch(std::exception& e) {
		hBot2::syserr("%s",e.what());
	}

	return new hBot2::config(pt);
};

hBot2::entity* asGET_ENTITY(hBot2::client* obj, uint32_t idx)
{
	if(obj == nullptr)
		return nullptr;

	if(idx > obj->get_entities().size())
		return nullptr;

	return obj->get_entities()[idx];
};
uint32_t asGET_ENTITY_COUNT(hBot2::client* obj)
{
	if(obj == nullptr)
		return 0;

	return obj->get_entities().size();
};

void asSYSLOG(const std::string& str) { hBot2::syslog("%s",str.c_str()); };
void asSYSERR(const std::string& str) { hBot2::syserr("%s",str.c_str()); };
void asDEVLOG(const std::string& str) { hBot2::devlog("%s",str.c_str()); };

uint32_t simpleplayer_id(hBot2::simple_player* p) { return p->m_id; };
std::string simpleplayer_name(hBot2::simple_player* p) { return p->m_name; };
uint8_t simpleplayer_race(hBot2::simple_player* p) { return p->m_race; };
uint8_t simpleplayer_level(hBot2::simple_player* p) { return p->m_level; };
uint32_t simpleplayer_gametime(hBot2::simple_player* p) { return p->m_gametime; };
uint8_t simpleplayer_str(hBot2::simple_player* p) { return p->m_str; };
uint8_t simpleplayer_vit(hBot2::simple_player* p) { return p->m_vit; };
uint8_t simpleplayer_dex(hBot2::simple_player* p) { return p->m_dex; };
uint8_t simpleplayer_int(hBot2::simple_player* p) { return p->m_int; };
uint16_t simpleplayer_body(hBot2::simple_player* p) { return p->m_body; };
uint8_t simpleplayer_namechange(hBot2::simple_player* p) { return p->m_changename; };
uint16_t simpleplayer_hair(hBot2::simple_player* p) { return p->m_hair; };
int32_t simpleplayer_x(hBot2::simple_player* p) { return p->m_x; };
int32_t simpleplayer_y(hBot2::simple_player* p) { return p->m_y; };
std::string simpleplayer_addr(hBot2::simple_player* p) { return inet_ntoa(*reinterpret_cast<struct in_addr*>(&p->m_addr)); };
uint16_t simpleplayer_port(hBot2::simple_player* p) { return p->m_port; };
uint32_t simpleplayer_skillgroup(hBot2::simple_player* p) { return p->m_skillgroup; };

hBot2::as_engine::as_engine(client* c) : m_client(c), m_engine(nullptr), m_builder(new CScriptBuilder())
{
    this->m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
    this->m_engine->SetMessageCallback(asMETHOD(hBot2::as_engine,message_callback),this,asCALL_THISCALL);
    this->m_builder->StartNewModule(this->m_engine,"__main__");
    this->m_builder->DefineWord("HBOT");
};
hBot2::as_engine::~as_engine()
{
    if(this->m_builder != nullptr) {
        delete this->m_builder;
        this->m_builder = nullptr;
    }
    this->m_engine->Release();
};

hBot2::client* hBot2::as_engine::get_client() { return this->m_client; };
asIScriptEngine* hBot2::as_engine::get_engine() { return this->m_engine; };
asIScriptModule* hBot2::as_engine::get_module() { return this->m_builder->GetModule(); };
CScriptBuilder* hBot2::as_engine::get_builder() { return this->m_builder; };

bool hBot2::as_engine::init()
{
    scoped_lock __lock(this);

    RegisterStdString(this->m_engine);
    RegisterScriptAny(this->m_engine);
    RegisterScriptArray(this->m_engine,true);
    RegisterScriptDictionary(this->m_engine);
    RegisterStdStringUtils(this->m_engine);
    RegisterScriptMath(this->m_engine);
    RegisterScriptMathComplex(this->m_engine);

	if(this->m_engine->RegisterEnum("entity_type")<0) return false;

	if(this->m_engine->RegisterEnumValue("entity_type","entity_monster",0)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_npc",1)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_stone",2)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_warp",3)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_door",4)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_building",5)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_pc",6)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_polymorph_pc",7)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_horse",8)<0) return false;
	if(this->m_engine->RegisterEnumValue("entity_type","entity_goto",9)<0) return false;

    if(this->m_engine->RegisterGlobalFunction("void SYSLOG(string str)",asFUNCTION(asSYSLOG),asCALL_CDECL)<0) return false;
    if(this->m_engine->RegisterGlobalFunction("void SYSERR(string str)",asFUNCTION(asSYSERR),asCALL_CDECL)<0) return false;
    if(this->m_engine->RegisterGlobalFunction("void DEVLOG(string str)",asFUNCTION(asDEVLOG),asCALL_CDECL)<0) return false;
    if(this->m_engine->RegisterGlobalFunction("int usleep(uint useconds)",asFUNCTION(usleep),asCALL_CDECL)<0) return false;
    if(this->m_engine->RegisterGlobalFunction("uint sleep(uint seconds)",asFUNCTION(sleep),asCALL_CDECL)<0) return false;

    if(this->m_engine->RegisterObjectType("simple_player",sizeof(simple_player),asOBJ_VALUE|asOBJ_POD)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint id()",asFUNCTION(simpleplayer_id),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","string name()",asFUNCTION(simpleplayer_name),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 race()",asFUNCTION(simpleplayer_race),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 level()",asFUNCTION(simpleplayer_level),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint gametime()",asFUNCTION(simpleplayer_gametime),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 strength()",asFUNCTION(simpleplayer_str),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 vitality()",asFUNCTION(simpleplayer_vit),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 dexterity()",asFUNCTION(simpleplayer_dex),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 intelligence()",asFUNCTION(simpleplayer_int),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint16 body()",asFUNCTION(simpleplayer_body),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint8 namechange()",asFUNCTION(simpleplayer_namechange),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint16 hair()",asFUNCTION(simpleplayer_hair),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","int x()",asFUNCTION(simpleplayer_x),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","int y()",asFUNCTION(simpleplayer_y),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","string addr()",asFUNCTION(simpleplayer_addr),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint16 port()",asFUNCTION(simpleplayer_port),asCALL_CDECL_OBJFIRST)<0) return false;
    if(this->m_engine->RegisterObjectMethod("simple_player","uint skillgroup()",asFUNCTION(simpleplayer_skillgroup),asCALL_CDECL_OBJFIRST)<0) return false;

	if(!this->m_engine->RegisterObjectType("entity",0,asOBJ_REF|asOBJ_NOCOUNT)<0) return false;
	if(!this->__register_class_method("entity","entity_type get_type()",asMETHOD(hBot2::entity,get_type))) return false;
	if(!this->__register_class_method("entity","uint get_vid()",asMETHOD(hBot2::entity,get_vid))) return false;
	if(!this->__register_class_method("entity","int get_x()",asMETHOD(hBot2::entity,get_x))) return false;
	if(!this->__register_class_method("entity","int get_y()",asMETHOD(hBot2::entity,get_y))) return false;
	if(!this->__register_class_method("entity","int get_z()",asMETHOD(hBot2::entity,get_z))) return false;
	if(!this->__register_class_method("entity","float get_angle()",asMETHOD(hBot2::entity,get_angle))) return false;
	if(!this->__register_class_method("entity","uint16 get_race()",asMETHOD(hBot2::entity,get_race))) return false;
	if(!this->__register_class_method("entity","uint get_moving_speed()",asMETHOD(hBot2::entity,get_moving_speed))) return false;
	if(!this->__register_class_method("entity","uint get_attack_speed()",asMETHOD(hBot2::entity,get_attack_speed))) return false;
	if(!this->__register_class_method("entity","uint8 get_state_flag()",asMETHOD(hBot2::entity,get_state_flag))) return false;
	if(!this->__register_class_method("entity","uint64 get_affect_flag()",asMETHOD(hBot2::entity,get_affect_flag))) return false;
	if(!this->__register_class_method("entity","string get_name()",asMETHOD(hBot2::entity,get_name))) return false;
	if(!this->__register_class_method("entity","uint16 get_part(uint8 idx)",asMETHOD(hBot2::entity,get_part))) return false;
	if(!this->__register_class_method("entity","uint8 get_empire()",asMETHOD(hBot2::entity,get_empire))) return false;
	if(!this->__register_class_method("entity","uint get_guild_id()",asMETHOD(hBot2::entity,get_guild_id))) return false;
	if(!this->__register_class_method("entity","uint get_level()",asMETHOD(hBot2::entity,get_level))) return false;
	if(!this->__register_class_method("entity","int16 get_alignment()",asMETHOD(hBot2::entity,get_alignment))) return false;
	if(!this->__register_class_method("entity","uint8 get_pk_mode()",asMETHOD(hBot2::entity,get_pk_mode))) return false;
	if(!this->__register_class_method("entity","uint get_mount_vnum()",asMETHOD(hBot2::entity,get_mount_vnum))) return false;

    if(!this->__register_class("network_stream")) return false;
    if(!this->__register_class_method("network_stream","bool connect(string ip, uint16 port)",asMETHOD(hBot2::client,connect))) return false;
    if(!this->__register_class_method("network_stream","void disconnect()",asMETHOD(hBot2::client,disconnect))) return false;
    if(!this->__register_class_method("network_stream","bool is_connected()",asMETHOD(hBot2::client,is_connected))) return false;
	if(!this->__register_class_method("network_stream","uint16 get_port()",asMETHOD(hBot2::client,get_port))) return false;
	if(!this->__register_class_method("network_stream","string get_ip()",asMETHOD(hBot2::client,get_ip))) return false;

	if(!this->__register_class_method("network_stream","entity@ find_entity(uint&in vid)",asMETHOD(hBot2::client,get_entity))) return false;
	if(!this->m_engine->RegisterObjectMethod("network_stream","entity@ get_entity(uint&in idx)",asFUNCTION(asGET_ENTITY),asCALL_CDECL_OBJFIRST)<0) return false;
	if(!this->m_engine->RegisterObjectMethod("network_stream","uint get_entity_count()",asFUNCTION(asGET_ENTITY_COUNT),asCALL_CDECL_OBJFIRST)<0) return false;

    if(!this->__register_class_method("network_stream","void send_auth(string username, string password)",asMETHOD(hBot2::client,send_auth))) return false;
    if(!this->__register_class_method("network_stream","void send_login(string username, uint key)",asMETHOD(hBot2::client,send_login))) return false;
    if(!this->__register_class_method("network_stream","void send_select_character(uint8 index)",asMETHOD(hBot2::client,send_select_character))) return false;
	if(!this->__register_class_method("network_stream","void send_chat(uint8 type, string text)",asMETHOD(hBot2::client,send_chat))) return false;
	if(!this->__register_class_method("network_stream","void send_version(string filename, string timestamp)",asMETHOD(hBot2::client,send_version))) return false;
	if(!this->__register_class_method("network_stream","void send_create_character(uint8 idx, string name, uint16 job, uint8 shape, uint8 con, uint8 intr, uint8 str, uint8 dex)",asMETHOD(hBot2::client,send_create_character))) return false;
	if(!this->__register_class_method("network_stream","void send_delete_character(uint8 idx, string code)",asMETHOD(hBot2::client,send_delete_character))) return false;
	if(!this->__register_class_method("network_stream","void send_select_empire(uint8 empire)",asMETHOD(hBot2::client,send_select_empire))) return false;
	if(!this->__register_class_method("network_stream","void send_move(int x, int y, uint8 rot, uint8 func, uint8 arg)",asMETHOD(hBot2::client,send_move))) return false;
	if(!this->__register_class_method("network_stream","void send_pick_up(uint vid)",asMETHOD(hBot2::client,send_pick_up))) return false;
	if(!this->__register_class_method("network_stream","void send_attack(uint8 type, uint vid)",asMETHOD(hBot2::client,send_attack))) return false;
	if(!this->__register_class_method("network_stream","void send_on_click(uint vid)",asMETHOD(hBot2::client,send_on_click))) return false;
	if(!this->__register_class_method("network_stream","void send_hack(string text)",asMETHOD(hBot2::client,send_hack))) return false;
	if(!this->__register_class_method("network_stream","void send_fishing()",asMETHOD(hBot2::client,send_fishing))) return false;
	if(!this->__register_class_method("network_stream","void send_answer_make_guild(string name)",asMETHOD(hBot2::client,send_answer_make_guild))) return false;
	if(!this->__register_class_method("network_stream","void send_item_use(uint8 pos)",asMETHOD(hBot2::client,send_item_use))) return false;

	if(!this->__register_class("item")) return false;
	if(!this->__register_class_method("item","uint get_vid()",asMETHOD(hBot2::item,get_vid))) return false;
	if(!this->__register_class_method("item","uint get_vnum()",asMETHOD(hBot2::item,get_vnum))) return false;
	if(!this->__register_class_method("item","uint get_owner()",asMETHOD(hBot2::item,get_owner))) return false;
	if(!this->__register_class_method("item","int get_x()",asMETHOD(hBot2::item,get_x))) return false;
	if(!this->__register_class_method("item","int get_y()",asMETHOD(hBot2::item,get_y))) return false;

    if(!this->m_engine->RegisterObjectType("config",0,asOBJ_REF)<0) return false;
    if(!this->m_engine->RegisterObjectBehaviour("config",asBEHAVE_FACTORY,"config@ f(string fname)",asFUNCTION(asCreateConfig),asCALL_CDECL)<0) return false;
    if(!this->m_engine->RegisterObjectBehaviour("config",asBEHAVE_ADDREF,"void f()",asMETHOD(hBot2::config,addref),asCALL_THISCALL)<0) return false;
    if(!this->m_engine->RegisterObjectBehaviour("config",asBEHAVE_RELEASE,"void f()",asMETHOD(hBot2::config,decref),asCALL_THISCALL)<0) return false;
    if(!this->__register_class_method("config","string get(string key, string def = \"\")",asMETHOD(hBot2::config,get_string))) return false;
    if(!this->__register_class_method("config","uint64 get(string key, uint64 def = 0)",asMETHOD(hBot2::config,get_int))) return false;
    if(!this->__register_class_method("config","bool get(string key, bool def = false)",asMETHOD(hBot2::config,get_bool))) return false;
    if(!this->__register_class_method("config","float get(string key, float def = 0)",asMETHOD(hBot2::config,get_float))) return false;
    if(!this->__register_class_method("config","double get(string key, double def = 0)",asMETHOD(hBot2::config,get_double))) return false;
    if(!this->__register_class_method("config","string get_string(string key, string def = \"\")",asMETHOD(hBot2::config,get_string))) return false;
    if(!this->__register_class_method("config","uint64 get_int(string key, uint64 def = 0)",asMETHOD(hBot2::config,get_int))) return false;
    if(!this->__register_class_method("config","bool get_bool(string key, bool def = false)",asMETHOD(hBot2::config,get_bool))) return false;
    if(!this->__register_class_method("config","float get_float(string key, float def = 0)",asMETHOD(hBot2::config,get_float))) return false;
    if(!this->__register_class_method("config","double get_double(string key, double def = 0)",asMETHOD(hBot2::config,get_double))) return false;
	if(!this->__register_class_method("config","bool set(string key, string val)",asMETHOD(hBot2::config,set_string))) return false;
	if(!this->__register_class_method("config","bool set(string key, uint64 val)",asMETHOD(hBot2::config,set_int))) return false;
	if(!this->__register_class_method("config","bool set(string key, bool val)",asMETHOD(hBot2::config,set_bool))) return false;
	if(!this->__register_class_method("config","bool set(string key, float val)",asMETHOD(hBot2::config,set_float))) return false;
	if(!this->__register_class_method("config","bool set(string key, double val)",asMETHOD(hBot2::config,set_double))) return false;
	if(!this->__register_class_method("config","bool set_string(string key, string val)",asMETHOD(hBot2::config,set_string))) return false;
	if(!this->__register_class_method("config","bool set_int(string key, uint64 val)",asMETHOD(hBot2::config,set_int))) return false;
	if(!this->__register_class_method("config","bool set_bool(string key, bool val)",asMETHOD(hBot2::config,set_bool))) return false;
	if(!this->__register_class_method("config","bool set_float(string key, float val)",asMETHOD(hBot2::config,set_float))) return false;
	if(!this->__register_class_method("config","bool set_double(string key, double val)",asMETHOD(hBot2::config,set_double))) return false;

    if(this->m_engine->RegisterGlobalProperty("network_stream@ net",&this->m_client)<0) return false;

    return true;
};

bool hBot2::as_engine::load_script(const std::string& name, const std::string& code)
{
    if(this->m_builder->AddSectionFromMemory(name.c_str(),code.c_str(),code.size())<0)
        return false;
    return true;
};
bool hBot2::as_engine::load_script(const std::string& filename)
{
    if(this->m_builder->AddSectionFromFile(filename.c_str())<0)
        return false;
    return true;
};

bool hBot2::as_engine::call_callback(std::string callback, const std::string& params, ...)
{
    transform(callback.begin(),callback.end(),callback.begin(),tolower);
    std::vector<asIScriptFunction*> funcs;
    this->lock();
    for(uint32_t i = 0; i < this->get_module()->GetFunctionCount(); ++i) {
        asIScriptFunction* fnc = this->get_module()->GetFunctionByIndex(i);
        if(fnc == nullptr)
            continue;

        std::string metastr = this->m_builder->GetMetadataStringForFunc(fnc);
        transform(metastr.begin(),metastr.end(),metastr.begin(),tolower);

        if(metastr == callback)
            funcs.push_back(fnc);
    }

    bool result = true;
    for(uint32_t i = 0; i < funcs.size(); ++i) {
        va_list args;
        va_start(args,params);
        if(!this->__call_func(funcs[i],params,'u',nullptr,args))
            result = false;
        va_end(args);
    }
    this->unlock();

    return result;
};
bool hBot2::as_engine::call_function(const std::string& function, const std::string& params, char rt, void** ret, ...)
{
    this->lock();
    asIScriptFunction* func = this->get_module()->GetFunctionByName(function.c_str());
    if(func == nullptr) {
        this->unlock();
        return false;
    }

    va_list args;
    va_start(args,ret);
    bool result = this->__call_func(func,params,rt,ret,args);
    va_end(args);
    this->unlock();

    return result;
};

bool hBot2::as_engine::build() { return this->m_builder->BuildModule()>=0; };

bool hBot2::as_engine::__register_class(const std::string& name) { return this->m_engine->RegisterObjectType(name.c_str(),0,asOBJ_REF|asOBJ_NOCOUNT)>=0; };
bool hBot2::as_engine::__register_class_method(const std::string& name, const std::string& funcdecl, asSFuncPtr funcptr) { return this->m_engine->RegisterObjectMethod(name.c_str(),funcdecl.c_str(),funcptr,asCALL_THISCALL)>=0; };

bool hBot2::as_engine::__call_func(asIScriptFunction* func, const std::string& params, char rt, void** ret, va_list args)
{
    asIScriptContext* ctx = this->m_engine->CreateContext();
    if(ctx == nullptr) {
        hBot2::syserr("%s","Can not create script context!");
        return false;
    }
    if(ctx->Prepare(func)<0) {
        hBot2::syserr("%s","Can not prepare script context!");
        ctx->Release();
        return false;
    }

    std::vector<std::string*> strings;

    for(uint32_t i = 0; i < params.size(); ++i) {
        switch(params[i])
        {
            case 'u':
            case 'i':
            {
                ctx->SetArgDWord(i,va_arg(args,uint32_t));
            } break;
            case 'b':
            case 'x':
            {
                ctx->SetArgByte(i,va_arg(args,uint32_t));
            } break;
            case 'w':
            {
                ctx->SetArgWord(i,va_arg(args,uint32_t));
            } break;
            case 'q':
            {
                ctx->SetArgQWord(i,va_arg(args,uint64_t));
            } break;
            case 's':
            {
                std::string* s = new std::string(va_arg(args,char*));
                strings.push_back(s);
                ctx->SetArgObject(i,s);
            } break;
            case 'p':
            case 'o':
            {
                ctx->SetArgObject(i,va_arg(args,void*));
            } break;
            case 'a':
            {
                ctx->SetArgAddress(i,va_arg(args,void*));
            } break;
            default:
                hBot2::syserr("Unknown parameter type '%c'!",params[i]);

                for(uint32_t i = 0; i < strings.size(); ++i)
                    delete strings[i];

                return false;
        }
    }

    int r = ctx->Execute();

    for(uint32_t i = 0; i < strings.size(); ++i)
        delete strings[i];

    if(r != asEXECUTION_FINISHED) {
        if(r == asEXECUTION_EXCEPTION)
            hBot2::syserr("AS Error: %s (%s)",ctx->GetExceptionString(),ctx->GetExceptionFunction()->GetName());
        ctx->Release();
        return false;
    }

    if(ret != nullptr) {
        switch(rt)
        {
        	case 'u':
            case 'i':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnDWord());
            } break;
            case 'b':
            case 'x':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnByte());
            } break;
            case 'w':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnWord());
            } break;
            case 'q':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnQWord());
            } break;
            case 's':
            case 'p':
            case 'o':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnObject());
            } break;
            case 'a':
            {
                *ret = reinterpret_cast<void*>(ctx->GetReturnAddress());
            } break;
            default:
                hBot2::syserr("Unknown return type '%c'!",rt);
                ctx->Release();
                return false;
        }
	}
    ctx->Release();

    return true;
};

void hBot2::as_engine::message_callback(const asSMessageInfo &msg)
{
    const char *type;
    if(msg.type == asMSGTYPE_WARNING)
        type = "Warning";
    else if(msg.type == asMSGTYPE_INFORMATION)
        type = "Info";

    if(msg.type == asMSGTYPE_ERROR)
        SYSERR("ASEngine Error: " << msg.section << " (" << msg.row << ", " << msg.col << "): " << msg.message);
    else
        SYSLOG("ASEngine " << type << ": "  << msg.section << " (" << msg.row << ", " << msg.col << "): " << msg.message);
};

This is the full source of my script engine and somehow I'm assuming that I've forgotten some important things.. I'm pretty new to AngelScript.

As Jake answered, to call a script class method, you first need to have the pointer to the object instance so you can pass it to the context with SetObject(). (manual)

However, I don't see anywhere in your code where you're getting the class methods to call. I only see the code where you're retrieving global functions from the script. To get the asIScriptFunction for a class method you have to call one of the GetMethodByXXX methods on asIObjectType.

I don't think you're calling class methods at all and the error is probably unrelated. Can you show us the script that you're trying to call when you get the "null pointer access" error? It would help in understanding what is causing it.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

For example, I'm calling "OnStartup" like that:

this->m_engine->call_function("OnStartup","",'u',reinterpret_cast<void**>(&rs))

This is my test case for the OnStartup function, which always fails:


bool OnStartup()
{
	int x = 0;
	x = net.find_entity(0).get_x();
	
	return true;
};

it fails at net.find_entity(0).get_x().

I seriously have no idea where to look for this error.

As I suspected, you're not calling a class method, so the SetObject() info was wrong.

There are two places where this script can raise a 'Null pointer access' error.

1. When accessing the global variable 'net' and that variable is null

2. When accessing the handle returned by find_entity() and that handle is null

I can see that you've registered 'net' with


    if(this->m_engine->RegisterGlobalProperty("network_stream@ net",&this->m_client)<0) return false;

, which means the script will use the object that m_client points to when the script is called. It appears to be initialized with a valid pointer in the as_engine constructor, but you may want to confirm the value of this member when calling the script to make sure it really is set as it should.

The find_entity() is registered with


 if(!this->__register_class_method("network_stream","entity@ find_entity(uint&in vid)",asMETHOD(hBot2::client,get_entity))) return false;

Is the method really returning a handle to an entity instance? Or is it returning a null pointer? Is the refcount of the entity incremented by the method when returning? AngelScript will release the returned handle afterwards, so it must be increased unless you don't want to keep the reference in the application.

It may be a good idea to change the script to check for a returned null handle before attempting to use it:


bool OnStartup()
{
  int x = 0;
  entity @ent = net.find_entity(0);
  if( ent !is null )
    x = ent.get_x();

  return true;
};

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks for looking into this. I really appreciate your help.

As I now see, I was looking for the wrong thing all the time..

This seems reasonable for me, I've taken a look into my client- and entity-class and get_entity(uint32_t vid) is actually returning a nullptr, regardless of how many entities there are. I'm feeling pretty dumb about not finding this.. everything a Google search about "null pointer access" regarding AngelScript brought me was this SetObject thing, so I was sticking to it.

This topic is closed to new replies.

Advertisement