Havok Script?!

Bobert13

Prince
Joined
Feb 25, 2013
Messages
346
What we've been able to discern so far...

  • There are no freely available resources for Havok Script, nor is there an official "What's New; What's Changed".
  • Leverages a strict implementation of extended-precision floating point numbers.
  • Has "hstructure" and "hmake" keywords, though they don't really seem to be anything special.
  • os.clock() is restricted to one-second resolution.
  • Does not strictly follow control structures. (see this post)
 
Since nobody seems to know anything, and I wasn't able to turn up any kind of manual available to the public, I decided to go ahead and run some tests with my WIP script. In ten generations of the same map, checking the data stored at a particular plot 9 different times during the course of the script; I achieved deterministic results!!! :thumbsup::thumbsup::thumbsup::thumbsup::thumbsup:

I went as far as to print all the way out to the 25th digit, and the numbers were actually filling all the way to the 18th digit (and even the 19th in two instances). I think it's pretty safe to assume that Havok Script is running a strict implementation of IEEE floating point at extended-precision. I approve of the change, even though I don't particularly care for Havok's lack of freely-available information of substance.
 
Good to know. Seems like its impossible to know the language extensions they supposedly made. To get manuals, you need to log in to a support portal. This is really annoying for a scripting engine that might conceivably be used by players to create content.
 
Code:
-- Highlight invalid trade plots
local bHighlightMiasma : boolean = pPlayer:GetGeneralUnitMiasmaHealthDelta() < 0;
for iPlotLoop = 0, Map.GetNumPlots()-1, 1 do
	local pPlot = Map.GetPlotByIndex(iPlotLoop);
	local hexID = ToHexFromGrid([COLOR="Blue"]Vector2[/COLOR](pPlot:GetX(), pPlot:GetY()));
	if pPlot:IsVisible(pPlayer:GetTeam(), false) then
		if (bHighlightMiasma and pPlot:HasMiasma()) then
			Events.SerialEventHexHighlight(hexID, true, g_invalidPlotMiasmaColor, g_invalidPlotMiasmaStyle);
		end
	end
end

This particular snippet from ChooseInternationTradeRoutePopup.lua includes a line that typecasts two numbers to a Vector2. Vectors are new, and so is typecasting, so that leads me to believe there's probably quite a bit of new functionality available. I am also curious about Havok's implementation of math.random. I'd like to know if it's deterministic across platforms (for multiplayer purposes). Lua's random definitely isn't. Perhaps we should make a thread over on the Firaxis forums requesting information. The least they could do is provide us with a "What's new in Havok Script" rundown.

Edit: Turns out Vector2 is a function written by Firaxis that seems to serve no purpose whatsoever... It just puts the input parameters into a table. :crazyeye:
 
This particular snippet from ChooseInternationTradeRoutePopup.lua includes a line that typecasts two numbers to a Vector2. Vectors are new, and so is typecasting, so that leads me to believe there's probably quite a bit of new functionality available. I am also curious about Havok's implementation of math.random. I'd like to know if it's deterministic across platforms (for multiplayer purposes). Lua's random definitely isn't. Perhaps we should make a thread over on the Firaxis forums requesting information. The least they could do is provide us with a "What's new in Havok Script" rundown.

Edit: Turns out Vector2 is a function written by Firaxis that seems to serve no purpose whatsoever... It just puts the input parameters into a table. :crazyeye:

I wouldn't say it serves no purpose, it's a structure. The random number generator is certainly different, as Firaxis seem to use their own (Game.rand). Some of the lua scripts suggest that it's properly seeded across different players' machines in MP

This comment is from aliens.lua
Code:
	-- NOTE: This must be a table of tables in order for Lua to index them by integer and ensure deterministic iteration (necessary for multiplayer)

As for Havok script, it seems that BehaviourTree.lua is interesting. While I don't know what the structure is used for yet, there are some interesting points

Code:
----------------------------------------------------
-- Prototypes
----------------------------------------------------
hstructure CvBehaviorStatus
	SUCCEEDED : number
	FAILED : number
	IN_PROGRESS : number
end

hstructure CvBehaviorNode
	Tick : ifunction
	Sort : ifunction
	GetStatus : ifunction
	Children : table
