• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Flurreh Kitsune Flufftail

Null pointer access

6 posts in this topic

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

0

Share this post


Link to post
Share on other sites

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.

2

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

1

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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;
};
1

Share this post


Link to post
Share on other sites

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.

Edited by Flurreh
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0