How is Google’s v8 Javascript as an ingame Scripting Language

I’ve been messing around with it for a few days, and have got to a level where I know what I’m doing, so here’s what’s what.

Binding

I use binding to describe binding c functions to the scripting world. The binding is similar to basic Lua. You define proxy c functions, then you assign them as named globals in the scripting enviroment. Lua has a few helper scripts to ease in binding, which is great if you’re in a rush, but usually ends up in a mess of undebuggable bloat. I always preferred to just play it straight, albeit with a few macros. Here’s some example code, bear in mind that I’ve made a few wrapper classes, so this isn’t straight v8, anything with v8plus in the name is mine.

static v8::Persistent<v8::FunctionTemplate> World_ft;

V8_PLUS_LIBRARY_START( World )

	static v8PlusFunction( CreateEntity )
	{
		v8This( CWorld );
		V8_ARG_COUNT( 1 );
		V8_ARG_STRING( vStrName, 0 );

		IEntity* ent = self->CreateEntity( vStrName.c_str() );
		if (!ent)
		{
			return v8::Undefined();
		}

		return ent->GetScriptObject();
	}

	void Construct( v8TemplateHandle global_template )
	{
		v8::HandleScope hs;

		World_ft = v8::Persistent<v8::FunctionTemplate>::New( v8::FunctionTemplate::New() );
		World_ft->SetClassName( v8String( "World" ) );

		v8::Local<v8::ObjectTemplate> instance_t = World_ft->InstanceTemplate();
		instance_t->SetInternalFieldCount(1);
		instance_t->Set( "CreateEntity", v8::FunctionTemplate::New(CreateEntity) );
	}

V8_PLUS_LIBRARY_END( World )

namespace v8pWorld
{

	v8::Local<v8::Object> CreateObject( void )
	{
		v8::Local<v8::Object> objReturn = World_ft->GetFunction()->NewInstance();
		return objReturn;
	}

}

CreateEntity is a member entity, and Construct creates the template.

In v8 everything happens in context. A context is a world where all the variables and objects live. If you don’t have a context you can’t make real objects and variables.. but you can make object templates. Object templates can be used by any of the context’s to quickly create an object.

In the above code we created an object template for a world object. Later on, when a world class is created, it creates the script enviroment and throws itself out as a global called world, using the object template above.

m_v8World.Set( v8pWorld::CreateObject() ); // Make a new world object from the template
m_v8World.Get()->SetInternalField( 0, v8::External::New(this) ); // Set the internal pointer to this class
m_v8Plus->SetGlobal( "world", m_v8World.Get() ); // and set it as a global

Calling

Calling is pretty simple and straight forward..

v8::Handle<v8::Value> arg[1] = { v8::Number::New(1) };
v8::Handle<v8::Value> returnval = functionobject->Call( context->Global(), 1, arg );

And obviously gets even simpler once you’ve wrapped the shit out of it

v8LocalValue vObjectProtoType = v8p->CallFunction( "EntityFactory", "GetPrototype", v8String( GetClassName().c_str() ) );

You can store the functions as objects and call whenever you want.

Error Catching

You can catch errors by having a v8::TryCatch in scope.

v8::TryCatch try_catch;
v8::Handle<v8::Script> script = v8::Script::Compile( v8String( strValue.c_str() ), v8String( strFileName.c_str() ) );
if ( script.IsEmpty() )
{
	ReportException( try_catch );
	return false;
}

The try_catch variable can then give you line number, source code, even the column in the code where it all went wrong.

Syntax

It’s javascript. Big woop.

World = {}

World.Initialize = function( )
{
	Msg( "Initialize\n" );
	Msg( "World: " , world, "\n" );

	for (var i = 0; i < 10000; i ++ )
	{
		var ent = world.CreateEntity( "TestEntity" );
		ent.SetPos( Vector( 1, i * 2, 1 ) );
		ent.Spawn();
	}
}

World.Shutdown = function( )
{
	Msg( "ShutDown\n" );
}

World.OnPlayerJoin = function( player )
{
	Msg( "Player Join: ", player, "\n" );
}

World.OnPlayerLeave = function( player )
{
	Msg( "Player Leave: ", player, "\n" );
}

People say Lua syntax is fine. No it isn’t. If you’re basing that on GMod’s Lua implementation you’re totally wrong. I hacked the syntax in GMod to include things like c++ style comments, here’s Lua comments..

-- OK single line comments aren't so bad

--[[
 Oh what the fuck is this Lua you idiot, why are you trying to be different!?!?!
 THIS IS NOT BETTER OR SIMPLER THAN C STYLE COMMENTS
--]]

Speed

Although it’s probably the most important thing when selecting a scripting language, I’ve got to admit, it’s not the most important thing to me. As long as it runs at a reasonable speed I’m happy. And it does.

I think the important thing to bear in mind when scripting in a game engine is that you’re prototyping in script. A lot of the modules you make should be transferred back into the engine.. and if you’re scripting in a nice modular manner then that should be a piece of piss to do.

From what I’ve heard, v8 is faster than standard Lua. But is slower than Lua JIT. But these things almost always depend on the benchmark, and don’t always apply to your application. If your app doesn’t append a character to a string 50,000 times in a for loop, then that specific benchmark is probably useless to you.

Summary

I’m happy where it’s going. I’m happy with the Javascript .prototype stuff. I appreciate that v8 is in the very early stages of development, and I’m happy that it is being actively developed. If anything changes in the situation I’ll let ya’ll know.