🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Strings

Started by
8 comments, last by WitchLord 19 years, 9 months ago
I have a problem that is nailing me in the back. I followed Dentoid's example on using the STL string for AS. When I pass strings from the host application to script functions, everything seems to work ok. But when I start making calls between script functions using string params/return values, then all hell breaks out. This code block shows the utility script functions (called by other script functions):

string get_string(Data* pObj, string tag)
{
	string temp;
	pObj->GetAttributeBase(tag, temp);
	return temp;
}

void sendto(Data* pTarget, string text)
{ pTarget->EnqueueOutput(text); }

This block shows two versions of the same function that are called by the host application:

// This version works fine
void look_monster(Data* pPlayer, Data* pMonster)
{
	string m_name, m_desc, p_name;

	pPlayer->GetAttributeBase("name", p_name);
	pMonster->GetAttributeBase("name", m_name);
	pMonster->GetAttributeBase("desc", m_desc);

	sendto(pPlayer->GetParent(), "\x1B[0;37m" + p_name + " looks at " + m_name + ".\r\n", pPlayer);
	sendto(pPlayer, "\x1B[1;36m" + p_name + "\r\n\x1B[0;37m" + m_desc + "\r\n");
}

// This version crashes
void look_monster(Data* pPlayer, Data* pMonster)
{
	string m_name = get_string(pMonster, "name");
	string m_desc = get_string(pMonster, "desc");
	string p_name = get_string(pPlayer, "name");

	sendto(pPlayer, m_name); // Prints ok
	sendto(pPlayer, m_desc); // Prints ok
	sendto(pPlayer, p_name); // Prints garbage

//	This crashes
//	sendto(pPlayer->GetParent(), "\x1B[0;37m" + p_name + " looks at " + m_name + ".\r\n", pPlayer);
//	sendto(pPlayer, "\x1B[1;36m" + p_name + "\r\n\x1B[0;37m" + m_desc + "\r\n");
}

This is how I am setting up the string in AS.

string string_factory(asUINT length, const char *s)			{ return string(s); }
void string_ctor(string *pthis)								{ new(pthis)string(); }
void string_dtor(string *pthis)								{ pthis->~string(); }
//string& string_assign_string(string &copy, string *pthis)	{ return *new(pthis)string(copy); }
string& string_assign_string(string &copy, string *pthis)	{ return *pthis = copy; }
bool string_equal(const string &l, const string &r)			{ return l == r; }
bool string_not_equal(const string &l, const string &r)		{ return l != r; }
string string_add_string(const string &l, const string &r)	{ return l + r; }


	pEngine->RegisterObjectType("string", sizeof (string), asOBJ_IS_COMPLEX);
	pEngine->RegisterStringFactory("string", asFUNCTION(string_factory), asCALL_CDECL/* | asCALL_RETURNBYREF*/);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(string_ctor), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(string_dtor), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_ASSIGNMENT, "string& f(string&)", asFUNCTION(string_assign_string), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_EQUAL, "bool f(const string&, const string&)", asFUNCTION(string_equal), asCALL_CDECL);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_NOTEQUAL, "bool f(const string&, const string&)", asFUNCTION(string_not_equal), asCALL_CDECL);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_ADD, "string f(const string&, const string&)", asFUNCTION(string_add_string), asCALL_CDECL);

I've been staring at this code for too long now and am not any closer to an answer. Any one have an idea?
Advertisement
Oh, one more thing:

string m_name = get_string(pMonster, "name");
string m_desc = get_string(pMonster, "desc");
string p_name = get_string(pPlayer, "name");

It is always the 3rd string that becomes gibberish, regardless of which order the calls are in.
Since it is always the third call that fails, regardless of order it is possibly a bug in AngelScript. I'll take a look at it as soon as possible.

In the meanwhile: What version of the library are you using?

You might also want to use string get_string(Data* pObj, string &tag) instead, since it would avoid passing the string object by value. It will probably not solve your problem but it is a little more efficient.


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

I found two different bugs in WIP 4 that might be related to your problem:

as_bytecode.cpp, ln 293, change to:

d.sfOffset = 0x7FFFFFFE;


as_bytecode.cpp, ln 342, change to:

if( destructors[n].sfOffset == 0x7FFFFFFE )


as_compiler.cpp, ln 1318 - 1321, change to:

