RPTools "next" Git Repository

Thoughts, Help, Feature Requests, Bug Reports, Developing code for...

Moderators: dorpond, trevor, Azhrei

Forum rules
PLEASE don't post images of your entire desktop, attach entire campaign files when only a single file is needed, or generally act in some other anti-social behavior. :)
User avatar
JamzTheMan
Great Wyrm
Posts: 1872
Joined: Mon May 10, 2010 12:59 pm
Location: Chicagoland
Contact:

Re: RPTools "next" Git Repository

Post by JamzTheMan »

Azhrei wrote:
jfrazierjr wrote:
Vhex wrote:That does answer the question, thanks. I prefer editing files directly myself, rather than copy & paste is why I ask.
Yea.. I don't know yet and I don't know if Craig/Azhrei knows for sure at this point.
Joe's got it right. We don't know yet. :)

It would be nice to load a campaign, "export" the macros to a directory, and be able to do all of your edits there using your favorite editor (vim!). The campaign would keep track of the exported directory and automatically suck them back in when it's saved. MT would need to monitor the directory and filenames and automatically reload them when it sees a timestamp/file size change as well.

It might be possible to do editing and testing of macros without MT at all. If a browser environment could be made to resemble MT's operating environment, then tools like Firebug could greatly simplify JavaScript macro development. Consider a scenario where a user loads a "maptool.js" or "dicetool.js" file into a web page. That gives them a simulated framework that is 90% the same as running inside MT, thus allowing all of today's browser tools for debugging JS to be used.

This may be infeasible, it will depend on what features of MT are exported into the JS engine and how intricately those features are tied to the implementation of the macros...

Man, I'm totally psyched for coding macro's in JavaScript! Weee!

And ya, if we could run at least partially inside Chrome or something, that would be sweet as well just for the inspection/development aspect.

Lastly, PLEASE PLEASE PLEASE allow me to edit all my macro's outside of MapTool! What would be perfect is to put MT into a "Dev" mode where ALL the macro's, tables, etc exist as physical files locally (or via URL, ie includes of JS to an http url). And MT reads/refreshes live from those files. And when done, a "Production" or "Package" mode where those files are saved into the campaign files and used and contained.

Although, I'd like to be able to store my macros/scripts to the web, so if I need to make a change to a macro, maybe via an external .js file that is included via a URL, then my friends could just launch MT and have the latest code.

Currently, we have 3 GM's sharing a single MT campaign file. If I make changes to the "framework" they have to export/import maps. Anything that could help "decouple" the "framework" from the "working maps" would be awesome. In fact, if the "Framework" was a different file that was loaded (ie included in/by) the "campaign" file, that would be awesome.
-Jamz
____________________
Custom MapTool 1.4.x.x Fork: maptool.nerps.net
Custom TokenTool 2.0 Fork: tokentool.nerps.net
More information here: MapTool Nerps! Fork

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools "next" Git Repository

Post by Craig »

Vhex wrote:antlr 4 is out by the way.
I am going to file that information under "interesting, but not planning to do anything about that right now" :)
Although I haven't been able to find all the differences between 3 and 4 the descriptions make it sound like its quite different.

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools "next" Git Repository

Post by Craig »

wolph42 wrote:Ok, please treat me here as the biggest n00b in the area, a couple of questions:

