SteamVR/Environments/Scripting/Linking Lua with Javascript

This tutorial shows how to communicate between the server-side VScript (Lua) and the client-side Panorama (Javascript) scripting systems.
== Linking Lua with Javascript ==
In some cases, you will need the Lua script to communicate with Javascript. In Arcade Toss, there’s a scoreboard that displays things like the scores, the timer and instructions. 
This is done using Custom Nettables in conjunction with Panorama, Javascript, and CSS.
You’ll first need to place a point_clientui_world_panel in your map. This the panel used for the Arcade Toss scoreboard:
Create an XML file in your \content\steamtours_addons\arcade_roll\panorama\layout\custom_destination directory. 
There is one called arcade_toss_scoreboard.xml in the example. Your dialog_layout_name will need a path to this file similar to this:
file://{resources}/layout/custom_destination/arcade_toss_scoreboard.xml
The scoreboard is pretty large, so the panel_dpi is lower than a typical panel and the ignore_input should be off.
Your XML file will include a styles (.CSS) file and a Javascript (.JS) file:
	<styles>
		<include src="file://{resources}/styles/custom_destination/arcade_toss_scoreboard.css" />
	</styles>
	<scripts>
		<include src="file://{resources}/scripts/custom_destination/arcade_toss_scoreboard.js" />
	</scripts>
You’ll need a custom_net_tables.txt file in your_addon\scripts directory.
You can change the key in the table, but the Arcade Toss table contains “hoops_score”:
{
	custom_net_tables =
	[
		"hoops_score",
	]
}
Then, you’ll need global variables created in your addon_game_mode.lua file with a SetTableValue function:
-- Team Scoring
_G.Scores = { red_score = 0, blue_score = 0 }
_G.Timer = 121
CustomNetTables:SetTableValue( "hoops_score", "scores", _G.Scores );
Your key name in the custom_net_tables.txt file should match the string in the SetTableValue function.
The next entry in the table is “scores” which is the data that the Javascript will use and the final entry “_G.Scores” is the global variable table that stores the scores of both teams.
In Arcade Toss, the UpdateScoreboard function is called whenever a red ball goes into a red target hole or a blue ball goes into a blue target hole.
--------------------------------------------------------------------------------
-- Scoreboard
--------------------------------------------------------------------------------
function UpdateScoreboard(team, value)
	--Team (Red = 1, Blue = 2)
	if _G.Timer > 0 then
		if team == 1 then
			if bIsRedTeamBehindTheLine == true then
				EmitGlobalSound("red_score_point")
				red_total = red_total + value
				_G.Scores = { red_score = red_total, blue_score = blue_total }
				CustomNetTables:SetTableValue( "hoops_score", "scores", _G.Scores );
			else
				EmitGlobalSound("score_error")
			end
		else
			if bIsBlueTeamBehindTheLine == true then
				EmitGlobalSound("blue_score_point")
				blue_total = blue_total + value
				_G.Scores = { red_score = red_total, blue_score = blue_total }
				CustomNetTables:SetTableValue( "hoops_score", "scores", _G.Scores );
			else
				EmitGlobalSound("score_error")
			end
		end
	end
end
The SetTableValue function is called if the team is not across the line. This sends the data referenced to the Javascript.
You’ll need to create a Javascript file in your \content\steamtours_addons\your_addon\panorama\scripts\custom_destination\ directory.
There’s a listener in the arcade_toss_scoreboard.js file that listens for the data from the custom_net_table.txt file:
(function()
{
	CustomNetTables.SubscribeNetTableListener( "hoops_score", OnGameStateChanged );
	UpdateScoreboard();
	GameEvents.Subscribe( "countdown", UpdateTimer );
	GameEvents.Subscribe( "pregame_countdown", PreGameTimer );
})();
It also provides the functions in the Javascript file to execute when the data is received OnGameStateChanged and UpdateScoreboard.
These two functions set up the scores to be displayed:
function OnGameStateChanged( table, key, data )
{
	$.Msg( "Table '", table, "' changed: '", key, "' = ", data );
	UpdateScoreboard();
}
function UpdateScoreboard()
{
	var scores = CustomNetTables.GetTableValue( "hoops_score", "scores" );
	var blueScore = CustomNetTables.GetTableValue( "hoops_score", "blue_score" );
	$("#RedScore").text = scores.red_score;
	$("#BlueScore").text = scores.blue_score;
}
This takes the data sent from the Lua file and breaks them down into Team Red’s score (known simply as “scores”) and Team Blue’s score (“blue_score”).
Then, the function puts them into the Panorama display. The #RedScore and #BlueScore refer to the ID’s of the panels in the XML file:
	<Panel class="Scoreboard">
		<Panel class="TeamScore" id="RedScoreGroup">
			<Panel class="TeamNameWrapper" id="RedWrapper">
				<Label class="TeamName" text="#ArcadeToss_ScoreRed" />
			</Panel>
			<Panel class="RedScoreWrapper">
				<Label class="Score" id="RedScore" text="999" />
			</Panel>
		</Panel>
		<Panel class="CenterPanel">
			<Image id="DestinationsTitle" src="file://{resources}/images/destinations_title_large.png" />
			<Label id="Title" text="#ArcadeToss_ScoreTitle" />
			<Label id="PreGameTimer" text="#ArcadeToss_ScoreStart" />
			<Label id="Timer" text="--:--" />
		</Panel>	
		<Panel class="TeamScore" id="BlueScoreGroup">
			<Panel class="TeamNameWrapper" id="BlueWrapper">
				<Label class="TeamName" text="#ArcadeToss_ScoreBlue" />
			</Panel>
			<Panel class="BlueScoreWrapper">
				<Label class="Score" id="BlueScore" text="999" />
			</Panel>
		</Panel>
	</Panel>
The data from the Lua file will then get placed into these score panels.
The CSS file placed in \content\steamtours_addons\arcade_roll\panorama\styles\custom_destination will contain the styles used for the panels in the XML file.
Category:SteamVR
Category:SteamVR Home
Category:Scripting
Category: Panorama