Ok, so i am confused.
Please give me reasons why people aren't using boost more?
I will do my own opinion on using boost at an engine level some time but it makes no sense.
"So you want a cross platform high performance engine? Well good luck doing all the low level code for each platform!"
Thats where boost comes in, it makes everything so easy. Threading? EASY. generics? EASY. EASY.
Imo, easy = quicker. Less code, easier to maintain.
Dependency oh noes! What year are you living in?
</rant>
Update : To clarify, I guess i am referring to the people using "non boost" c++, the people spending a long time doing low level OS stuff, making game engines with their own platform layers that just waste hordes of time ?
A formatting note - I have tried to clean the code a little to work with this width of page. The original code with less dumbassery is linked in the header file here for reference. Get the example code from here : LINK I know i needed one. When i had chosen v8 as my weapon of choice i found it to be incredibly easy to grasp. What i didnt expect is for the simplicity to grab me around the ankles and dangle me off the edge of confusion cliff. Before i realised i was scratching my head with a few good c++ books open wondering what on earth i had done wrong that was giving v8 exceptions from a single line of code. What i would advise, is try to avoid shortcuts. I was using CProxyV8, i had seen v8Juice and both of them are really neat, but every single error i ran into was related to me not understanding what it is v8 was actually asking for and most times it was because of the use of the wrappers. Finding my own way I learnt a few things along the way - using v8 from the ground up is actually easier to understand. The first thing that helps is to look at the v8 namespace comments as they usually reveal something important, if its related to the JS side, or if its related to the c++ side.Once i saw that i was attempting to use a JS object as a c++ class, yea things started to make more sense. What i needed from v8. Now while the point and line class example is so heavily leaned on, it still didnt really help me to figure out the route i needed to take to expose certain classes to the script environment. The included sample http process and the other samples also , did things in a very straightforward and limited way. Below i will present an empty class from my codebase, with the code i used to expose and gracefully use the script side easily. I needed to wrap and unwrap a class. In order to expose a class to JS, i wanted to use an EXISTING C++ class, and just pass a pointer/handle to the scripts. That way i can also control what part of my game/scripts they can actually overwrite and change, and what instances of class they can manipulate. For example, i dont want multiple instances of the core, or any subsystem of the core. I just want a script side global(used loosely here) that the script writer can access (and which also protects him from accidentally overwriting one of my objects). A template based helper function I wrote 2 functions that are free to use , and will wrap and unwrap a class accordingly. The usage of the code provided here is shown lower down, so it might not make sense here. Wrapping involves creating a JS object from a c++ class, and maintaining a handle to manipulate it, and unwrapping involves unwrapping an object to a c++ pointer again, normally from the v8arguments handle that a function passes in on being called. example use : ExposeClass< somenamespace::someClass >( somev8Context, someClassInstance, v8::String::New("someclass"), v8::ReadOnly);
//http://blog.owned.co.za v8 Javascript Helper Function ,
//Give this function the c++ object (an instance) to wrap,
//and it returns a JS object to expose things under.
//Note theres 2 functions here ,
//the top one is used by the ExposeClass function
template
v8::Handle WrapClass(T* y)
{
// Handle scope for temporary handles,
v8::HandleScope handle_scope;
v8::Persistent class_template_;
v8::Handle rt = v8::ObjectTemplate::New();
//The raw template is the ObjectTemplate
// (that can be exposed to script too)
//but is maintained internally.
rt->SetInternalFieldCount(1);
//Create the actual template object,
class_template_ = v8::Persistent::New(rt);
//Create the new handle to return, and set its template type
v8::Handle result = class_template_->NewInstance();
v8::Handle class_ptr
class_ptr = v8::External::New(static_cast(y));
//Point the 0 index Field to the c++ pointer for unwrapping later
result->SetInternalField(0, class_ptr);
//Return the value, releasing the other handles on its way.
return handle_scope.Close(result);
}
template
v8::Handle ExposeClass(v8::Persistent context,
T* y,
v8::Handle exposedName,
v8::PropertyAttribute props)
{
v8::HandleScope handle_scope;
v8::Handle obj = Core::Script::WrapClass(y);
context->Global()->Set(exposedName, obj, props);
return handle_scope.Close(obj);
}
And for unwrapping - (usually inside CALLED functions from script. use : someNamespace::someClass* sc = UnwrapClass< someNamespace::someClass >( myJSObjToUnwrap );
//http://blog.owned.co.za v8 Javascript Helper Function ,
//Give this function the v8 JS object to unwrap, and the class to unwrap to.
template
T* UnwrapClass(v8::Handle obj)
{
v8::Handle field;
field = v8::Handle::Cast(obj->GetInternalField(0));
void* ptr = field->Value();
return static_cast(ptr);
}
How i use the above templates Nobody is claiming magic in the code above, it might even be wrong and or, doing something badly. I just found it to work - any comments and fixes will be noted and adjusted if you comment. Now, the usage, at least MY usage of the above code was to expose c++ classes with existing c++ functions to the script context. Step 1 - A Class to expose, with some members id like in scripts. First, i have a c++ class declared, with some static functions that i would like to expose.
class cCore
{
public:
//This is a simple example,
//do not copy this as a real class.
cCore(){};
~cCore() {};
//We need a persistant handle to the core in scripts, a non persistant
//v8::Handle will get lost in the handle scopes,
//and throw some weird exceptions to hunt down.
//Wrap class and unwrap class return
//NON persistant handles, so store your own
//persistant ones if you want to
//use it outside of the first handle scope.
//core script object, "core" in scripts.
v8::Persistent cso_core;
//We expose some functions in our class to the scripts from c++,
//By wrapping an object (cso_core above) and the attaching functions
//to that object. Those functions, when called from javascript -
//end up here.
//The functions are self explanatory.
//Print some text to the console/ui console
static v8::Handle xecho(const v8::Arguments& args);
//execute a javascript file
static v8::Handle xexec(const v8::Arguments& args);
//exit all systems and shutdown
static v8::Handle xexit(const v8::Arguments& args);
}; //end class declaration
Step 2 - Creating the Javascript Object , of my class.
//Just for clarity sake, so you can see my workflow.
void cScriptSystem::startup()
{
//Create a script engine for the core
v8::HandleScope handle_scope;
//Create a context for the system to use
//(i have just one at this point)
coreContext = v8::Context::New(NULL, global);
//Enter the main context, making it active.
v8::Context::Scope context_scope(coreContext);
exposeCore(); //see below
};
//And the code to expose the class,
void cScriptSystem::exposeCore()
{
v8::HandleScope handlescope;
//This will be reused to expose multiple
//classes, short name for easy code.
v8::Handle cc;
//get the JS version of the C++ object,
//note that core is simply Core::cCore* core;
cc = ExposeClass< Core::cCore >(coreContext, core,
v8::String::New("core"),
v8::ReadOnly);
//set the persistant handle for use outside of this handlescospe
core->cso_core = v8::Persistent::New(cc);
//Give the functions to the object.
//This makes the functions come out as
//core.echo(), core.exec(), core.exit() in scripts.
Expose(core->cso_core, v8::String::New("echo") ,
v8::InvocationCallback(Core::cCore::xecho));
Expose(core->cso_core, v8::String::New("exec") ,
v8::InvocationCallback(Core::cCore::xexec));
Expose(core->cso_core, v8::String::New("exit") ,
v8::InvocationCallback(Core::cCore::xexit));
};
Step 3 - Actually handling the function calls on the c++ side. This is where the unwrapClass comes in... If you noticed the v8::Arguments& args on the functions, it hands in the class that the function is being called upon. So if i called core.exit() , the object that it will pass me is the core object (our C++ object, in JS form). See the code for clarity,
v8::Handle cCore::xexit(const v8::Arguments& args)
{
//args.Holder() is the object that the function was invoked upon.
//This means it could be exposed to 2 classes,
//under different types so be sure
//that you dont just randomly unwrap into the wrong container type.
Core::cCore* core = UnwrapClass( args.Holder() );
//The code inside the normal exit function is identical,
//so i can just call the normal c++ code directly.
core->startShutdown();
//This is to return void, basically.
return v8::Undefined();
}
Step 4 - The missing function. I left out a function along the way, you may have noticed. The function is called Expose,
void Expose(v8::Handle intoObject, v8::Handle namev8String, v8::InvocationCallback funcID)
{
v8::HandleScope handle_scope;
v8::Handle thisFunc;
thisFunc = v8::FunctionTemplate::New(funcID);
intoObject->Set(namev8String, thisFunc->GetFunction());
}
Conclusion I hope this helps clarify the v8 logic, and helps users figure out how easy it actually is to automate things with templates and macros. Theres still many ways to simplify the code above but for simplicity - take it as it is. In closing, v8 offers some super easy to use casting functions. Ill give some examples as i found these to be really nice but be wary, do exception handling, type checking and proper management of values handed to c++ from v8. It will save you some time looking through v8 exception callstacks if you manually handle possible exceptions.
//you can now use it std::string(*somestdstring)
v8::String::Utf8Value somestdstring ( args[0] );
//you can now use it *somecstring (same as const char* somecstring;)
v8::String::Utf8Value somecstring ( args[1] );
//normal double,
double somedouble = args[2]->ToNumber()->Value();
//booleans
bool somebool = args[3]->ToBoolean()->BooleanValue();
//and integers.
int someint = args[4]->ToInt32()->Int32Value();
//And one last thing, giving javascript meaningful return values.
//This should be more than enough to let you figure out how simple
//v8 makes things for you on the c++ side.
return handle_scope.Close(v8::Number::New(somedouble));
return handle_scope.Close(v8::Int32::New(someint));
return handle_scope.Close(v8::Boolean::New(somebool));
Out.
To celebrate the months wasted trying to find a way to make gameswf work for me, i am going to post the test build of the game here. There is not a lot to the UI yet, just a login screen and a "login complete" screen. After that, there is the escape key to exit.
For this test, the username is devcore , and so is the password. Iv attached some images below for post sake.
The tech so far
Currently im using v8 javascript engine for scripting,
PhoenixCore for rendering Link
And awesomium for the UI stuff Link
The rest of the story
Is still to come. I will post later today sometime maybe, the ideas behind the networking code on the client tool development side,
and i hope that there will be some discussion behind that. So if you can/want to please check back in a while for the networking part.
Candy
[caption id="attachment_110" align="aligncenter" width="431" caption="FLCore"]
[/caption]
[caption id="attachment_110" align="aligncenter" width="450" caption="FLCore"]
[/caption]
Notes :
Requires VC (vs2008) runtime libraries. Google these, if you dont have them. If you cant run the exe, open the html instead for now.
The Download
Self Extractor (3.8 MB)
Link
|