Overall I have no clue what 'the new parser' would look like. The only thing I've picked up so far is what Craig mentions in the OPs:
- the parser will only check out [that what is found here]
Correct this is the same as what currently happens only the block of text in [ ] is evaluated (well also { } but I might appropriate that for a different use).
wolph42 wrote: - supports JS (to what extend?)
Say if you have [attack("SuperScaryMonster")] then the attack() function maps to a JavaScript code function using Rhino (may in future change to Nashorn) which is a full implementation of JavaScript. It wont have any of the browser based hooks since its not running in a browser, but it will have access to an API depending on what tool its running in (so it can fetch things like maps, tokens etc).
wolph42 wrote: - has additional features concerning dicerolls
While I am sure that someone will find a use for this in macros, its probably more useful outside of macros, say your playing a game that you roll a number of d6 to do damage and something extra happens if you roll a six and you don't really want to use macros to keep track of this, you can do [ 4d6! ] and get all the rolls displayed instead of just the result. Of course you could always create a macro count6s() you use like [count6s(4d6!)] that will format the result.
wolph42 wrote: - will (at least) require all existing script to mark out properties and variables with $ and @
- so what effect does that have on the current scrip?
a. will it still function
b. will it require 'some' change
c. can we throw it away and start anew
d. will co-exist with JS
e. wil be based on JS and thus every function needs to be rewritten
f. some combination of the above
Not sure what the difference between c) and e) are. But yes the story hasn't changed since the first discussions of the JavaScript macros long ago they wont be compatible with 1.3 macros, thats the bad news. The good news is that JavaScript macros will have a lot less idiosyncrasies (no 2 levels of braces limit, no stack size issues) there are also plenty of JavaScript tutorials and resources for learning, and it is a lot more flexible and faster. Generally there won't be much macro scritping within the [ ] it will mostly be within a JavaScript file, the challenge (well one of them) that I have is to make that as easy as possible for people to create them. Its a trade off, give up compatibility and gain a lot more functionality, or only break compatibility a little bit and really have no real ability to grow the macro language.

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools Git Repository

Post by Craig »

Azhrei wrote:
Better support for unicode so a much larger character set should work
Both " and ' can be used to enclose strings.
Hm. Doesn't Unicode have an entire class of characters that represent string delimiters? Is there any value in allowing all of them as delimiters?
None at all :) The two are enough, and less confusing for people.
Azhrei wrote: I'm primarily thinking of people writing code in an editor that replaces the quotes around a string with a left-open-quote and right-close-quote. When they copy/paste into a window they'll get errors. It would be nice if the parser could accept them instead.
Call me a snob if you want, but I will not be an enabler for those using Microsoft Word to do coding :)

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Re: RPTools Git Repository

Post by jfrazierjr »

Craig wrote: Call me a snob if you want, but I will not be an enabler for those using Microsoft Word to do coding :)
Here frakin here!!!
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools "next" Git Repository

Post by Craig »

JamzTheMan wrote:
Man, I'm totally psyched for coding macro's in JavaScript! Weee!

And ya, if we could run at least partially inside Chrome or something, that would be sweet as well just for the inspection/development aspect.
I have zero comments to make on that :)

JamzTheMan wrote: Although, I'd like to be able to store my macros/scripts to the web, so if I need to make a change to a macro, maybe via an external .js file that is included via a URL, then my friends could just launch MT and have the latest code.

Currently, we have 3 GM's sharing a single MT campaign file. If I make changes to the "framework" they have to export/import maps. Anything that could help "decouple" the "framework" from the "working maps" would be awesome. In fact, if the "Framework" was a different file that was loaded (ie included in/by) the "campaign" file, that would be awesome.
Its not likely that MapTool will fetch and run the JavaScript from the web for a variety of reasons.
1) what happens when the website of the scripts are using is down.
2) What happens when the author introduces a new incompatible version?

So its likely that JavaScript macros will always travel along with the rest of the campaign. Its also likely that there will be export/import functionality so you can edit in your favourite editor. There is also the possibility that you could import from a URL, which would mostly solve the problem you have without causing issues with people who still need an older version.

User avatar
Vhex
Giant
Posts: 162
Joined: Fri Sep 09, 2011 4:41 am
Location: Honolulu, HI

Re: RPTools "next" Git Repository

Post by Vhex »

The info on antlr 4 was just informational, I actually prefer (and still use) antlr 3. I haven't learned the syntax changes for antlr 4 and it's not backwards compatible, so for what I do I just haven't messed with it. Antlr3 means I can easily port it to netbeans for my editing =P

As far as the information on external items goes, I like the development/package model. It's currently a pain to edit macros and copy/paste them back in, even with the awesome RPTokExport. Having them stored in files and able to be "packaged" when testing is done is a great idea.

I do like a separate repository, but agree that it presents problems when the internet is down. Other software solves that with a check on startup (resort to previous if not available) but I can see how that would have issues with different people running different versions.

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: RPTools "next" Git Repository

