PDA

View Full Version : [Tutorial] Creating a Basic Extension



lokiare
February 12th, 2014, 03:09
To start you should plan out what you want your extension to do. Its also helpful to unzip several pre-made extensions and rule sets to see how things are done in them. To do this copy the rule set or extension out of the rule set or extenstion folder into a location outside the Fantasy Grounds folder. Then rename the file from *.pak or *.ext to *.zip. Then open it as you would a normal zip file. Extract those files to a location you can easily get to. Then open those files in your favorite reader (I use Notepad++).

An extension is based on the same code as a rule set, but it supersedes the code in a rule set. This is helpful because you can override entire files in a ruleset or simply override a few widgets or pieces of code.

What you need to do next is create a folder in your Fantasy Grounds extensions folder:
<drive letter>:\Users\<username>\AppData\Roaming\Fantasy Grounds\extensions\<extension folder name>

After you create the folder, next you need to create an xml file called 'extension' in that folder. More information can be found here (https://www.fantasygrounds.com/modguide/extensions.xcp). Then we fill in the xml file with the following:



<?xml version="1.0" encoding="iso-8859-1"?>
<root version="3.3" release="1.0">
<announcement text="Text that is displayed on start of ruleset. Usually the extension name and copyright info." font="emotefont" />
<properties>
<name>Name of Extension</name>
<version>0.1(version of extension)</version>
<author>Author of Extension</author>
<description>A description of the extension.</description>
</properties>
<base>
<!-- This file is our main Lua file. You can name it what you want, but you must use xml restrictions in order to do that.-->
<script name="ScriptPackageName" file="scripts/scriptFileName.lua" />
</base>
</root>


Once you have this done, you can begin coding the extension in the script file that you created. To access your script files functions and global variables you'll use the 'name=' attribute of the <script> tag, in this case it is "ScriptPackageName". This is useful if you have to put scripts in other locations such as within xml tags within other file locations that you are overriding (such as the example xml file of "campaign/campaign_images.xml"). Sometimes you will need to put scripts within xml tags in order to have certain functions and callbacks work properly.

A good practice is to keep all of your global variables in your main Lua file (in this case "ScriptPackageName") and access them from the custom script locations, because it is difficult to derive a package name to where those other scripts are located (and likely have to be done at run time due to 'instances' of those packages and classes).

Our Lua file should look like this:



--
-- © Copyright James (Lokiare) Holloway 2014+ except where explicitly stated otherwise.
-- Fantasy Grounds is Copyright © 2004-2014 SmiteWorks USA LLC.
-- Copyright to other material within this file may be held by other Individuals and/or Entities.
-- Nothing in or from this LUA file in printed, electronic and/or any other form may be used, copied,
-- transmitted or otherwise manipulated in ANY way without the explicit written consent of
-- James (Lokiare) Holloway or, where applicable, any and all other Copyright holders.
--


You'll want to put your copyright info and the copyright info of SmiteWorks first using the comment tags "--". This will help protect SmiteWorks and yourself from any kind of lawsuit or copyright theft.



-- Global Variables for this package
count = 0;


Global variables can be accessed in other packages by using the package name and a '.' and then the global variable name (for instance: "ScriptPackageName.count" for the above variable). In this Lua file package they can be accessed just using the variable name "count". Variables in Lua aren't typed, so you don't have to know what's in a variable to use it or assign it.

To keep this simple I'm going to make an extension for 4E that allows you to send some text to the chat window on the start of someones turn. This text will include the name of the character who's turn it is and the number of rounds that have gone by. In order to do this we have to find out who's turn it is on the combat tracker.



function getTokenInfo(nodeEntry)
-- This is the structure of Fantasy Grounds chat messages. Sender is who it shows as sending the message. Font is the font used to display the message. Icon is the special fantasy grounds icon displayed next to the sender. You can assign special icons, but that is beyond the scope of this tutorial.
local msg = {sender = "Zones", font = "emotefont", icon = "turn_flag"};
msg.text = "";
-- Get the current characters name (check to make sure the nodeEntry is not nil)
if nodeEntry then
-- Here we use the ActorManager to get the actor from the Combat Tracker based on the node entry that is passed into the function.
local rActor = ActorManager.getActorFromCT(nodeEntry);
-- We set the message text to be equal to the actors name.
msg.text = rActor.sName;
end
-- Return the msg that we created so it can be used to display the message to the chat panel.
return msg;
end


Now that we know who's turn it is and we return that information in a msg object (all variables are really tables in Lua). We need to use a callback in order to have Fantasy Grounds trigger the action on the start of a turn. For more functions and callbacks refer to the rule set reference guide (https://www.fantasygrounds.com/refdoc/). Some specific functions and callbacks may not be detailed there, but you can find them specifically in the rule set .pak file that they belong to. The rule set reference guide mainly covers the core Rule set that all other rule sets are based on.



-- This function is one that the Combat Tracker calls if present at the start of a creatures turn.
function onTurnStartEvent(nodeEntry)
-- Here again we create a msg (https://www.fantasygrounds.com/refdoc/Comm.xcp) and call the getTokenInfo function that we created earlier to get a message with the creatures name whose turn it is.
local msg = getTokenInfo(nodeEntry);
-- We concatenate several strings onto it using '..' the Lua concatenation symbols for strings. (its useful because it tries to convert whatever you are putting together into a string.
msg.text = "Its " .. msg.text .. "s turn.";
--Here we call the Comm (https://www.fantasygrounds.com/refdoc/Comm.xcp) package to send the message to the chat. We use deliverChatMessage in order to have it echoed to the clients that are connected.
-- Iterate the count
count = count + 1;
-- Add the count to the message
msg.text = msg.text .. " The turn count is " .. count .. ".\r";
Comm.deliverChatMessage(msg);
end


After this you need to register your callback in the combat tracker package.



-- This function is to initialize variables
function onInit()
-- Here is where we register the onTurnStartEvent. We can register many of these which is useful. It adds them to a list and iterates through them in the order they were added.
CombatManager.setCustomTurnStart(onTurnStartEvent) ;
end


There you have it. If you load up Fantasy Grounds, you should see your extension listed. I suggest creating a new campaign to test your extension in, so you don't mess up an existing campaign with bugs. Throw a few creatures into the combat tracker and change turns and see what the chat log says.

Any questions or comments are welcome.

lokiare
April 21st, 2016, 04:16
A user verified this tutorial is still valid for the 5E rule set.

bigbluepaw
January 27th, 2017, 19:40
Hey folks. Just an FYI, I followed this tutorial to the letter and FG gave me an error over the following code.


<includefile source="campaign/campaign_images.xml" />

I assume that is because this file does not exist anywhere in the extension folder or sub-folders.

I would suggest removing that line because the extension won't load.

I would love to see how that example works. But it might not be appropriate here, especially for new coders. Just a thought.

damned
January 28th, 2017, 00:29
The windows have changed significantly since 3.2.0 so this tutorial will need some updating....

Varsuuk
January 31st, 2017, 12:19
Heheh JUST as I start reading tutorials, I am noticing a lot different ;) I was warned the Runequest one is "a bit old" - so, if someone is trying to learn enough to get a feel on how to start extentions or rulesets, what would you suggest they start looking at to get the skeletons of needed work?

Like, look at these 2 stickied then check patch notes or beta forum for description of changes? etc?

damned
January 31st, 2017, 12:27
Heheh JUST as I start reading tutorials, I am noticing a lot different ;) I was warned the Runequest one is "a bit old" - so, if someone is trying to learn enough to get a feel on how to start extentions or rulesets, what would you suggest they start looking at to get the skeletons of needed work?

Like, look at these 2 stickied then check patch notes or beta forum for description of changes? etc?

What are you wanting to do?

Trenloe
January 31st, 2017, 16:48
what would you suggest they start looking at to get the skeletons of needed work?
https://www.fantasygrounds.com/forums/showthread.php?20651-Modifying-the-CoreRPG-ruleset

If you're modifying BRP read the guide that is supplied in the <FG app data>\docs directory.

Varsuuk
January 31st, 2017, 17:02
That's the problem. I just want to learn how to read through existing CoreRPG and then maybe 5e / C&C that I own to learn enough to probably start by creating a character sheet for something (up in air atm) and code functionality to it to see how it goes.

I'm a curious guy who enjoys mucking with coding - I have vague ideas in where I might want to go once I get a minimal understanding but no precise questions. If I did, I'd be golden because between you and some other community devs here, I could have my every question answered.

My problem is where to start, what to read either in forums/pdfs to guide me while I look at the xml and lua. I had originally thought to start from the developer wiki to look at the creating that simple Runequest example. I knew it was old but suspected it could at least show me a set of steps even if the referenced files/names were off. Probably still good for that, I will be reading it throughout the day while wait on extensive performance tests I'm running here at the office.

After that, I figured try reading through all of the armory forums for posts by others either giving tutorials first then people asking questions next in the forums figuring to get info by inference.

But yeah, If you were to be asked "I want to learn HOW to develop a ruleset, I am thinking of doing something like taking C&C and making one change of some sort to something character related that is big (I'll likely make up something silly like adding Comeliness and some other mechanic I can find that I have no interest in other than to force me to learn how to make changes.

After that, I'd probably try to implement something based on Core as. parent ruleset. Even if whatever I pick is closer to 3.5 or C&c etc, I want to build it closer to from scratch. This is for me, for my intellectual exercise. If I find I have a knack, certainly I would then seriously consider selecting some system I know that I'd like to see implemented.

But yeah, right now I am looking for an outline of how to approach and if lucky, any posts or tutorials that even if dates, would allow me to gain insights.

Trenloe
January 31st, 2017, 17:08
My problem is where to start, what to read either in forums/pdfs to guide me while I look at the xml and lua.
https://www.fantasygrounds.com/forums/showthread.php?20651-Modifying-the-CoreRPG-ruleset

Varsuuk
January 31st, 2017, 17:11
https://www.fantasygrounds.com/forums/showthread.php?20651-Modifying-the-CoreRPG-ruleset

If you're modifying BRP read the guide that is supplied in the <FG app data>\docs directory.


Thank you Trenloe, another of the wizards for this sort of stuff ;)

I'm actually not at all knowledgeable regarding BRO. I don't own it or any pdf on it (closest are all my Chaosium Midkemia books and boxed Thieves World?)

Only reason I listed Runewuest was because it was the pdf linked on the developer wiki in "developing ruleset" as a simplistic tutorial on how to take the D20 ruleset (didn't look, guess that's an old one you can dl) and starting to make the Runequest one or something. As I said, I just started it and saw that much was not matching.

Varsuuk
January 31st, 2017, 17:12
https://www.fantasygrounds.com/forums/showthread.php?20651-Modifying-the-CoreRPG-ruleset

Perfect, will start there. Because that is exactly what I want to do.

Anything I should particularly be aware of vis a vis 3.2.2 affect on these threads?

MarianDz
February 9th, 2017, 17:35
Please don't know somebody what are conditions for logo.png because my one won't work :confused:

17849
17850

I want add it to my language extension but it still won't work.

And maybe font extension cant have logo displayed when enabled as modules has ;)

