PDA

View Full Version : Mod File Generation and Packing Tool



hooker
January 1st, 2018, 18:22
Sadly I cannot edit the title but maybe I'll create a new post once I consolidate it the packages below.

FantasyGrounded
New Project(2/13)
https://i.imgur.com/VDGAmfk.png
FantasyGrounded (PhantasY) is a project that helps utilize and explore data from the Fantasy Grounds application. Currently campaign data is supported including data available from previous sessions. As a DM and as a player I prefer to backup my character sheet after each session -- the first goal of this project is to automate character backups after each session.

Search through existing campaigns:


from phantasy import datahelper
data = datahelper.DataHelper()
for campaign in x.campaigns:
print(campaign)


Get metadata and data from a specific campaign:


campaign = data.getCampaign('Basic Campaign')
print(campaign.metadata, campaign.getData())


Other Data Files
The other forms of data in the root folder, some of which are listed here (https://www.fantasygrounds.com/wiki/index.php/Data_Files_Overview)(FG Wiki), will be implemented similarly.

Searching & Reading Campaign Data

Pull data using the datahelper.pymethods, or by directly accessing it through campaign.py.
Use the included utils to convert the data from XML→Dict→
Render the data usable for FGModGen or readable by other processes.


Installation

Download Python 3.x (https://www.python.org/downloads/)
Clone or download FGModGen (https://github.com/zacharyhooker/fantasygrounded)(Github)
Setup run.py to either search or read campaigns as below.



TODO

Rulesets/Lua
FGModGen is currently ruleset agnostic although it can generate modules for specific rulesets. It is necessary to allow a larger scripting platform for the Lua implementation that SmiteWork's provides.
Extensions
Extensions (and most other FG files) are compressed files with scripting resources. The first order of FantasyGrounded's extension capabilities is to allow UI modifications. Think FG Gap and BigFonts' XML font and graphics wrapping capabilities.
Distribution
Simple integration into the forum for posting and updating.



https://github.com/zacharyhooker/fantasygrounded





FGModGen
I've updated this project! (2/13)


An FG .mod files generally consist of two files:

definition.xml - Includes the name, author, and ruleset of the mod.
db.xml - A list of all of the data, including file locations, and their references.
But it may also consist of image, text, or other files.

FGModGen is a module generator and packer: you specify a folder, author, and mod name and the script finds images in the folder you specify and compiles a valid definition and db XML file. Then you can call mod.zip(location) to zip and install the mod to your Fantasy Ground's data folder.


newMod = ModuleGen('ModuleName', author='You', xmlout='ModuleNameOUt')
newMod.genXML()
newMod.zip('S:\Fantasy Grounds\Data\modules\')
FGModGen is written in Python 3 and currently supports image and map packing. The source is here (https://github.com/zacharyhooker/FGModGen)(github).

Installation

Download Python 3.x (https://www.python.org/downloads/)
Clone or download FGModGen (https://github.com/zacharyhooker/FGModGen)
Edit or create a new main execution and zip the file out to your FG Data/Modules folder.
(Check the bottom of MapModuleGen.py or create a new file and import ModuleGen)
Run the script.
Load Fantasy Grounds and enable the new module in-game.



FAQ

How is this useful for the average player?

It makes organizing maps so much nicer -- you can group them all at once and add or remove them based on what you load in the module tab. You can include larger maps in your campaigns and allow preloading over HTTP or FTP. Simply pack all of your images and maps, host the mod file somewhere and have others download and install it at their leisure.
Is there a guide for editing the XML?

I found that this (https://www.fantasygrounds.com/forums/showthread.php?14028-How-to-edit-mod-files)(FG forums) guide is the most descriptive. If you're interested in any editing or modding the wiki can also help. I find that reverse engineering other's work is the best way to learn.
It's not working!

Please copy a few lines of the error you're seeing and Google them before PMing or posting please


TODO

Merge with FantasyGrounded
Implement encounters.
Unify XML reading and production with FGrounded.


https://github.com/zacharyhooker/fantasygrounded

If any of you have any ideas or feedback, please let me know.

Bidmaron
January 1st, 2018, 18:28
Welcome to the boards, hooker! A very notable start with us!

I am a windows and python idiot, so where does your code shown get typed in?

This looks famously useful.

hooker
January 1st, 2018, 18:46
Bidmaron, you need to download the code from github. This link should work: https://github.com/zacharyhooker/FGModGen/archive/master.zip, then download Python 3 (I prefer 3.6) from here (https://www.python.org/downloads/release/python-360/)

In the github zip you'll see the basic structure of the data.

Open MapModuleGen.py in notepad or IDLE (comes with python) and scroll to the bottom.

You should see this:


x = ModuleGen('HMaps', author='Hooker', xmlout='hookermaps', libdir='hookermaps/maps')
x.genXML()
#x.zip()
x.zip('S:\Fantasy Grounds\Data\modules')

From here change the data in ModuleGen to your liking.



x = ModuleGen('HMaps', author='Hooker', xmlout='hookermaps', libdir='hookermaps/maps')

Where `HMaps` is what you want the name of your mod to be.
`xmlout` is the directory you want your XML stored (you can change it to whatever, but I'd keep it something small.
`libdir` is the directory your images are stored in.

The `xmlout` and `libdir` are relative directories though absolute should work.

For instance..


`x = ModuleGen('BidmaronMaps', author='Bidmaron', xmlout='C:/mystuff/bidmaronmaps', libdir='C:/mystuff/bidmaronmaps/maps')`


These directions should help. https://stackoverflow.com/questions/6513967/running-python-script-from-idle-on-windows-7-64-bit

Instead of creating a new one, open the python file in the github zip.

Cheers

Bidmaron
January 1st, 2018, 18:48
Thanks, hooker!

Bidmaron
January 1st, 2018, 18:49
Trenloe/MW, is there a place to put tools such as hooker's that are not ruleset dependent, or can we just save this in CoreRPG thread somewhere? This seems useful enough to warrant some kind of lasting link somewhere.

Trenloe
January 1st, 2018, 23:56
Being stickied in the workshop works. Which it is now.

Bidmaron
January 2nd, 2018, 02:55
Congrats, hooker. You made the big time.

hooker
February 14th, 2018, 00:50
I have updated the initial post and included a new project! I hope to merge the two together as I progress. Cheers.

mlesnews
February 18th, 2018, 06:08
hello hooker, I'm not sure I'm setting things up correctly. I pulled everything down with the github desktop client, installed latest version of python, and repointed x.zip path to where my FG lives.

https://i.imgur.com/fOZzgHx.png



I looked in ./phantasy/utis.py and changed what appeared to be a typo in line 1, lxml to xml

1. from xml import etree


Which changed the error to what you see below.

G:\Games\Fantasy Grounds\Data\fantasygrounded> python run.py
run.py
raceback (most recent call last):
File "run.py", line 19, in <module>
main()
File "run.py", line 14, in main
print(princes.metadata)
ttributeError: 'NoneType' object has no attribute 'metadata'

hooker
February 18th, 2018, 06:48
mlesnews -- whoops! I should have added the requirements.txt as part of the install. lxml isn't a typo you'll need to install lxml as well as a few other requirements.
I've added requirements.txt to both of the working repos.


There's 3 ways to solve this:


Git latest/redownload the repositories and then run
pip install -r requirements.txt in your local cmd/powershell.
If you don't feel like getting the latest code you can just run
pip install lxml
Or manually install lxml as per these (https://lxml.de/installation.html) directions.


Sorry for the confusion, let me know if you have any other issues.

mlesnews
February 18th, 2018, 20:02
https://i.imgur.com/8mFXDPG.png

hooker
February 18th, 2018, 22:23
That's probably because that example script is the one I'm using for my Princes of Apocalypse campaign. Please change the campaign init to use a campaign you have saved.

mlesnews
February 18th, 2018, 22:45
So what if I'm in multiple campaigns and playing multiple characters? How would I have it look through every campaign in the ./campaigns folder and backup every character?


run.py

from phantasy import datahelper
import pprint
import os

def main():
x = datahelper.DataHelper()
princes = None
print(__file__)
for campaign in x.campaigns:
if campaign.startswith('Princes'):
princes = x.getCampaign(campaign)
break
outdir = os.path.join(os.path.dirname(__file__), 'render')
pprint.pprint(princes.getAttribute('charsheet', {'name': 'Krug'}))
pprint.pprint(princes.getAttribute('feat', {'name': 'Great Weapon Master'}))
#princes.rD(princes.getAttr('charsheet', {'name': 'Krug'}), outdir)
return 0

if __name__ == "__main__":
main()

hooker
February 18th, 2018, 23:01
You'd want to loop through every campaign like it does now but don't check for the names. I don't have the time at the moment to write it out; but I believe in you!

mlesnews
February 18th, 2018, 23:54
I don't know python but would you please make any suggestions? Do I just need the two pprint lines? What is the significance of feat?


from phantasy import datahelper
import pprint
import os

def main():
x = datahelper.DataHelper()
mycampaign = None
print(__file__)
for campaign in x.campaigns:
mycampaign = x.getCampaign(campaign)
outdir = os.path.join(os.path.dirname(__file__))
pprint.pprint(mycampaign.getAttribute('charsheet') )
pprint.pprint(mycampaign.getAttribute('feat'))
# mycampaign.rD(mycampaign.getAttr('charsheet'), outdir)
return 0

if __name__ == "__main__":
main()

mlesnews
February 20th, 2018, 17:19
Question for you Bidmaron, were you able to get it to work where it created a module that you then loaded into Fantasy Grounds? If so, what did do or show? Thanks in advance.

hooker
February 20th, 2018, 19:07
I don't know python but would you please make any suggestions? Do I just need the two pprint lines? What is the significance of feat?
Sure, I've updated the project. If you would get latest you can now see that the run.py has been changed to backup all characters from all campaigns. (You can read the changelog if you want to know more about the new backup function)



Question for you Bidmaron, were you able to get it to work where it created a module that you then loaded into Fantasy Grounds? If so, what did do or show? Thanks in advance.
I know you're asking Bid, but I wanted to provide a few screenshots of what it looks like to make a module and what it looks like in game.

https://i.imgur.com/R4CkAJh.png
First you add all of the pictures that you want to make into a module into the image folder and setup your script to render from and zip to the correct locations.

Then you can freely load up or create a new campaign. Check the load modules tab.
https://i.imgur.com/PLsts9q.png

From there you can load the images from the Images & Maps tab from the group dropdown.
https://i.imgur.com/UGod9p1.png

Cheers!

Bidmaron
February 20th, 2018, 23:20
What he said!

mlesnews
February 21st, 2018, 02:12
Thanks guys, I'll update, run it and see what happens! Whoop, I'm excited!



from phantasy import datahelper
import pprint
import os

def main():
x = datahelper.DataHelper()
for title, campaign in x.campaigns.items():
outdir = os.path.join(os.path.dirname(__file__), 'render', title)
if not os.path.exists(outdir):
os.makedirs(outdir)
if 'Princes' in title:
characters = x.getCharacters(campaign)
for name, charsheet in characters.items():
outfile = os.path.join(outdir, name)
x.renderData(charsheet, outfile, campaign.metadata['db.xml'])

return 0

if __name__ == "__main__":
main()



When I run this, it doesn't even generate any output or errors. No mod file gets created. I suspect its because as I've highlighted in red in the codeblock, I do not have any campaigns that contain the word 'Princes' in it.


https://i.imgur.com/G6hPpu7.png

hooker
February 21st, 2018, 03:11
Yeah, if you don't have any campaigns with that in it you may want to remove it or change it to a campaign you have saved. I just add that for my testing purposes as I have a few campaigns and don't want to backup all characters for all campaigns.

Also I think you misunderstand the current separation between projects.

FGModGen is the code for generating a mod file based on data.

FantasyGrounded is a way to read and backup data from campaigns.

At some point I hope to merge the two, but currently they're separate.