Post by Azhrei »

Vhex wrote:The info on antlr 4 was just informational, I actually prefer (and still use) antlr 3. I haven't learned the syntax changes for antlr 4 and it's not backwards compatible, so for what I do I just haven't messed with it. Antlr3 means I can easily port it to netbeans for my editing =P
Well, I only made a cursory look at it, but it seems it's a lot more flexible in regards to what sort of grammar it will accept. And it generates the parse tree dynamically instead of having native code embedded in the static tree. This means it (a) benefits from JIT performance optimizations because there's more common code, and (b) is easier to debug as single-stepping the code doesn't step into the grammar source!

Personally I prefer the grammar style demonstrated in the v4 General FAQ page, but that's because I have years of experience developing such code using lex+yacc (ugh!).

Doesn't matter to me, though. :)

User avatar
Vhex
Giant
Posts: 162
Joined: Fri Sep 09, 2011 4:41 am
Location: Honolulu, HI

Re: RPTools "next" Git Repository

Post by Vhex »

Oh, don't get me wrong, I'll learn it eventually. My problem isn't with anything they've done, I like the core concepts and the design ideal that they went with. My problem is I can use Antlr 3 without a reference (mostly, unless I'm doing something obscure) and I can't do that with Antlr 4. I'm always for continuing progress, but sometimes I wish I could dump syntax into my brain Matrix style.

For a lexer/parser, it's more of a "I'm not gaining anything by switching right this minute" kind of thing. When I have a new project to do that includes it I'll definitely sit down and learn 4. Maybe. Definitely maybe. I hated yacc.

User avatar
JamzTheMan
Great Wyrm
Posts: 1872
Joined: Mon May 10, 2010 12:59 pm
Location: Chicagoland
Contact:

Re: RPTools "next" Git Repository

Post by JamzTheMan »

Craig wrote: So its likely that JavaScript macros will always travel along with the rest of the campaign. Its also likely that there will be export/import functionality so you can edit in your favourite editor. There is also the possibility that you could import from a URL, which would mostly solve the problem you have without causing issues with people who still need an older version.
I could live with an "import from URL". Or rather even, maybe something along the line of how Hero Labs/Army Builder updates work?

Basically, in Hero Labs, you can give people a URL to an xml file (ie http://www.somedomain.com/maptool/pathf ... mework.xml). This XML basically just has a list of files (in our case, .cmpgn or what ever format you allow for imports), as well as description, etc. So when you launch HL, it looks for updates, and alerts user if there are any. User can then click "import" to grab latest files and tells you what files get replaced, etc.

Basically, the biggest pain I suffer using MT is updating Frameworks or to some extents, drop-ins. Anything that decouples that process and makes it more modular/easier to update would be pure awesomesauce. I only mention it hear as macros are a big part of this and if the JavaScript was more modular, frameworks could be more broken down (ie someone works on statblock parsers where someone else concentrates on spells, etc).
-Jamz
____________________
Custom MapTool 1.4.x.x Fork: maptool.nerps.net
Custom TokenTool 2.0 Fork: tokentool.nerps.net
More information here: MapTool Nerps! Fork

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools "next" Git Repository

Post by Craig »

So I said that I would create a post with more details about the JavaScript functions etc. But I had to make sure I could add some JavaScript functions and get all of that working and due to the flu I wasn't able to get it out as quickly as I would have liked, but better late than never :)

So firstly what do the functions look like in the script (which from now on I will refer to as RPTools Script so no one thinks I am talking about JavaScript). All of the stuff described in this post works in the latest code in the git repository.

If you make it through the original post and this post you will probably notice that RPTools doesn't seem to have much in the way of looping, its not something that you have missed there isn't much. The intention is to push as much of the coding as possible down to the JavaScript level, RPTools is really only for really simple stuff. Anyway, onwards!

Either Java or JavaScript can export and make available functions to RPTools Script, I will really only detail the JavaScript definition of functions in this post as thats what most people are going to be more interested it, and to be honest the Java part is a lot more straight forward so if you can understand the JavaScript part looking at the Java exported functions in git its dead easy to see how to create a function.

To call a function with no parameters not surprisingly its something like the following

Code: Select all

[AttackRoll()]
Arguments can either be passed by position or by name (or a mixture as long as all the named parameters come after the non named parameters).

So for example if we had a function by the name of rollSomeDice(num, sides) that rolls a number of dice all of the following are equivalent.

Code: Select all

[rollSomeDice(2, 6)]
[rollSomeDice(2, sides: 6)]
[rollSomeDice(num: 2, sides: 6)]
[rollSomeDice(sides: 6, num: 2)]

The order of the named arguments in the call don't matter (otherwise there would not be much point in having named parameters).

To support this each JavaScript function that you write that will be exported will accept a single argument. This argument will be a JavaScript object that contains each of the parameters, so for the above say your JavaScript function was defined as

Code: Select all

function doRollSomeDice(args) {
Then inside the function args would look like

Code: Select all

{ 
    num: 2,
    sides: 6
}
Except of course it would be a JavaScript object not text. So you examine the arguments, roll the requisite number of dice and return the result. Thankfully the RPTools scripting engine takes care of conversions between the types it knows about and the types JavaScript knows about (in most cases anyway, there are sure to be some odd corner cases where you may have to tell JavaScript this is actually a number not the string "2" before returning it if it is inside a list or dictionary).

When exporting a function you will need to tell the scripting engine what parameters it accepts, the data types of these parameters, any default values the parameters may have and the return data type of the function. These are all defined in terms of the RPTools script type not the JavaScript type. When the function is called the engine will attempt to match up all the parameters and then convert the values to what is expected, so if you pass 1.4 to a function that expects and integer value it will be truncated to 1, the script engine is pretty aggressive about conversion so it will convert numbers to strings or even single values to a list to match the function definition. Likewise when the function returns a value the script will convert that value into the value it expects.


The conversion between types is detailed below.

Code: Select all

RPTools Script type                                        JavaScript Type
Long                                                           Number
Double                                                         Number
List                                                           JavaScript Array
Dictionary                                                     JavaScript Object
Boolean                                                        boolean
String                                                         String
Result                                                         Java Object (Result object)
Null                                                           null
Any
Null is mostly used when defining default values for function parameters, Any has no mapping in JavaScript and is only used to represent a function that can return any data type, in this case the engine will make a "best guess" at what type of value it is.

All parameters that do not have a default value are mandatory.
Probably the easiest way to show how to export a function is to write a JavaScript file that does just that.

We can export the doRollSomeDice() function with the following JavaScript code

Code: Select all

var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
The ExportedFunction() constructor expects the name of the function as it will be exported to RPTools script, the return data type and the name of the function in the JavaScript code (this cant be in a new scope it has to be in the main scope of the script ie an object method, but each script/group of scripts are run in a scope of its own). All of this would go in the same script so for our first go

Code: Select all

function doRollSomeDice(args) {
    var times = args.num;
    var sides = args.sides;

    var res = 0;
    while (times--) {
        res += rand(sides);
    }

    return res;
}

var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
The rand() function returns a number between 1 and its argument (and will be improved with a proper random function in the near future).
And this works for the example calls at the top of the script, but it has a problem we want to be able to just roll a single dice with either of the following

Code: Select all

[rollSomeDice(sides: 6)]
But doing either of these will give us an error as num is not provided to the function. To allow for this we can add a default parameter to num of 1.

Code: Select all

function doRollSomeDice(args) {
    var times = args.num;
    var sides = args.sides;

    var res = 0;
    while (times--) {
        res += rand(sides);
    }

    return res;
}

var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG, 1);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
Now the above will work, but it could be better, after all it only returns a number what if we also want to know what the rolls were (for tool tips or what have you). You can do this by returning a Result which contains a value, a detailed explanation (e.g. "2 + 4" as a string) and a list of the individual rolls.

Code: Select all

function doRollSomeDice(args) {
    var times = args.num;
    var sides = args.sides;

    var res = 0;
    var ivals = [];
    while (times--) {
        var roll = rand(sides);
        res += roll;
        ivals.push(roll);
    }

    var details = arrayAsString(ivals, " + ");

    return new Result().setValue(res).setDetails(details).setIndividualValues(ivals);
}

var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_RESULT, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG, 1);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc;

The arrayAsString() function above will just format the array as a string with the provided delimiter (so something like "1 + 4").

You could also return the following

Code: Select all

    return { value: res, details: details, individual: ivals };

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: RPTools "next" Git Repository

Post by Craig »

You can also define parameters that consume all extra arguments. You can have a parameter that consumes all extra non named arguments as a list, or a parameter that consumes all extra named arguments as a dictionary (either one or the other not both), it must be the last parameter in the parameter list. To understand how you
can use them the list() function takes multiple values and returns a list
e.g.

Code: Select all

[list(1,4,6,7,8,8,9)]
The dict() function takes multiple named arguments and returns them as a dictionary type.
e.g.

Code: Select all

[dict(name: ScaryMonster, level: 10, hitPoints: 60)]
The lists and dictionary are analogous to json arrays and json objects in the 1.3 scripting language although significantly faster for lookups as there will be no need to convert to/from strings. Properties should also be faster for the same reason.

The next steps that I need to tackle are dice roll functions (and specifying dice roll patterns) as well as exporting an API between JavaScript scripts that have been loaded so that people can write reusable libraries, and probably more built in functions.

User avatar
JML
Dragon
Posts: 515
Joined: Mon May 31, 2010 7:03 am
Location: Blagnac, France

Re: RPTools "next" Git Repository

Post by JML »

Thanks a lot for keeping us informed. It's really exiting to see things progressing. Thank you for the hard work.

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: RPTools "next" Git Repository

Post by Azhrei »

Are the parameters passed by value or by reference? In particular I'm wondering about the JS Array and JS Object types. I noticed that you used var times = args.num; in your sample code and then decremented times; does this imply pass by reference and a desire not to modify the original? :?

And is there a particular reason for the Result type? It seems that a JS Object could suffice so I'm thinking there must be a particular reason regarding type coercion or maybe some feature of the RPTools Script?

Cool stuff, Craig. :)

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Re: RPTools "next" Git Repository

