Implementing Awesomium

From Valve Developer Community
Jump to: navigation, search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024
Warning.pngWarning:Awesomium's API has been abandoned since ~2016 by its creators. It is no longer available to download directly and is not recommended for new projects, as Awesomium does not fully support newer HTML5 standards, does not support TLS 1.2+ and contains unfixed bugs with security flaws.
Note.pngNote:If you're using Source 2013, the vgui::HTML WebKit control can be used as a replacement for Awesomium. This tutorial applies to Source 2007, where the built-in browser control used an old version of the Internet Explorer engine. (The code below will work in the 2013 version: see the Discussion page)

Awesomium is a free (to non-commercial users) SDK that allows you to embed WebKit in your project. It offers a .NET and C++ API, and can be easily added to the Source Engine.

Source 2007 does include an HTML control, but it uses the Internet Explorer rendering engine, and doesn't support JavaScript. Using Awesomium allows you to take advantage of CSS3, HTML Canvas, and WebGL. It also allows you to bridge the gap between the browser and the game world, as you can call JavaScript functions inside the game, and can call game methods from JavaScript.

HTML is a mature presentation layer, so it makes sense to use it for in-game UI that would otherwise be difficult to construct using the VGUI library alone. Counter-Strike: Global Offensive's UI previously used an implementation of Adobe Flash called Scaleform for instance.

Pre-requisites

Awesomium Linked & Included

First, you'll need to install the Awesomium SDK, and link it up in your Client project. There's a really easy to follow tutorial on the site on how to do that, so I won't cover that again: Setting up Awesomium in your C++ project

The VAwesomium Code

Second, you'll need the business end of the device- VAwesomium. VAwesomium wraps up the Awesomium functionality into an extensible VGUI Panel that you can plonk into your mod and go. I'm currently using it in my mod Estranged, where we're working on in-engine puzzles and backstory elements composed in HTML.

To use it, simply download or check out the source code, and add it to your Client project: https://github.com/alanedwardes/VAwesomium

Basic Usage

Here's an example of it being used in a vgui::Panel element:

Header:

class MyPanel : public vgui::Panel
{
public:
    MyPanel(vgui::Panel *parent, const char *panelName);
    [...]
private:
    VAwesomium *m_Browser;
};

CPP:

MyPanel::MyPanel(vgui::Panel *parent, const char *panelName) : vgui::Panel(parent, panelName)
{
    m_Browser = new VAwesomium(this, "VAwesomium");
    m_Browser->SetSize(GetWidth(), GetTall());
    m_Browser->OpenURL("https://developer.valvesoftware.com/wiki/Main_Page");
}

Advanced Usage

If you want to add JavaScript functions that your page can call to interface with the engine, you'll need to inherit from the VAwesomium class.

Header:

#include "VAwesomium.h"

#define EXIT_COMMAND "ExitMyVAwesomium"

#include <vgui/VGUI.h>
#include <vgui_controls/Panel.h>

class MyVAwesomium : public VAwesomium
{
    DECLARE_CLASS_SIMPLE(MyVAwesomium, VAwesomium);
public:
    MyVAwesomium(vgui::Panel *parent, const char *panelName) : VAwesomium(parent, panelName){};

    virtual void OnDocumentReady(Awesomium::WebView* caller, const Awesomium::WebURL& url);

    virtual void OnMethodCall(Awesomium::WebView* caller, unsigned int remote_object_id, const Awesomium::WebString& method_name, const Awesomium::JSArray& args);
};

CPP:

using namespace Awesomium;

#ifdef PostMessage
#undef PostMessage
#endif

void MyVAwesomium::OnDocumentReady(WebView* caller, const WebURL& url)
{
    JSValue result = caller->CreateGlobalJavascriptObject(WSLit("MyObject"));

    JSObject &myObject = result.ToObject();
    myObject.SetCustomMethod(WSLit("ReturnToGame"), false);

    caller->ExecuteJavascript(WSLit("AwesomiumInitialized()"), WSLit(""));
}

void MyVAwesomium::OnMethodCall(Awesomium::WebView* caller, unsigned int remote_object_id, const Awesomium::WebString& method_name, const Awesomium::JSArray& args)
{
    if (method_name == WSLit("ReturnToGame"))
    {
        BaseClass::GetParent()->PostMessage(BaseClass::GetParent(), new KeyValues("command", "command", EXIT_COMMAND));
    }
}

With the Above, MyObject.ReturnToGame() will be available to your HTML page.

More JavaScript

The JavaScript interface is very powerful, you can execute JavaScript methods that return data from the page, and you can call methods in-browser that return data from the game. To find out more, see the JavaScript pages on the Awesomium wiki.

JavaScript Gotchas

The implementation isn't perfect, as with Awesomium you have to wait until the OnDocumentReady method has fired to add JavaScript objects to the page. That's why at the end of that method I execute the JavaScript method AwesomiumInitialized() - it allows me to notify my page that the JavaScript objects I just created in the C++ are now available on the page.

Contributing

My class is far from perfect, and is bound to be lacking in certain features or include bugs just waiting to be fixed. I put the project up on GitHub, so please feel free to contribute to the project, and if you're using it, make sure you update it now and again before you distribute it.

VAwesomium on GitHub: https://github.com/alanedwardes/VAwesomium