Trenloe
February 9th, 2017, 17:54
You need to set the graphics as an icon resource within the extension: https://www.fantasygrounds.com/refdoc/icon.xcp

Then use that icon name in the icon="<icon resource name>" portion of the extension <announcement> entry. See extension.xml in this extension for an example of the announcement entry: https://www.fantasygrounds.com/forums/showthread.php?33834-Map-resize-to-TV-resolution-for-Face-To-Face-games

MarianDz
February 9th, 2017, 19:21
Thank you :o Trenloe ... it working now

zzzbest
December 20th, 2017, 01:04
I made a trivial string change to an extension and FG doesn't see it. I created a zip and renamed it .ext - is there a step I missed? Or some specific zip parameters that must be set?
Regards,
Bruce

Andraax
December 20th, 2017, 01:09
Probably zipped the directory instead of the contents of the directory...

damned
December 20th, 2017, 11:41
The most likely error is what Andraax suggests followed by the file actually being called filename.ext.zip

zzzbest
December 21st, 2017, 23:50
Probably zipped the directory instead of the contents of the directory...

Thanks that worked!

lesliev
March 30th, 2018, 11:44
Is this tutorial still valid?

The example failed to load because the campaign_images.xml file didn't exist. I couldn't find this file in the CoreRPG or 5E pak files. After removing the line referring to it, the extension seemed to load without error, but I saw no messages at all in the chat log.