{  bc->InstrWORD(BC_COPY, (short)a->type.GetSizeInMemoryDWords());  bc->Pop(1); // Pop the reference to original value}


With these changes I can successfully run the following test case:
//// This test shows how to register the std::string to be used in the scripts.// It also used to verify that objects are always constructed before destructed.//// Author: Andreas Jönsson//#include "angelscript.h"#include <stdio.h>#include <string.h>#include <string>using namespace std;#define TESTNAME "TestStdString"class COutStream : public asIOutputStream{public:	void Write(const char *text) { printf(text); }};static string StringFactory(asUINT length, const char *s){	return string(s);}static void ConstructString(string *thisPointer){	new(thisPointer) string();}static void DestructString(string *thisPointer){	thisPointer->~string();}static string &AssignString(string &other, string &thisPointer){	return thisPointer = other;}static string ConcatenateString(string &first, string &second){	return first + second;}static string printOutput;static void PrintString(string &str){	printOutput = str;}static const char *script2 ="void testString()               \n""{                               \n""  print(getString(\"Ida\"));    \n""}                               \n""                                \n""string getString(string &str)   \n""{                               \n""  return \"hello \" + str;      \n""}                               \n";bool TestStdString(){	bool fail = false;	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);    engine->RegisterObjectType ("string", sizeof(string), asOBJ_CLASS_CDA);    engine->RegisterStringFactory ("string", asFUNCTION(StringFactory), asCALL_CDECL);    engine->RegisterObjectBehaviour ("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST);    engine->RegisterObjectBehaviour ("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST);    engine->RegisterObjectBehaviour ("string", asBEHAVE_ASSIGNMENT, "string &f(const string&)", asFUNCTION(AssignString), asCALL_CDECL_OBJLAST);	engine->RegisterObjectBehaviour (0, asBEHAVE_ADD, "string f(const string&, const string &)", asFUNCTION(ConcatenateString), asCALL_CDECL);	engine->RegisterGlobalFunction("void print(string &)", asFUNCTION(PrintString), asCALL_CDECL);	COutStream out;	engine->AddScriptSection(0, TESTNAME, script2, strlen(script2), 0);	engine->Build(0, &out);	engine->ExecuteString(0, "testString()", &out, 0);	if( printOutput != "hello Ida" )	{		fail = true;		printf("%s: Failed to print the correct string\n", TESTNAME);	}	engine->Release();	return fail;}



You're probably running version 1.8.2, right? I'll verify if the same bugs exists in that version and let you know how to fix them.


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

I'm using 1.8.1 at the moment (last official release when I started my project). I'm to a point in my project that it wont be any hassle to start trying out the WIPs, so I'll upgrade to the latest one.

Thanks for the response. Going to lunch now but I'll check your suggestions when I get back
I tried changing "get_string(Data* pData, string tag)" to "get_string(Data* pData, string& tag)" but that didnt work. For example, if I have a statement like "string p_name = get_string(pPlayer, "name")", then AS will call the function ok. But afterwards, any attempt to use p_name will cause AS to quiety abort out of the function.

I download WIP4 and applied the changes you suggested, but AS is refusing to compile my script code:

Code.as (514, 7) : Error   : Expected '('Code.as (517, 2) : Error   : Expected expression valueCode.as (521, 38) : Error   : Expected expression valueCode.as (526, 2) : Error   : Expected expression valueCode.as (531, 2) : Error   : Expected expression valueCode.as (536, 2) : Error   : Expected expression valueCode.as (541, 2) : Error   : Expected expression valueCode.as (546, 2) : Error   : Expected expression valueCode.as (551, 2) : Error   : Expected expression valueCode.as (556, 2) : Error   : Expected expression valueCode.as (561, 2) : Error   : Expected expression valueCode.as (566, 2) : Error   : Expected expression value


I am assuming the line numbers relate to the code below are correct. I only have one script file and I added the section at line offset 0.

511 void show_move(Data* pPlayer, Data* pDst, Data* pSrc)512 {513 	uint temp = 0;514 	uint from = 0;515 	string name, to_src, to_dst;516 517 	from = pSrc->GetId();518 519 	pPlayer->GetAttributeBase("name", name);520 521	if (pDst->GetRefid("east", temp) && from == temp)	// ...


I'm still looking into this problem at the moment, but yeah, it doesn't make a lot of sense.
At the moment it seems that if functions that have 2 or more uints declared are causing the problems. If I remove one of the uints from the function it compiles ok.

Also, the declaration "uint temp, from" results in "Code.as (590, 13) : Error : Expected identifier"
"from" is a reserved keyword in 1.9.0, as is "import". This is why you're getting these errors.

They are used by the new global statement:

import void function_decl(int param1, int param2) from "module";

I've yet to come up with a good solution for allowing the use of these keywords in other contexts, e.g. variable names.

You could temporarily rename the keywords by changing the as_tokendef.h file.

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

Oh man... Its nice when things are not serious, but damn.. I feel like a dork!
No worries. [smile]

I believe I've figured out a way to avoid making 'from' a reserved keyword. I'll try to incorporate it into WIP 5.

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

This topic is closed to new replies.

Advertisement