VGUI HTML Screen: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Created tutorial)
 
m (→‎Getting Started: Unicodifying, replaced: [[Image: → [[File:)
 
(28 intermediate revisions by 6 users not shown)
Line 1: Line 1:
=HTMLView=
<div class="boilerplate metadata" id="cleanup" style="text-align: center; background: #000000; margin: .5em 10%; padding: .3em 1em; border: #9F9FFF 1px solid;">
This is a tutorial on adding a HTML screen that can be shown during gameplay, and have it's address changed by in-game commands.
A [[VGUI HTML Screen In Multiplayer|Multiplayer]] version of this code is now available!
</div>
 
<div class="boilerplate metadata" id="cleanup" style="text-align: center; background: #000000; margin: .5em 10%; padding: .3em 1em; border: #9F9FFF 1px solid;">
An [[VGUI HTML Screen In Orange Box|Orange Box]] version of this code is now available!
</div>
 
This is a tutorial on adding a HTML screen that can be shown during gameplay, and have its address changed by in-game commands.
I use it for adding backstory to my maps, perhaps it will be useful for others too.
I use it for adding backstory to my maps, perhaps it will be useful for others too.


'''Note:''' This modification creates a HTML control that has JavaScript '''disabled''' for security reasons.
'''Mod Note:''' This modification is for the '''Episode 1''' engine, and will '''not''' work on the [[Orange Box]].
 
'''HTML Note:''' This modification creates a HTML control that has JavaScript '''disabled''' for security reasons.
 
==Acknowledgements==
All credit for the initial creation of the panel goes to the wiki at [[VGUI2: Creating a panel]]!


=Requirements=
==Change Log==
===Tuesday, January 23, 2007===
*'''A critical update has been released!'''
*This '''critical''' update fixes the scrollbars which stopped working when the Monday update went in
 
===Monday, January 22, 2007===
*[[User:Daedalus|Daedalus]] has updated the code to allow you to trigger entities in your map
<pre>
If the given URL starts with 'entity://', it will trigger an entity action.
Example: 'entity://relay_open_door->trigger'
You may also add a URL to go to after the entity action has been fired by placing a ; at the end, and then your url. E.g.:
  'entity://relay_open_door->trigger;html/sample2.html'
  'entity://relay_close_door->trigger;:www.google.com'
</pre>
*The sample map has been updated to display an example of this entity interaction.
 
===Updating your code===
* You will need the modified [[VGUI_HTML_Screen/IHTMLView.h|IHTMLView.h]], [[VGUI_HTML_Screen/HTMLView.cpp|HTMLView.cpp]] and to follow the tutorial on adding the EntHTML object (below.)
 
==Requirements==
*Visual Studio .Net 2003/2005
*Visual Studio .Net 2003/2005
*Source SDK
*Source SDK


=Getting Started=
==Getting Started==
For this example, we'll be creating our own mod (you can later make changes to your own mod if you desire.)
For this example, we'll be creating our own mod (you can later make changes to your own mod if you desire.)
Please note that this '''will not work''' for unedited HL2/HL2:MP, CS:Source, etc. It requires changes to some core files.
Please note that this '''will not work''' for unedited HL2/HL2:MP, CS:Source, etc. It requires changes to some core files.


==Create your mod==
We hope to end up with something that can display this:
 
[[File:Vgui htmlview.jpeg]]
 
===Create your mod===
Before we begin, we need to ensure we have the latest Source SDK source files.
Before we begin, we need to ensure we have the latest Source SDK source files.
On the Source SDK screen, double click '''Refresh SDK Content'''. This ensures we don't have out of date source code.
On the Source SDK screen, double click '''Refresh SDK Content'''. This ensures we don't have out of date source code.
Line 21: Line 56:
For this example, we'll be using HL2 single player, so select ''Modify Half-Life 2 Single Player'' and click Next.
For this example, we'll be using HL2 single player, so select ''Modify Half-Life 2 Single Player'' and click Next.


I always like to put my mods in the SourceMods folder, but choose yourself where you'd like to put your mod, then enter a name for it, eg ''HTMLTest'' and click Next.
I always like to put my mods in the SourceMods folder, but choose yourself where you'd like to put your mod, then enter a name for it, e.g. ''HTMLTest'' and click Next.


Source will now copy all the files over and prepare your mod.
Source will now copy all the files over and prepare your mod.


==Double checking==
===Double checking===
Now we need to be sure that everything works before we start messing with the code. If you've done this all before, you may skip this step.
Now we need to be sure that everything works before we start messing with the code. If you've done this all before, you may skip this step.


Line 33: Line 68:
Try to open the 2005 version first, and if that isn't recognized, use the 2003 version.
Try to open the 2005 version first, and if that isn't recognized, use the 2003 version.


===Compiling===
====Compiling====
At the top of the screen inside Visual Studio.Net should be a 'Solution Configuration' option, which by default reads ''Debug HL2''. We want to change that to ''Release HL2'' before proceeding.
At the top of the screen inside Visual Studio.Net should be a 'Solution Configuration' option, which by default reads ''Debug HL2''. We want to change that to ''Release HL2'' before proceeding.


Next, click the Build menu and then click Build Solution and grab yourself a coffee.
Next, click the Build menu and then click Build Solution and grab yourself a coffee.


===Testing===
====Testing====
If all goes well, you should be able to run the 'run_mod.bat' file in your mod directory and have it load up HL2. You can't do much at this point except look around the menus.
If all goes well, you should be able to run the 'run_mod.bat' file in your mod directory and have it load up HL2. You can't do much at this point except look around the menus.


If something went wrong...Post in the discussion or email me and I'll see how I can help.
If something went wrong...Post in the discussion or email me and I'll see how I can help.


=Adding the HTMLView=
==Adding the HTMLView==
Now we get to the code changes.
Now we get to the code changes.


Line 50: Line 85:
Click the + next to ''client_hl2'' to expand it.
Click the + next to ''client_hl2'' to expand it.


==Adding the header file==
===Adding the header files===
We need to add our header file now. Just create one in the header folder of the project and paste my code in.
We need to add our header file now. Just create one in the header folder of the project and paste my code in.
Right click Header Files and click ''Add->Add New Item''.
Right click Header Files and click ''Add->Add New Item''.


===IHTMLView.h===
====IHTMLView.h====
<pre>
This should go into the <code>src\cl_dlls</code> folder.
//========= Copyright © 2006, Julian 'Daedalus' Thatcher. =====================//
//
// Purpose: Header file for HTMLView window
//
//
// $NoKeywords: $
//=============================================================================//


// IHTMLView.h
'''[[VGUI_HTML_Screen/IHTMLView.h|View source code]]'''
class IHTMLView
{
public:
virtual void Create( vgui::VPANEL parent ) = 0;
virtual void Destroy( void ) = 0;
virtual void Activate( void ) = 0;
virtual void UpdateHTML ( void ) = 0;
};


extern IHTMLView* htmlview;
That wasn't too hard now, was it?


#define CenterThisPanelOnScreen()\
====EntHTML.h====
    int x,w,h;\
Same as above. Add a file named EntHTML.h to the header folder and paste the code in.
    GetBounds(x,x,w,h);\
    SetPos((ScreenWidth()-w)/2,(ScreenHeight()-h)/2)


#define CenterPanelOnScreen(panel)\
This should go into the <code>src\public\vgui_controls</code> folder.
    int x,w,h;\
    panel->GetBounds(x,x,w,h);\
    panel->SetPos((panel->ScreenWidth()-w)/2,(panel->ScreenHeight()-h)/2)
</pre>


That wasn't too hard now, was it?
'''[[VGUI_HTML_Screen/EntHTML.h|View source code]]'''


==Adding the source file==
===Adding the source file===
Now we add the source code for our HTML View.
Now we add the source code for our HTML View.


===HTMLView.cpp===
====HTMLView.cpp====
<pre>
Place this file into the ''Source files'' folder of the project.
//========= Copyright © 2006, Julian 'Daedalus' Thatcher. =====================//
//
// Purpose: HTMLView implementation
//
// Ingame Usage Commands:
//  cl_htmltarget path_to_file Sets the URL to view
//  ToggleHTMLView Shows or hides the HTML view
//
// If the given url does not begin with 'http://', it is considered relative
// to the mod directory.
//
//
// $Created: Tuesday, 26 December 2006
// $Author:  Julian 'Daedalus' Thatcher (daedalus.raistlin@gmail.com)
// $NoKeywords: $
//=============================================================================//
 
//The following include files are necessary to allow your MyPanel.cpp to compile.
#include "cbase.h"
#include "IHTMLView.h"
 
using namespace vgui;
 
#include "iclientmode.h"
#include <vgui/IVGui.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/Frame.h>
#include <vgui_controls/HTML.h>
#include <vgui_controls/TextEntry.h>
 
static void onTargetUpdate (ConVar *var, char const *pOldString);
 
ConVar cl_showhtmlview("cl_showhtmlview", "0", FCVAR_CLIENTDLL, "Sets the state of HTMLView <state>");
ConVar cl_htmltarget("cl_htmltarget", "", FCVAR_CLIENTDLL,
"Sets the HTML address to <state>. ", onTargetUpdate);
 
//CHTMLView_Panel class: Tutorial example class
class CHTMLView_Panel : public vgui::Frame
{
DECLARE_CLASS_SIMPLE(CHTMLView_Panel, vgui::Frame);
//CHTMLView_Panel : This Class / vgui::Frame : BaseClass
 
CHTMLView_Panel(vgui::VPANEL parent); // Constructor
~CHTMLView_Panel(){}; // Destructor
 
protected:
//VGUI overrides:
virtual void OnTick();
virtual void OnCommand(const char* pcCommand);
 
private:
//Other used VGUI control Elements:
vgui::Button *m_exit;


public:
The file should be placed in the <code>src\cl_dlls</code> folder.
vgui::HTML  *m_HTML;
};


// Constuctor: Initializes the Panel
'''[[VGUI_HTML_Screen/HTMLView.cpp|View source code]]'''
CHTMLView_Panel::CHTMLView_Panel(vgui::VPANEL parent)
: BaseClass(NULL, "HTMLView")
{
SetParent( parent );


SetKeyBoardInputEnabled( true );
===Update your vgui_controls.lib===
SetMouseInputEnabled( true );
SetProportional( true );
SetTitleBarVisible( true );
SetMinimizeButtonVisible( false );
SetMaximizeButtonVisible( false );
SetCloseButtonVisible( true );
SetSizeable( false );
SetMoveable( true );
SetVisible( true );


m_HTML = new vgui::HTML(this, "MyHTMLPage");
Now we need to update our vgui_controls.lib file.


SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
Open up your <code>Everything_SDK-200x</code> solution file.


LoadControlSettings("resource/UI/HTMLView.res");
We need to create a new HTML control.


vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
====Header file====
Copy the [[VGUI_HTML_Screen/EntHTML.h|EntHTML.h]] file to your <code>src\public</code> folder.
DevMsg("HTMLView has been constructed\n");


CenterThisPanelOnScreen();
====Source file====
Copy the [[VGUI_HTML_Screen/EntHTML.cpp|EntHTML.cpp]] file to your <code>src\vgui2\controls</code> folder, and add it to your ''vgui_controls'' project:
* Open the ''vgui_controls'' project
* Right click '''Source Files''' and click
:* Add -> Existing Item (''if you have already placed the EntHTML.cpp file in your src\vgui2\controls folder'')
:* Add -> New Item (''if you have not yet placed EntHTML.cpp into your src\vgui2\controls folder'')
::* Remember to save your file to your src\vgui2\controls folder!
* Right click the ''vgui_controls'' project and select '''Build Solution'''
* After it all compiles successfully, return to your '''Game_HL2-200x''' project for the rest of this tutorial.


}
===Other required code modifications===
 
//Class: CHTMLView_PanelInterface Class. Used for construction.
class CHTMLView_PanelInterface : public IHTMLView
{
private:
CHTMLView_Panel *MyPanel;
public:
CHTMLView_PanelInterface()
{
MyPanel = NULL;
}
void Create(vgui::VPANEL parent)
{
MyPanel = new CHTMLView_Panel(parent);
}
void Destroy()
{
if (MyPanel)
{
MyPanel->SetParent( (vgui::Panel *)NULL);
delete MyPanel;
}
}
void Activate( void )
{
if ( MyPanel )
{
MyPanel->Activate();
}
}
 
// Update HTML address
void UpdateHTML ( void )
{
char *target;
char temp[1024];
if ( MyPanel )
{
// Get value of 'cl_htmltarget'
target = (char *) cl_htmltarget.GetString();
if(strlen(target) > 0)
{
// Search for http:// prefix
if( !(
target[0] == 'h' &&
target[1] == 't' &&
target[2] == 't' &&
target[3] == 'p' &&
target[4] == ':' &&
target[5] == '/' &&
target[6] == '/' )
)
{
// Start is not 'http://', append target to game directory
strcpy(temp, engine->GetGameDirectory());
strcat(temp, "/");
strcat(temp, target);
MyPanel->m_HTML->OpenURL(temp, true);
} else {
// Absolute (http://) path given
MyPanel->m_HTML->OpenURL(cl_htmltarget.GetString(), true);
}
}
}
}
};
 
void CHTMLView_Panel::OnTick()
{
BaseClass::OnTick();
SetVisible(cl_showhtmlview.GetBool()); //CL_SHOWMYPANEL / 1 BY DEFAULT
}
 
//
// Handle commands from VGUI events.
// By default, only the 'exit' button has a command, and that
// command is 'turnoff'
void CHTMLView_Panel::OnCommand(const char* pcCommand)
{
if(!Q_stricmp(pcCommand, "turnoff"))
cl_showhtmlview.SetValue(0);
}
 
static void onTargetUpdate (ConVar *var, char const *pOldString)
{
htmlview->UpdateHTML();
}
 
static CHTMLView_PanelInterface g_MyPanel;
 
// The following are exported to the game system
IHTMLView* htmlview = (IHTMLView*)&g_MyPanel;
 
CON_COMMAND(ToggleHTMLView, "Toggles HTMLView on or off")
{
cl_showhtmlview.SetValue(!cl_showhtmlview.GetBool());
htmlview->Activate();
};
 
CON_COMMAND(UpdateHTMLView, "Updates HTMLView address")
{
DevMsg("Updating myPanel location");
htmlview->UpdateHTML();
}
 
// This was used for debugging
// Displays current mod directory
CON_COMMAND(WhereAmI, "Displays current path")
{
const char *pGameDir = engine->GetGameDirectory();
DevMsg(pGameDir);
}
</pre>
 
==Other required code modifications==
There are changes that we need to make to one of the core game files.
There are changes that we need to make to one of the core game files.
Don't worry, we don't change much.
Don't worry, we don't change much.


===vgui_int.cpp===
====vgui_int.cpp====
Find this file in the Source Files tree somewhere near the bottom and open it up.
Find this file in the Source Files tree somewhere near the bottom and open it up.


At the top of the file are a bunch of ''#include'' statements.
At the top of the file are a bunch of ''#include'' statements.
Under the last one (but before the line ''using namespace vgui''), add this:
Under the last one (but before the line ''using namespace vgui''), add this:
<pre>
 
#include "IHTMLView.h"
#include "IHTMLView.h"
</pre>
 
This lets the game access our HTMLView.
This lets the game access our HTMLView.


Next, find the line ''void VGui_CreateGlobalPanels( void )'', somewhere around line '''154'''.
Next, find the line ''void VGui_CreateGlobalPanels( void )'', somewhere around line '''154'''.
There should be two statements beginning with ''VPANEL''. Directly underneath these, add:
There should be two statements beginning with ''VPANEL''. Directly underneath these, add:
<pre>
 
VPANEL gameParent   = enginevgui->GetPanel( PANEL_INGAMESCREENS );
VPANEL gameParent   = enginevgui->GetPanel( PANEL_INGAMESCREENS );
htmlview->Create(gameParent);
htmlview->Create(gameParent);
</pre>


Next, find the line ''void VGui_Shutdown()'' which should be the function directory below the one you just edited.
Next, find the line ''void VGui_Shutdown()'' which should be the function directory below the one you just edited.
Somewhere in this function, after the '''{''' and before the '''}''' you need to add:
Somewhere in this function, after the '''{''' and before the '''}''' you need to add:
<pre>
 
htmlview->Destroy();
htmlview->Destroy();
</pre>


Good news! We're almost done!
Good news! We're almost done!


==The User Interface==
===The User Interface===
Now we need to add the UI file that the game loads for our HTML view.
Now we need to add the UI file that the game loads for our HTML view.


===HTMLView.res===
====HTMLView.res====
Save this file to ''yourmod''\resource\ui\HTMLView.res.
Save this file to ''yourmod''\resource\ui\HTMLView.res.
<pre>
"resource/UI/HTMLView.res"
{
"HTMLView"
{
"ControlName" "CHTMLView_Panel"
"fieldName" "HTMLView"
"xpos" "64"
"ypos" "48"
"wide" "512"
"tall" "384"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"settitlebarvisible" "1"
"title" "Document"
}
"frame_topGrip"
{
"ControlName" "Panel"
"fieldName" "frame_topGrip"
"xpos" "6"
"ypos" "0"
"wide" "499"
"tall" "4"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_bottomGrip"
{
"ControlName" "Panel"
"fieldName" "frame_bottomGrip"
"xpos" "6"
"ypos" "380"
"wide" "491"
"tall" "4"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_leftGrip"
{
"ControlName" "Panel"
"fieldName" "frame_leftGrip"
"xpos" "0"
"ypos" "6"
"wide" "4"
"tall" "371"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_rightGrip"
{
"ControlName" "Panel"
"fieldName" "frame_rightGrip"
"xpos" "508"
"ypos" "6"
"wide" "4"
"tall" "363"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_tlGrip"
{
"ControlName" "Panel"
"fieldName" "frame_tlGrip"
"xpos" "0"
"ypos" "0"
"wide" "6"
"tall" "6"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_trGrip"
{
"ControlName" "Panel"
"fieldName" "frame_trGrip"
"xpos" "505"
"ypos" "0"
"wide" "6"
"tall" "6"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_blGrip"
{
"ControlName" "Panel"
"fieldName" "frame_blGrip"
"xpos" "0"
"ypos" "377"
"wide" "6"
"tall" "6"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_brGrip"
{
"ControlName" "Panel"
"fieldName" "frame_brGrip"
"xpos" "497"
"ypos" "369"
"wide" "14"
"tall" "14"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_caption"
{
"ControlName" "Panel"
"fieldName" "frame_caption"
"xpos" "60"
"ypos" "32"
"wide" "504"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_minimize"
{
"ControlName" "Button"
"fieldName" "frame_minimize"
"xpos" "0"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "0"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Default" "0"
}
"frame_maximize"
{
"ControlName" "Button"
"fieldName" "frame_maximize"
"xpos" "0"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "1"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Default" "0"
}
"frame_mintosystray"
{
"ControlName" "Button"
"fieldName" "frame_mintosystray"
"xpos" "0"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "o"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Command" "MinimizeToSysTray"
"Default" "0"
}
"frame_close"
{
"ControlName" "Button"
"fieldName" "frame_close"
"xpos" "0"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "r"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Default" "0"
}
"frame_menu"
{
"ControlName" "FrameSystemButton"
"fieldName" "frame_menu"
"xpos" "5"
"ypos" "6"
"wide" "14"
"tall" "14"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"textAlignment" "west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Default" "0"
}
"MyHTMLPage"
{
"ControlName" "HTML"
"fieldName" "MyHTMLPage"
"xpos" "8"
"ypos" "25"
"wide" "494"
"tall" "320"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"ExitButton"
{
"ControlName" "Button"
"fieldName" "ExitButton"
"xpos" "460"
"ypos" "356"
"wide" "40"
"tall" "16"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"labelText" "Exit"
"textAlignment" "west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"Command" "turnoff"
"Default" "1"
}
"BuildModeDialog"
{
"ControlName" "BuildModeDialog"
"fieldName" "BuildModeDialog"
"xpos" "1"
"ypos" "124"
"wide" "240"
"tall" "336"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"settitlebarvisible" "1"
"title" "#Frame_Untitled"
}
}
</pre>


==Optional step: Add HTMLView to main menu==
'''[[VGUI_HTML_Screen/HTMLView.res|View source file]]'''
 
===Optional step: Add HTMLView to main menu===
This step isn't required, but may be helpful in quickly checking if things worked.
This step isn't required, but may be helpful in quickly checking if things worked.
Open up your ''yourmod''\resource\GameMenu.res file, and add the following before the final '''}'''.
Open up your ''yourmod''\resource\GameMenu.res file, and add the following before the final '''}'''.
<pre>
 
         "5"
         "5"
{
{
"label" "HTMLView"
"label" "HTMLView"
"command" "engine ToggleHTMLView"
"command" "engine ToggleHTMLView"
"notmulti" "1"
"notmulti" "1"
}
}
</pre>


=Finishing up=
==Finishing up==
Ok, so all the code has been added, the resource file created, and the other source edited.
Ok, so all the code has been added, the resource file created, and the other source edited.
Hit Build Solution again and wait for it to compile.
Hit Build Solution again and wait for it to compile.
If there are any problems, please post in the Discussion section of this page and I'll try to help out.
If there are any problems, please post in the Discussion section of this page and I'll try to help out.


==In-Game operation==
===In-Game operation===
So now, load up your mod.
So now, load up your mod.
If you edited your GameMenu.res file, there should be a new menu item at the end simply titled 'HTMLView'. A big screen showing a black box and an 'Exit' button should appear when you click this.
If you edited your GameMenu.res file, there should be a new menu item at the end simply titled 'HTMLView'. A big screen showing a black box and an 'Exit' button should appear when you click this.
Line 654: Line 192:


So far, all you've seen is a black box and a button.
So far, all you've seen is a black box and a button.
In the console, type:
In the console, type one of the following:
 
cl_htmltarget :www.google.com
cl_htmltarget somefile/inyourmod/directory/example.txt
cl_htmltarget scripts/credits.txt
 
Note that the ''':''' tells the HTMLView that it is an external URL (since you can't use speech marks in Hammer.)
 
''As of January 22, 2007, the following may also be used '''inside''' of html files (not in the console.)''
<pre>
<pre>
cl_htmltarget "http://www.google.com"
  <a href="entity://entity_name->entity_action;new/page/to_go_to.html">Activate entity and move to new page</a>
  <a href="entity://relay_open_door->trigger">Open door</a>
</pre>
</pre>
''Note:'' The entity interaction can only be done inside a html file, due to the limitations / complexities of the console.
And then either press the menu item or type '''ToggleHTMLView''' again and you should see google :)
And then either press the menu item or type '''ToggleHTMLView''' again and you should see google :)


=Sample Level=
 
Note that you can load up text or HTML files located in your mod directory.
In my mod, I have created a ''HTML'' folder, and then created subfolders which contain backstory relevant to each map.
I have a [[Point_servercommand]] entity that I tell to run ''cl_htmltarget html/ship/intro.txt'' and another command that runs ''ToggleHTMLView'' to display the HTML View.
 
For a detailed example, check the example map.
 
==Sample Level==
Want an example of how to implement this into your levels?
Want an example of how to implement this into your levels?
'''Coming soon!'''
 
Download the [http://www.users.on.net/~daedalusraist/vgui_htmlview.zip example Hammer file and compiled .bsp] file.
 
===How does it work?===
The example level consists of the following '''main''' entities:
* [[Point_servercommand]] - ''Used to send commands to the server''
* [[Trigger_proximity]] - ''Used to turn on/off the lightup of objects''
* [[Func_button]] - ''Used to trigger the relays for displaying a page''
* [[Logic_relay]] - ''Used to simplify sending commands to the [[Point_servercommand]] entity''
 
The relays send commands to the [[Point_servercommand]] entity (which I call ''cmd'') to update the HTML target (''cl_htmltarget wherever.com'') and to display the HTML view (''ToggleHTMLView'').
 
I typically create a '''base''' scenario, and then copy and paste that around the level (with unique names on.)
 
===Base Scenario===
What follows is a step by step guide on my '''base''' scenario for using my screen.
 
* Place a new [[Point_servercommand]] entity in the world and name it '''cmd'''. This should be away from the rest of the entities you will place in this tutorial.
* Place a [[Prop_static]] entity in the world and select an interesting model (eg, the clipboard: ''models/props_lab/clipboard.mdl'')
* Place a box (using the Invisible texture) over the area you want the 'use' area to be (typically, cover the front of the object). Tie this to entity [[Func_button]] and add the following output:
<pre>
My output named: OnTrigger
Target entities named: relay_showhtml
Via this input: Trigger
</pre>
* Place a [[Logic_relay]] next to this, and name it '''relay_showhtml'''. On the ''Outputs'' tab, add the following outputs:
<pre>
My output named: OnTrigger
Target entities named: cmd
Via this input: Command
With parameter override of: cl_htmltarget :www.google.com
</pre>
<pre>
My output named: OnTrigger
Target entities named: relay_show_view
Via this input: Trigger
</pre>
* Place a [[Logic_relay]] near your [[Point_servercommand]] entity and name it ''relay_show_view''. Add the following output:
<pre>
My output named: OnTrigger
Target entities named: cmd
Via this input: Command
With parameter override of: ToggleHTMLView
</pre>
 
At this point in time, you can go up and 'use' the object.
However, the user would probably not know this. My solution to this is to make the object 'glow' when you approach it.
This requires a [[Trigger_proximity]] and a [[Light_spot]] entity.
* Create a [[Light_spot]] entity, and face it towards your object. Name it '''spot_objectglow''' and set it to 'Initially dark'. I also set the <code>Inner (bright) angle</code> to 10, and the <code>Outer (fading) angle</code> to 15, for small items and 13 and 18 respectively for larger items. Experiment a little.
* Create a box that spans the area that player walks into to make the object glow, and texture it with the Trigger texture. Tie this to entity [[Trigger_proximity]] and add the following outputs:
<pre>
My output named: OnStartTouch
Target entities named: spot_objectglow
Via this input: TurnOn
</pre>
<pre>
My output named: OnEndTouch
Target entities named: spot_objectglow
Via this input: TurnOff
</pre>
 
And there you go!
 
Once you have these, I typically select all the objects we just inserted (except the [[Point_servercommand]] and [[Logic_relay]] named ''relay_show_view'') and hit Copy, then Paste Special and ensure ''Make pasted entity names unique'' is ticked.
Then it's simply a matter of changing the [[Logic_relay]]'s output of <code>cl_htmltarget :www.google.com</code> to something else.
 
Check the example map for 3 examples!
 
 
[[Category:Programming]][[Category:Tutorials]][[Category:VGUI|H]]

Latest revision as of 00:15, 7 January 2024

This is a tutorial on adding a HTML screen that can be shown during gameplay, and have its address changed by in-game commands. I use it for adding backstory to my maps, perhaps it will be useful for others too.

Mod Note: This modification is for the Episode 1 engine, and will not work on the Orange Box.

HTML Note: This modification creates a HTML control that has JavaScript disabled for security reasons.

Acknowledgements

All credit for the initial creation of the panel goes to the wiki at VGUI2: Creating a panel!

Change Log

Tuesday, January 23, 2007

  • A critical update has been released!
  • This critical update fixes the scrollbars which stopped working when the Monday update went in

Monday, January 22, 2007

  • Daedalus has updated the code to allow you to trigger entities in your map
If the given URL starts with 'entity://', it will trigger an entity action.
 Example: 'entity://relay_open_door->trigger'
 You may also add a URL to go to after the entity action has been fired by placing a ; at the end, and then your url. E.g.:
   'entity://relay_open_door->trigger;html/sample2.html'
   'entity://relay_close_door->trigger;:www.google.com'
  • The sample map has been updated to display an example of this entity interaction.

Updating your code

  • You will need the modified IHTMLView.h, HTMLView.cpp and to follow the tutorial on adding the EntHTML object (below.)

Requirements

  • Visual Studio .Net 2003/2005
  • Source SDK

Getting Started

For this example, we'll be creating our own mod (you can later make changes to your own mod if you desire.) Please note that this will not work for unedited HL2/HL2:MP, CS:Source, etc. It requires changes to some core files.

We hope to end up with something that can display this:

Vgui htmlview.jpeg

Create your mod

Before we begin, we need to ensure we have the latest Source SDK source files. On the Source SDK screen, double click Refresh SDK Content. This ensures we don't have out of date source code.

Now double click click Create A Mod.

For this example, we'll be using HL2 single player, so select Modify Half-Life 2 Single Player and click Next.

I always like to put my mods in the SourceMods folder, but choose yourself where you'd like to put your mod, then enter a name for it, e.g. HTMLTest and click Next.

Source will now copy all the files over and prepare your mod.

Double checking

Now we need to be sure that everything works before we start messing with the code. If you've done this all before, you may skip this step.

Now, go to your mod folder, then go into your src folder. There are a few different Visual Studio .Net solution files. We want the one named Game_HL2. However, there are two different versions. Try to open the 2005 version first, and if that isn't recognized, use the 2003 version.

Compiling

At the top of the screen inside Visual Studio.Net should be a 'Solution Configuration' option, which by default reads Debug HL2. We want to change that to Release HL2 before proceeding.

Next, click the Build menu and then click Build Solution and grab yourself a coffee.

Testing

If all goes well, you should be able to run the 'run_mod.bat' file in your mod directory and have it load up HL2. You can't do much at this point except look around the menus.

If something went wrong...Post in the discussion or email me and I'll see how I can help.

Adding the HTMLView

Now we get to the code changes.

In Visual Studio, there should be a file tree (it may just show client_hl2 and server_hl2 currently.)

Click the + next to client_hl2 to expand it.

Adding the header files

We need to add our header file now. Just create one in the header folder of the project and paste my code in. Right click Header Files and click Add->Add New Item.

IHTMLView.h

This should go into the src\cl_dlls folder.

View source code

That wasn't too hard now, was it?

EntHTML.h

Same as above. Add a file named EntHTML.h to the header folder and paste the code in.

This should go into the src\public\vgui_controls folder.

View source code

Adding the source file

Now we add the source code for our HTML View.

HTMLView.cpp

Place this file into the Source files folder of the project.

The file should be placed in the src\cl_dlls folder.

View source code

Update your vgui_controls.lib

Now we need to update our vgui_controls.lib file.

Open up your Everything_SDK-200x solution file.

We need to create a new HTML control.

Header file

Copy the EntHTML.h file to your src\public folder.

Source file

Copy the EntHTML.cpp file to your src\vgui2\controls folder, and add it to your vgui_controls project:

  • Open the vgui_controls project
  • Right click Source Files and click
  • Add -> Existing Item (if you have already placed the EntHTML.cpp file in your src\vgui2\controls folder)
  • Add -> New Item (if you have not yet placed EntHTML.cpp into your src\vgui2\controls folder)
  • Remember to save your file to your src\vgui2\controls folder!
  • Right click the vgui_controls project and select Build Solution
  • After it all compiles successfully, return to your Game_HL2-200x project for the rest of this tutorial.

Other required code modifications

There are changes that we need to make to one of the core game files. Don't worry, we don't change much.

vgui_int.cpp

Find this file in the Source Files tree somewhere near the bottom and open it up.

At the top of the file are a bunch of #include statements. Under the last one (but before the line using namespace vgui), add this:

#include "IHTMLView.h"

This lets the game access our HTMLView.

Next, find the line void VGui_CreateGlobalPanels( void ), somewhere around line 154. There should be two statements beginning with VPANEL. Directly underneath these, add:

VPANEL gameParent	  = enginevgui->GetPanel( PANEL_INGAMESCREENS );
htmlview->Create(gameParent);

Next, find the line void VGui_Shutdown() which should be the function directory below the one you just edited. Somewhere in this function, after the { and before the } you need to add:

htmlview->Destroy();

Good news! We're almost done!

The User Interface

Now we need to add the UI file that the game loads for our HTML view.

HTMLView.res

Save this file to yourmod\resource\ui\HTMLView.res.

View source file

Optional step: Add HTMLView to main menu

This step isn't required, but may be helpful in quickly checking if things worked. Open up your yourmod\resource\GameMenu.res file, and add the following before the final }.

       "5"
	{
		"label" "HTMLView"
		"command" "engine ToggleHTMLView"
		"notmulti" "1"
	}

Finishing up

Ok, so all the code has been added, the resource file created, and the other source edited. Hit Build Solution again and wait for it to compile. If there are any problems, please post in the Discussion section of this page and I'll try to help out.

In-Game operation

So now, load up your mod. If you edited your GameMenu.res file, there should be a new menu item at the end simply titled 'HTMLView'. A big screen showing a black box and an 'Exit' button should appear when you click this.

Alternatively, use the console command ToggleHTMLView.

So far, all you've seen is a black box and a button. In the console, type one of the following:

cl_htmltarget :www.google.com
cl_htmltarget somefile/inyourmod/directory/example.txt
cl_htmltarget scripts/credits.txt

Note that the : tells the HTMLView that it is an external URL (since you can't use speech marks in Hammer.)

As of January 22, 2007, the following may also be used inside of html files (not in the console.)

  <a href="entity://entity_name->entity_action;new/page/to_go_to.html">Activate entity and move to new page</a>
  <a href="entity://relay_open_door->trigger">Open door</a>

Note: The entity interaction can only be done inside a html file, due to the limitations / complexities of the console.

And then either press the menu item or type ToggleHTMLView again and you should see google :)


Note that you can load up text or HTML files located in your mod directory. In my mod, I have created a HTML folder, and then created subfolders which contain backstory relevant to each map. I have a Point_servercommand entity that I tell to run cl_htmltarget html/ship/intro.txt and another command that runs ToggleHTMLView to display the HTML View.

For a detailed example, check the example map.

Sample Level

Want an example of how to implement this into your levels?

Download the example Hammer file and compiled .bsp file.

How does it work?

The example level consists of the following main entities:

The relays send commands to the Point_servercommand entity (which I call cmd) to update the HTML target (cl_htmltarget wherever.com) and to display the HTML view (ToggleHTMLView).

I typically create a base scenario, and then copy and paste that around the level (with unique names on.)

Base Scenario

What follows is a step by step guide on my base scenario for using my screen.

  • Place a new Point_servercommand entity in the world and name it cmd. This should be away from the rest of the entities you will place in this tutorial.
  • Place a Prop_static entity in the world and select an interesting model (eg, the clipboard: models/props_lab/clipboard.mdl)
  • Place a box (using the Invisible texture) over the area you want the 'use' area to be (typically, cover the front of the object). Tie this to entity Func_button and add the following output:
My output named: OnTrigger
Target entities named: relay_showhtml
Via this input: Trigger
  • Place a Logic_relay next to this, and name it relay_showhtml. On the Outputs tab, add the following outputs:
My output named: OnTrigger
Target entities named: cmd
Via this input: Command
With parameter override of: cl_htmltarget :www.google.com
My output named: OnTrigger
Target entities named: relay_show_view
Via this input: Trigger
My output named: OnTrigger
Target entities named: cmd
Via this input: Command
With parameter override of: ToggleHTMLView

At this point in time, you can go up and 'use' the object. However, the user would probably not know this. My solution to this is to make the object 'glow' when you approach it. This requires a Trigger_proximity and a Light_spot entity.

  • Create a Light_spot entity, and face it towards your object. Name it spot_objectglow and set it to 'Initially dark'. I also set the Inner (bright) angle to 10, and the Outer (fading) angle to 15, for small items and 13 and 18 respectively for larger items. Experiment a little.
  • Create a box that spans the area that player walks into to make the object glow, and texture it with the Trigger texture. Tie this to entity Trigger_proximity and add the following outputs:
My output named: OnStartTouch
Target entities named: spot_objectglow
Via this input: TurnOn
My output named: OnEndTouch
Target entities named: spot_objectglow
Via this input: TurnOff

And there you go!

Once you have these, I typically select all the objects we just inserted (except the Point_servercommand and Logic_relay named relay_show_view) and hit Copy, then Paste Special and ensure Make pasted entity names unique is ticked. Then it's simply a matter of changing the Logic_relay's output of cl_htmltarget :www.google.com to something else.

Check the example map for 3 examples!