VGUI Screen Creation: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(rewrite based on existing information and some new information)
Line 1: Line 1:
[[Category:Programming]][[Category:Tutorials]][[Category:VGUI]]
[[Category:Programming]][[Category:Tutorials]][[Category:VGUI]]  


==Getting it to load==
==Adding a VGUI screen to a map==


===First Step===
'''Note:''' This section assumes a mod where VGUI screens have been fixed (see the [[#VGUI code modifications|code modifications section]] below) but otherwise left the same. VGUI screens do ''not'' work in HL2 or HL2:DM; they crash the game. (CS:S not tested.)
Create a .res file in your mod's <code>scripts\screens</code> folder. This example is called <code>vgui_test_screen.res</code>:


<pre>"screen_basic.res"
# Create a [[vgui_screen]] entity. This is a point entity.
{
# Set its '''Panel Name''' to the name of the screen that should be shown. (This is not the filename of the screen.) The available screens are listed in <code>vgui_screens.txt</code> (which can be [[GCFScape|extracted]] from <code>'''???'''.gcf</code> at <code>''steamdir''\SourceMods\''moddir''\scripts</code>). An example that comes with HL2 is <code>vgui_test_screen</code>.
"Background"
# Set '''Panel Width in World''' and '''Panel Height in World''' to match the size of the brush. 64 wide by 32 tall would be a reasonable starting size.
{
# Compile the map and test.
"ControlName" "MaterialImage"
"fieldName" "Background"
"xpos" "0"
"ypos" "0"
"zpos" "-2"
"wide" "480"
"tall" "240"
"material" "vgui/screens/vgui_overlay"
}
"OwnerReadout"
{
"ControlName" "Label"
"fieldName" "OwnerReadout"
"xpos" "10"
"ypos" "20"
"wide" "240"
"tall" "34"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"labelText" "No Owner"
"textAlignment" "center"
"dulltext" "0"
"paintBackground" "0"
}
"HealthReadout"
{
"ControlName" "Label"
"fieldName" "HealthReadout"
"xpos" "240"
"ypos" "20"
"wide" "240"
"tall" "34"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"labelText" "Health: 100%"
"textAlignment" "center"
"dulltext" "0"
"paintBackground" "0"
}
"DismantleButton"
{
"ControlName" "MaterialButton"
"fieldName" "Dismantle"
"xpos" "78"
"ypos" "160"
"wide" "324"
"tall" "48"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "2"
"labelText" "Dismantle"
"textAlignment" "center"
"dulltext" "0"
"brighttext" "0"
"Default" "0"
"command" "quit"
"paintborder" "0"
"enabledImage"
{
"material" "vgui/screens/vgui_button_enabled"
"color" "255 255 255 255"
}
"mouseOverImage"
{
"material" "vgui/screens/vgui_button_hover"
"color" "255 255 255 255"
}
"pressedImage"
{
"material" "vgui/screens/vgui_button_pushed"
"color" "255 255 255 255"
}
"disabledImage"
{
"material" "vgui/screens/vgui_button_disabled"
"color" "255 255 255 255"
}
}
}</pre>


===Second Step===
The position of the entity in the map marks the bottom-left corner of the panel. The panel's direction (the normal of its face) is set by the entity's angle (Yaw).
The materials used in the .res file can be found in <code>source material.gcf</code> using Nem's [[GCFScape]]. Extract the files in <code>hl2\materials\vgui\screens</code> to your mod's <code>materials\vgui\screens</code> folder.


===Third Step===
==Creating a VGUI screen==
In your mod's <code>scripts</code> folder create or open the text file <code>vgui_screens.txt</code> and add a new entry for the screen.


ex.
VGUI screen files have a ''.res'' extension and should be placed in <code>''steamdir''\SourceMods\''yourmod''\scripts\screens\</code>.


<pre>"VGUI_Screens"
# <code>vgui_test_screen.res</code> is a good starting point for creating a VGUI screen file; it can be extracted from <code>source engine.gcf</code> at path <code>hl2/scripts/screens/</code> using [[GCFScape]].
{
# The materials used in the ''.res'' file can be found in <code>source materials.gfc</code>. Extract the material files mentioned in the ''.res'' file to <code>''steamdir''\SourceMods\''moddir''\materials\vgui\screens</code>.
"vgui_test_screen"
# Add the screen to <code>''steamdir''\SourceMods\''moddir''\scripts\vgui_screens.txt</code>. Here is an example which describes screen <code>vgui_test_screen</code> at <code>scripts/screens/vgui_test_screen.res</code> and <code>teleport_countdown_screen</code>. Adjust it for your screen.
{
// This is our example screen
"type" "vgui_screen_panel"
"pixelswide" "480"
"pixelshigh" "240"
// This must be the file you created in step 1
"resfile" "scripts/screens/vgui_test_screen.res"
}
"teleport_countdown_screen"
{
"type" "teleport_countdown_screen"
"pixelswide" "480"
"pixelshigh" "240"
"resfile" "scripts/screens/teleport_countdown_screen.res"
}
}</pre>


===Fourth Step===
"VGUI_Screens"
Open Hammer create a small square map with a spawn, a light, and a vgui_screen.
{
    "vgui_test_screen"
    {
        // This is our example screen
        "type" "vgui_screen_panel"
        "pixelswide" 480
        "pixelshigh" 240
        // This must be the file you created in step 1
        "resfile" "scripts/screens/vgui_test_screen.res"
    }
}


Change the vgui_screen's properties like so:
==VGUI code modifications==
:Panel Name = vgui_test_screen
:Panel Width in World = 64
:Panel Height in World = 32


Height and Width can be changed to whatever you need. Those values define the actual size of the screen in the world.
There is a problem with VGUI screens receiving input. Unless it is fixed, the game may crash when the cursor points at the screen.


===Fifth Step===
<code>CInput::ExtraMouseSample</code> calls <code>g_pClientMode->CreateMove()</code> without initializing the button flags, thus the VGui screen is updated with bad button input.  Since <code>IN_VALIDVGUIINPUT</code> is only set from within <code>CInput::CreateMove</code>, the VGui screens only update when the button flags are valid.
Save your files, build your map, launch your mod, and whala! you have a vgui_screen in game.


==Getting Input to work==
There are two known fixes. They both involve code changes and therefore are only applicable to mods.
Here is the proper way of fixing [[vgui]] input:
===Modifications to in_buttons.h===
Where the other flags are defined add:
#define IN_VALIDVGUIINPUT (1 << 23) //bitflag for vgui fix


===Modifications to in_main.cpp===
=== Fix 1 ===
Inside the function <code>CInput::CreateMove(...)</code> add:
 
cmd->buttons |= IN_VALIDVGUIINPUT;
In '''in_buttons.h''', where the other flags are defined add:
    #define IN_VALIDVGUIINPUT     (1 << 23) //bitflag for vgui fix
 
next, in '''in_main.cpp''' inside method <code>CInput::CreateMove( ''...'' )</code>
add:
    cmd->buttons |= IN_VALIDVGUIINPUT;
right above:
right above:
g_pClientMode->CreateMove( input_sample_frametime, cmd );
    g_pClientMode->CreateMove( input_sample_frametime, cmd );
===Modifications to c_baseplayer.cpp===
 
====CreateMove====
next, in '''c_baseplayer.cpp''' inside method <code>C_BasePlayer::CreateMove( ''...'' )</code>
Inside the function <code>C_BasePlayer::CreateMove( ... )</code> add:
add:
if(pCmd->buttons & IN_VALIDVGUIINPUT)
    if(pCmd->buttons & IN_VALIDVGUIINPUT)
right above:
right above:
DetermineVguiInputMode( pCmd );
    DetermineVguiInputMode( pCmd );
So it only calls <code>DetermineVguiInputMode</code> if the buttons include our flag
''(So it only calls <code>DetermineVguiInputMode</code> if the buttons include our flag)''


====DetermineVguiInputMode====
and finally, inside method <code>C_BasePlayer::DetermineVguiInputMode( ''...'' )</code>
Inside the function <code>C_BasePlayer::DetermineVguiInputMode(...)</code>
change '''both''' instances of:
change '''''both''''' instances of:
    pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
to read:
to read:
pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT);
    pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT);
 
The reason we do this is because <code>CInput::ExtraMouseSample</code> calls <code>g_pClientMode->CreateMove()</code> without initializing the button flags, thus the VGui screen is updated with bad button input.  Since <code>IN_VALIDVGUIINPUTM</code> is only set from within <code>CInput::CreateMove</code>, the VGui screens only update when the button flags are valid.
 
== Alternative Fix ==


An alternative fix would be to add a new variable to '''CUserCmd''' such as bButtonFlagsValid that can be set to either '''true''' or '''false''' depending on the validity of the button flags.  This would allow the structure to internally store this information for its whole lifetime while freeing up that extra button bit.
=== Fix 2 ===


== Further Possibilities ==
An alternative fix would be to add a new boolean variable to <code>CUserCmd</code> such as <code>bButtonFlagsValid</code> that can be set depending on the validity of the button flags.  This would allow the structure to internally store this information for its whole lifetime while freeing up that extra button bit.
* Make it so that when a player is viewing the screen, all input is sent to the screen, including movement keys. The player will not be able to move again, until they look outside the bounds of the screen.


== External links ==
== External links ==
* [http://www.jakoavain.net/helk/granted.jpg Screenshot of working panels in the mod Hostile Planet]
* [http://www.jakoavain.net/helk/granted.jpg Screenshot of working panels in the mod Hostile Planet]

Revision as of 19:54, 27 September 2005


Adding a VGUI screen to a map

Note: This section assumes a mod where VGUI screens have been fixed (see the code modifications section below) but otherwise left the same. VGUI screens do not work in HL2 or HL2:DM; they crash the game. (CS:S not tested.)

  1. Create a vgui_screen entity. This is a point entity.
  2. Set its Panel Name to the name of the screen that should be shown. (This is not the filename of the screen.) The available screens are listed in vgui_screens.txt (which can be extracted from ???.gcf at steamdir\SourceMods\moddir\scripts). An example that comes with HL2 is vgui_test_screen.
  3. Set Panel Width in World and Panel Height in World to match the size of the brush. 64 wide by 32 tall would be a reasonable starting size.
  4. Compile the map and test.

The position of the entity in the map marks the bottom-left corner of the panel. The panel's direction (the normal of its face) is set by the entity's angle (Yaw).

Creating a VGUI screen

VGUI screen files have a .res extension and should be placed in steamdir\SourceMods\yourmod\scripts\screens\.

  1. vgui_test_screen.res is a good starting point for creating a VGUI screen file; it can be extracted from source engine.gcf at path hl2/scripts/screens/ using GCFScape.
  2. The materials used in the .res file can be found in source materials.gfc. Extract the material files mentioned in the .res file to steamdir\SourceMods\moddir\materials\vgui\screens.
  3. Add the screen to steamdir\SourceMods\moddir\scripts\vgui_screens.txt. Here is an example which describes screen vgui_test_screen at scripts/screens/vgui_test_screen.res and teleport_countdown_screen. Adjust it for your screen.
"VGUI_Screens"
{
   "vgui_test_screen"
   {
       // This is our example screen
       "type"		"vgui_screen_panel"
       "pixelswide"	480
       "pixelshigh"	240
       // This must be the file you created in step 1
       "resfile"	"scripts/screens/vgui_test_screen.res"
   } 
}

VGUI code modifications

There is a problem with VGUI screens receiving input. Unless it is fixed, the game may crash when the cursor points at the screen.

CInput::ExtraMouseSample calls g_pClientMode->CreateMove() without initializing the button flags, thus the VGui screen is updated with bad button input. Since IN_VALIDVGUIINPUT is only set from within CInput::CreateMove, the VGui screens only update when the button flags are valid.

There are two known fixes. They both involve code changes and therefore are only applicable to mods.

Fix 1

In in_buttons.h, where the other flags are defined add:

   #define IN_VALIDVGUIINPUT		    (1 << 23) //bitflag for vgui fix

next, in in_main.cpp inside method CInput::CreateMove( ... ) add:

   cmd->buttons |= IN_VALIDVGUIINPUT;

right above:

   g_pClientMode->CreateMove( input_sample_frametime, cmd );

next, in c_baseplayer.cpp inside method C_BasePlayer::CreateMove( ... ) add:

   if(pCmd->buttons & IN_VALIDVGUIINPUT)

right above:

   DetermineVguiInputMode( pCmd );

(So it only calls DetermineVguiInputMode if the buttons include our flag)

and finally, inside method C_BasePlayer::DetermineVguiInputMode( ... ) change both instances of:

   pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);

to read:

   pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT);

Fix 2

An alternative fix would be to add a new boolean variable to CUserCmd such as bButtonFlagsValid that can be set depending on the validity of the button flags. This would allow the structure to internally store this information for its whole lifetime while freeing up that extra button bit.

External links