end

BehaviorStatus = hmake CvBehaviorStatus
{
	SUCCEEDED = 1,
	FAILED = 2,
	IN_PROGRESS = 3,
};

----------------------------------------------------
-- Functions
----------------------------------------------------
function BehaviorTree(t : table)
	return SelectorNode(t);
end

-- Action Nodes are the leaves of a behavior tree, and actually do
-- things.
function ActionNode(t : table)
	if ((t[1] == nil or type(t[1]) ~= "function") and (t.Tick == nil or type(t.Tick) ~= "function")) then
		error("Action Nodes should only contain a function!");
	end
	
	local action : CvBehaviorNode = hmake CvBehaviorNode{};

	-- support either a function in the table, or a named Tick function in the table
	local tickFunction = nil;
	if (t.Tick ~= nil) then
		tickFunction = t.Tick;
	else
		tickFunction = t[1];
	end

	action.Tick = function(...) 
		local status : number = tickFunction(unpack(arg));
		if (status == nil) then
			error("Behavior tree action node did not return a status");
			return BehaviorStatus.FAILED;
		end

		return status;
	end

	return action;
end
This strongly suggests some variable typing and the hstructure keyword seems to be new.
 
They've added a function call to incapsulate two parameters into a table when from both a simplicity point of view and a performance point of view, they shouldn't be putting the variables into a table at all much less calling another function on top of that! Lua in general is terrible with table reads and writes as they always occur from memory (and not from the processor's cache); this could (and probably does) behave differently in the Havok script parser as it's a fairly simple way to shave a lot of IO time off the top and run the script faster. Additionally, Lua does not support inline function calls in any manner (another thing that I'm quite positive has changed with Havok as LuaJIT even looked for places to inline small frequently called functions).

Map.rand and Game.rand are nothing new, they were both in civ V and were deterministic across platforms. I haven't tested Game.rand, but Map.rand in BE is still restricted to integers, capped at 65,535, has no min value input, and still requires a string (even if it's empty) as the second parameter. That leads me to believe neither has changed much if at all.

hstructure is actually something interesting. And it does have type mapping there (where it typecasts a new variable and possibly sets some value to avoid "nil") but the types seem to be existing Lua types. Furthermore, in the code you posted, there's not a thing there that can't already be done with tables and metatables. If these new structs come with some useful way of manipulating or accessing them then that would be cool, but there's no such thing there. I'll definitely be doing a "Find in Files" for hstructure though to see if I can turn up anything new and exciting. Thanks for posting about them.
 
:cry:

Havok Script's implementation of the os.clock() function is clamped to full seconds... Unless it provides some new function or parameters that lua doesn't have, there is no way to benchmark a segment of code inside of a script running in the game! In 5.0 through 5.2 on Windows and Linux systems, os.clock's resolution was in milliseconds and it's accuracy in a lightly stressed environment was within an acceptable range (something like +/- 6ms IIRC)...

WHY? :wallbash:
 
Havok Script's implementation of the os.clock() function is clamped to full seconds... Unless it provides some new function or parameters that lua doesn't have, there is no way to benchmark a segment of code inside of a script running in the game! In 5.0 through 5.2 on Windows and Linux systems, os.clock's resolution was in milliseconds and it's accuracy in a lightly stressed environment was within an acceptable range (something like +/- 6ms IIRC)...

WHY?

According to their propaganda product website, they provide in-depth profiling tools for their customers, so it's conceivable that they want to encourage them to use those.

Anyways, I agree that the typed stuff doesn't seem to do much in that script beyond what Lua can already do. The only thing that seems to be new is the ifunction - perhaps inline function?
 
Just curious if anyone else out there has found anything else interesting regarding Havok Script or the new Lua code. I scanned over most of the instances of hstructure and hmake and so far as I can tell there's nothing significantly different about hstructures compared to Lua tables. And hmake is simply the command to initialize hstructures. The typemapping types additionally aren't anything new unless ifunction is a guaranteed inlined function. Inlined code would be something new and could help explain why Havok Script appears to execute equivalent code significantly faster than Lua or LuaJIT.
 
Back
Top Bottom