Post by jfrazierjr »

Azhrei wrote:Are the parameters passed by value or by reference? In particular I'm wondering about the JS Array and JS Object types. I noticed that you used var times = args.num; in your sample code and then decremented times; does this imply pass by reference and a desire not to modify the original? :?
Well... everything in javascript is pass by value(sort of). In this case, "args.num" is an object which is "unboxed"(so to speak) back into it's primitive type, so modifying "timer" does not actually do anything to "args.num". I am not 100% sure, but I believe that if args was a TRUE object in the calling scope being passed in, then any change to "args.num" would persist, but any variable derived from it (such as times in "var times = args.num") is a copy of the original value.

Azhrei wrote: And is there a particular reason for the Result type? It seems that a JS Object could suffice so I'm thinking there must be a particular reason regarding type coercion or maybe some feature of the RPTools Script?
Yes, since javascript(and most other languages that are not Perl.... 8) ) only allow a single return value from method/function calls, so the Result object is the way to package up all of the details you might be interested in knowing. This is critical for DiceTool but in some cases could be important for MapTool as well. This really needs to be a typed object for consistency. The current parser returns a "Result" object with two properties, the new one is just adding an additional one(or more???) so we have access to even more information(with a "default" toString() method showing the .result for example) and the let people who really want to get details have access to it. My HOPE is that everyone who writes rollers would always return a Result object cause if not, the additional information is lost... This will then let the consumer utilize the format he wants instead of the format the function writer assumed everyone wanted. This also will help prevent(hopefully) splintering.... why should there be two different (or more!!!) functions to say roll XdY with the only difference being one will return the values summed and the other returning each individual roll result...

As a simple example,

Code: Select all

var rollResult = doRollSomeDice(num: 4, sides: 6)
"Total:" + rollResult.result
"Details:" +  rollResult.details
"Values:" + rollResult.values
Would print something like this:
Total:18
Details:5 + 4 + 3 + 6
Values:[5, 4, 3, 6]
The above is just a quick example since I have not grabbed the code yet so this may not be exactly right.
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

Post Reply

Return to “MapTool”