lokiare
March 31st, 2018, 14:17
I've modernized it, but it should have worked as-is. You should double check that you followed all of the steps and you should use "/console" to pull up the console before you open the combat tracker in case you get warnings instead of errors.

danielfruth
November 27th, 2019, 04:51
30495

This is how the sheet looks so far. I _think_ I am using the most recent extension but the size of the Attacks Frame doesn't match the tutorial. Changing the offset 15 should change the upper left corner I think but it isn't actually having any effect. It's not really a big deal. The attacks frame is a bit of a pain anyway because when you scroll down and click on something at the bottom it bounces up so what you actually click on is the lowest text entry _before_ you scrolled down. I think I'd rather use a roll entry from the skills or feats to simulate an attack.

Anyway, there are none of those saves so I deleted them. I have them mostly automated in the section below. I deleted the title and will copy the class section so I can multiclass. Then I'll try to copy the Class thing to create races. I will probably get rid of the AC calculation since in Rifts the AR is simply a roll to see if the armor or you was hit. A miss is 5 or less and dodge is another roll altogether. Its been a while since I played so it sounds weird as I think about it. I guess I played too much D&D, its corrupted my mind.

damned
November 27th, 2019, 05:26
Hi danielfruth

This has been posted on the wrong thread but Im not sure which one to move it to...

Unfortunately Ive left some legacy code in the frames you are talking about. At the top of the page you will see a script that sets the sizes for some frames - it uses this so that the frames can resize if the charsheet is resized by the player.

Look for the function resizeFrames

lprchaun
March 3rd, 2023, 15:35
thanks for this, it was a good start. I have been trying to zip my extension with a password. I am able to get it to work normally, but when I add the password, FGU fails to see it.

Trenloe
March 3rd, 2023, 15:58
I have been trying to zip my extension with a password. I am able to get it to work normally, but when I add the password, FGU fails to see it.
That's expected - because FGU isn't aware of the password you used, and there isn't a way to tell FG what the password is for extensions.

If you end goal is to have an extension and people can't view the code, and you're going to make this extension public, consider putting the extension in the FG Forge and have it in the Vault - which will mean it will be password protected by the FG process and so FG can use it, but users can't open it.

lprchaun
March 3rd, 2023, 16:28
That's expected - because FGU isn't aware of the password you used, and there isn't a way to tell FG what the password is for extensions.

If you end goal is to have an extension and people can't view the code, and you're going to make this extension public, consider putting the extension in the FG Forge and have it in the Vault - which will mean it will be password protected by the FG process and so FG can use it, but users can't open it.



Thank you. I was trying to figuer out if the Forge did that automatically, but I couldn't find any documentation on it.