Page 1 of 1

Who needs a scripting language? When compiled C will do.

Posted: Fri Apr 09, 2010 10:14 am
by avansc
Okay, well maybe thats a little miss leading, and yes, perhaps there are things this following method can't do that you can in some scripting language.
This method however does allow you to dynamically use compiled C code, WITHOUT changing the codebase.

What we are going to be using is called dynamic linking, dlfcn.h is the header that will give us all the goodies to do this.

NOTE : This will require you to do some planning because you have to have a alias to get to the code in in the library you will dynamically linked.

lets look at this code.

dynamic.h

Code: Select all

#ifndef _dynamic_h
#define _dynamic_h

extern "C" int calc(int a);

#endif
dynamic.cpp

Code: Select all

#include <stdio.h>

#include "dynamic.h"

int calc(int a) {
	return a*a;
}
Okay, so thats pretty straight forward, we compile this code into a dynamic library, that would be dll/so/dylib for window/linux/osx, respectively.
i called it dynamic and my particular extension was dylib.(OSX)

Now for the main code.

main.cpp

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(void)
{
	void *handle;
	int (*calc)(int);
	
	handle = dlopen("dynamic.dylib", RTLD_NOW);
	if(handle == NULL) {
		printf("%s\n", dlerror());
		exit(1);
	}
	
	calc = (int(*)(int)) dlsym(handle, "calc");
	
	if(dlerror() != NULL)
	{
		printf("%s\n", dlerror());
		exit(-1);
	}
	
	for(int a = 1;a <= 5;a++)
		printf("%d squared = %d\n", a, calc(a));
	
	dlclose(handle);
	
	return 0;
}
the most important line is, calc = (int(*)(int)) dlsym(handle, "calc");
here it looks for a function called calc in the library that we loaded, (well the extern C bit, but yanno).

and well the rest is pretty straight forward.

on a side note i have been trying to do it where you have a single base class with a few smart virtual functions, then the libraries would have inherited that, so that you only use say cNPC in the main program, but you can extend the code base dynamically by making class cDragon : public cNPC or something like that. but im having a little issue where it will load fine but its crashing once i call functions on the NPC class that are virtual. anyways.

if you spend some time and make a few functions that will stay consistent you can really use this to your advantage.
you can change entire render systems and so on, make expansions like this, levels, weapons, the possibilities really are endless. and the best part of all is that its compiler, so its fast, and you dont have to change your codebase.

Re: Who needs a scripting language? When compiled C will do.

Posted: Fri Apr 09, 2010 12:43 pm
by Ginto8
So basically this has you compile all the "script" functions into a shared/dynamic library, and then dynamically use those functions from the executable? That sounds cool :)

Re: Who needs a scripting language? When compiled C will do.

Posted: Fri Apr 09, 2010 12:50 pm
by GroundUpEngine
Custom dll's, I like it! :)

Re: Who needs a scripting language? When compiled C will do.

Posted: Fri Apr 09, 2010 1:03 pm
by avansc
Okay, so i finally got inherited classes to work, this is really where this technique will pull a bukake on a scripted version.

In this example you have a base class, cNPC. that gets compiled into your main app. Now, we want to make a dragon enemy, but its not really nice having to have to recompile the base just to add a new character or enemy. and its really impractical if you have a shipped version of the game.

so here we compile a new dynamic library that inherits from the cNPC class, and over rides functions that characters need to do, in this case i just have attack, since this is just for academic illustration.

then when you use the cNPC in the codebase it will act like the COMPILED code of the dragon.

lets take a look at the code.

cNPC.h // i dont have a cNPC.cpp since its so minimal

Code: Select all

#ifndef _cNPC_h
#define _cNPC_h

class cNPC
{
public:
	virtual void attack() const = 0;
};

typedef cNPC *create_t();
typedef void destroy_t(cNPC*);

#endif
cDragon.h

Code: Select all

#ifndef _cDragon_h
#define _cDragon_h

#include "cNPC.h"

class cDragon : public cNPC
{
public:
	virtual void attack() const;
};

extern "C" cNPC* create();
extern "C" void destroy(cNPC *t);

#endif
cDragon.cpp

Code: Select all

#include <stdio.h>

#include "cDragon.h"

void cDragon::attack() const
{
	printf("Dragon attack!\n");
}

cNPC* create()
{
	return new cDragon;
}

void destroy(cNPC *t)
{
	delete t;
}
main.cpp

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

#include "cNPC.h"

int main(void)
{	
	void *handle = dlopen("cDragon.dylib", RTLD_NOW);
	
	if(handle == NULL) {
		printf("%s\n", dlerror());
		exit(1);
	}
	
	create_t* create_npc = (create_t*)dlsym(handle, "create");
	destroy_t* destroy_npc = (destroy_t*)dlsym(handle, "destroy");
	
// should check for errors here, but fux that for now.

	cNPC *dragon = create_npc();
	dragon->attack();
	
	
	return 0;
}

Re: Who needs a scripting language? When compiled C will do.

Posted: Mon Apr 19, 2010 2:24 pm
by TheOtherGyro
Problem with this is, most modders and mappers don't know C++. Also, that sounds like it would be a bitch to port to another platform.

Other than that, it's pretty cool. It sounds to me like that would be blazing fast compared to using a scripting language. Have you done any benchmarking?

Re: Who needs a scripting language? When compiled C will do.

Posted: Mon Apr 19, 2010 2:26 pm
by Falco Girgis
TheOtherGyro wrote:Problem with this is, most modders and mappers don't know C++. Also, that sounds like it would be a bitch to port to another platform.

Other than that, it's pretty cool. It sounds to me like that would be blazing fast compared to using a scripting language. Have you done any benchmarking?
It would be blazingly fast, but the entire point of a scripting language is that you don't have to compile the assets.

And yeah, that's not very platform independent.