The Forums Are Now Closed!

The content will remain as a historical reference, thank you.

Tutorial: How to Hook

By on November 6, 2009 1:54:19 PM from Demigod Forums Demigod Forums

Some of the modders in the SupCom mod community have made some abysmal code that causes problems with compatibility even now, so I'mma write a quick tutorial here on how to make your mod compatible.

#1 Tables.

You can recognize a table by the use of {}. This marks a table constructor. Tables are passed by reference- that is, if you pass a table to a function, the table is the same table, and not copied. Table constructors can contain fields, like this:[code]{

    Key = value,

    Anotherkey = anothervalue,

}[/code]This is much, much faster and neater than creating an empty table and inserting into it, and should be used whenever you want to store something in a table when you know what it is at create time.

Now, you're going to see a lot of predefined tables in GPG code. You can see an example of big tables by cracking open any blueprint file, but they're everywhere in Lua. Now, how do you alter a table that's already been created? There are several ways, but the easiest is to use table.insert(table, value). This function will literally append the value to the end of the table. You call it, your value's in, you toddle off.

The second way to modify tables is through the use of the table[key] = value syntax. Here, you specify your own key, instead of table.insert coming up with an efficient numerical key for you. This can be important in, for example unit description tables, when the description key has to match the one specified, or blueprints. Here, Lua doesn't distinguish between overwriting a previous key, and adding a new one, so you'd best be careful to make sure that you're the correct user of that key. By assigning a key to nil, you can also remove that key/value pair from the table, i.e. table[key] = nil.

Do not ever change a table by hooking a file with an altered version of the constructor in it. That's a sin, and other modders will rightfully end your existence.

#2 Functions

If you have the function without a key, there is no way to tell what function it is without resorting to some extreme methods. However, you can modify it without needing to know the source. Modifying a function occurs only at the environment where the modification takes place. E.G. if you want to alter a function for everyone who calls it, you need to alter it at the point of calling. Function hooking uses a simple principle: you overwrite a variable with the value of a new function, which calls the old function. By using this, you can for example record when a function is called, and such things.

[code]function example(args) end

local temp = example

function example(...) # This will make sure that no arguments are ever lost. If you know the source function, you can name and gather information about them.

    return temp(...)

end[/code]

Of course, that function effectively makes no change. However, you could alter it to do anything instead.

 

The key with the above techniques is that they will nest indefinitely, and are order-independent. That means that you can use them with a hundred mods, and it doesn't matter when they're loaded, and it will still work out correctly. Do not ever change a function or table by simply overwriting the definition of it, unless you must, and those instances are pretty rare.

 

In SupCom, there's a UnitDescriptions table, where table[ID] = description. People overwrote the definition of it. Surprisingly, their mods have conflict issues, now the original creator doesn't support it and .. mess. If you need to alter a GPG function or table, do try not to destroy the original.

+5 Karma | 8 Replies
November 8, 2009 6:12:47 PM from Demigod Forums Demigod Forums

Now, how do you alter a table that's already been created? There are several ways, but the easiest is to use table.insert(table, value).

Did you mean table.insert(key, value)?

Good post though! I think part of the problem is that some modders just hack together a prototype proof of concept and continue working with it instead of discarding and starting with some semblance of order.

November 16, 2009 3:39:17 PM from Demigod Forums Demigod Forums

table.insert and table.remove use numerical keys. table.insert(table, value) is correct. If table.insert worked like that, what would be the point compared to using table[key] = value? I checked the lua.org documentation, and it does specify optionally to add the key for (table, key, value) but I have never seen it used this way and it's perfectly possible that it doesn't function this way in Lua 5.0.1 (Demigod's Lua), especially since there is no point to it compared to tab[k] = v.

table.remove is unfortunately difficult and irritating to use, since it takes a key, information that you don't get when using table.insert. Easier to use table[key] = nil.

December 4, 2009 3:13:52 PM from Demigod Forums Demigod Forums

table.insert is a constant function

<table> is the tablename

table.insert(<table>, value) and table.insert(<table>, key, value) are not quite comparable. its the same function but the use is different. table.insert appends a value to a table. its most often used when the table is an array! so you dont need to bother where to insert it, its just appended to the array and the key is the nummerical position of the value in the array. a different use of tables is to use them as dictionaries. then the key is not a number but a string. table.insert(<table>, "keyname', value) then is equal to <table>.keyname = value or <table>["keyname"] = value. be aware of the quotes!

of course you can also give a key when you want to insert something into the array-table, then its a real insert and not an append.

December 4, 2009 3:28:59 PM from Demigod Forums Demigod Forums

When I was working on altering the size of the QoT model, I found the necessary values in the queen_character.lua file. This file, although labelled as a lua, it is actually a blueprint file. Within the file is the character blueprint and it contains the field [Name = Queen]. This field was necessary to match my mod changes to the original table. The problem was that I could not figure out what the table was named. The blueprint namer functions have a series of rules for converting the filename to a default blueprint name, however none of these seemed to work. Additionally, without the [Name = queen] line, the mod did not affect anything. In the end I did a destructive replacement of the entire file (horrid compatiblity, I know), which did work. A better alternative I assume would be to use [import '/base file'].

So my question then is, when a blueprint table is created in a regular lua file, how is the table referenced? I'm further assuming that once I can reference the table I can then use the table.insert function as normal.

December 4, 2009 3:46:13 PM from Demigod Forums Demigod Forums

hm i dont know exactly but i think that blueprints are just normal lua files with only table definitions in it. i suggest you look into the mod that sorian made for the torchbearer. perhaps you can achieve something by setting merge=true... just look into his mod.

the blueprint files are actually all loaded automatically and i dont know how the naming convention is. i think its also lua code that loads blueprints and that i have seen it somewhere when in added another type of angels so another way would be to look out for that.

i would assume that it is like this:

newname = import("charachterblueprint.bp").CharacterBlueprint

then i gues that its stored somewhere in a unitarray or something...

December 4, 2009 4:06:09 PM from Demigod Forums Demigod Forums

 

Don't have the game files infront of me, but there is a globalinit.lua or something close to that with wildcard import loops.  Think it said:

for *.*_aiblueprint in /units/

import (filename)

end

 

I believe this is where the bulk of the lua/blueprints get loaded. 

 

When you say ' destructive replacement of the entire file' does that mean you just refenced the key and overwrote the original with your version?

like Characterblueprints['queen'] = {your version of it}

That is what i did for the aitemplates as I ended up changing the bulk of the file or plan to change most of the file anyway, so I figure i might as will overwrite the original with my version?   Technically at this point i could probably just delete out the default skillbuilds and replace just that section with my own.

December 4, 2009 5:34:48 PM from Demigod Forums Demigod Forums

When I first started working the mod I did reference Sorian's TorchBearer Fix. In it he does two important things:

    Merge = true,
    BlueprintId="hema01",

The [BlueprintId] gives the name for the blueprint to be altered, the [Merge] includes all of the original information from the original [BlueprintId] and only overwrites with the new data.

Unfortunately, for theQoT, my attempts to find her BlueprintID weren't successful. I tried all of the following [BlueprintID]s, none of them worked.

#    BlueprintId="hqueen",

#    BlueprintId="\000hqueen",
#    BlueprintId="queen_open_character",
#    BlueprintId="queen_closed_character",
#    BlueprintId="queen_open",
#    BlueprintId="queen_closed",
#    BlueprintId="hqueen_open_character",
#    BlueprintId="hqueen_closed_character",
#    BlueprintId="hqueen_open",
#    BlueprintId="hqueen_closed",
#    BlueprintId="queen_unpacked_character",
#    BlueprintId="queen_packed_character",
#    BlueprintId="queen_unpacked",
#    BlueprintId="queen_packed",
#    BlueprintId="hqueen_unpacked_character",
#    BlueprintId="hqueen_packed_character",
#    BlueprintId="hqueen_unpacked",
#    BlueprintId="hqueen_packed",

When you say ' destructive replacement of the entire file' does that mean you just refenced the key and overwrote the original with your version?

I added the file to a mod in a hook directory in the appropriate location and made the changes I wanted. If I only included the single line change I wanted (along with the required [Name] field) all of the other information was wiped out. I could tell because the file also controlled all of the animations, which were disabled when I loaded my mod. Without the [Name] field the changes were not implimented (most likely because nothing was present to identify which table should be altered]. Additionally, once I got the changes working I attempted to use the [merge] field, however it did not do anything, everything was still overwritten.

 

December 4, 2009 11:20:13 PM from Demigod Forums Demigod Forums

The blueprints are normal lua code that just looks a little weird because there are some lua metatables defined so that when a blueprint is read in, a function gets called, so:

CharacterBlueprint { bunchofkeyvaluepairs }

actually calls a function (CharacterMeta.__call() in this case).  It seems kind of a pointless abstraction and could just as easily have been written in a less-obfuscating: CharacterBlueprint({ bunchofkeyvaluepairs}).

These metatables are defined in lua\system.  This one in particular is in lua\system\CharacterBlueprints.  All it really does is store the blueprint in the global "Characters" table using the lowercase Name as the key...

So...you'll find the blueprint in Characters['queen'] (or Characters.queen if you prefer) and can just override the values you wish like: Characters.queen.AnimStates.Idle.TimeScale = 2

If you are wanting to modify a blueprint file that ends in ".bp" then read lua\system\Blueprints.lua for some help on that.  For blueprints that end in ".lua" then the stuff I wrote above is how you do it.

Stardock Forums v1.0.0.0    #108435  walnut2   Server Load Time: 00:00:00.0000296   Page Render Time:

Stardock Magazine | Register | Online Privacy Policy | Terms of Use

Copyright ?? 2012 Stardock Entertainment and Gas Powered Games. Demigod is a trademark of Gas Powered Games. All rights reserved. All other trademarks and copyrights are the properties of their respective owners. Windows, the Windows Vista Start button and Xbox 360 are trademarks of the Microsoft group of companies, and 'Games for Windows' and the Windows Vista Start button logo are used under license from Microsoft. ?? 2012 Advanced Micro Devices, Inc. All rights reserved. AMD, the AMD Arrow logo and combinations thereof are trademarks of Advanced Micro Devices, Inc.