Decoding TileDissectorMethod.jstmp from ProtoTilesPen - Minecraftian14/JShortyOutlet GitHub Wiki
Well... let's begin by having a look at what this example is...
{
"package": "mcxiv.dissector",
"name": "Create Dissector Method",
"identities": [
{
"name": "Create Dissector Method",
"regex": "\\n([ ]*createDissectorMethod\\(\"(\\w+)\"\\)([^;]+);)",
"template": {
"type": "lines",
"content": [
" /**",
"<< * @param PD:NAME PD:DOCS.>>",
" * @param fade If true, fades the image about the cuts by fadeLength.",
" * @param fadeLength The length by which the fade takes effect.",
" * @param raw If it's null, a new array is returned based on the original pixels taken in by the constructor. If it's not null, the effect os applied on this array.",
" * @param interpolator The interpolator to be used to fade the pixels.",
" * @param clone If true returns a completely new array and doesn't disturbs values in the given array (raw).",
" * @param deNull If true changes all null values to transparent colors.",
" * @return <<RD:DOCS>>",
" * The dimensions remain the same, ie, the remaining pixels are Null or Transparent.",
" */",
" public static Color[][] <<MN:NAME>>(<<int PD:NAME, >>boolean fade, int fadeLength, Color[][] raw, FloatFunction interpolator, boolean clone, boolean deNull) {",
" raw = arrayPreCheck(raw, clone);",
" <<VAR_WIN>>",
" <<VAR_HIN>>",
" <<VAR_WFL>>",
" <<VAR_HFL>>",
" <<VAR_WIN_2>>",
" <<VAR_HIN_2>>",
" <<VAR_WFL_2>>",
" <<VAR_HFL_2>>",
" <<VAR_EL>>",
"<< ArrUtil.retainByPredicate(raw, (x, y) -> CROP:EXPR);>>",
" if (fade) {",
"<< ArrUtil.fade(raw, interpolator, FADE:PARAMS);>>",
" }",
" if (deNull) ArrUtil.deNull(raw, Color.INVISIBLE);",
" return raw;",
" }"
]
}
}
],
"elements": [
{
"name": "Method Name",
"docs": "",
"tag": "MN",
"references": {
"NAME from PARENT": 2
}
},
{
"name": "Parameter Definition",
"docs": "",
"regex": "\\.parameter\\(\"(.*)\", ([^)]+)\\)",
"tag": "PD",
"references": {
"NAME": 1,
"DOCS": 2
}
},
{
"name": "Returns Definition",
"docs": "",
"regex": "\\.description\\(\"\"\"\\n[ ]+([^)]+)\\n[ ]*\"\"\"\\)",
"tag": "RD",
"references": {
"DOCS": 1
}
},
{
"name": "Crop Method Call",
"docs": "",
"regex": "\\.crop\\(([^)]+)\\)",
"tag": "CROP",
"references": {
"EXPR": 1
}
},
{
"name": "Fade Method Call",
"docs": "",
"regex": "\\.fade\\(([^)]+)\\)",
"tag": "FADE",
"references": {
"PARAMS": 1
}
}
],
"expressions": [
{
"name": "Width stored as an integer",
"regex": "w_in[^_]",
"tag": "VAR_WIN",
"expression": "int w_in = raw.length;"
},
{
"name": "Height stored as an integer",
"regex": "h_in[^_]",
"tag": "VAR_HIN",
"expression": "int h_in = raw[0].length;"
},
{
"name": "Width stored as a float",
"regex": "w_fl[^_]",
"tag": "VAR_WFL",
"expression": "float w_fl = raw.length;"
},
{
"name": "Height stored as a float",
"regex": "h_fl[^_]",
"tag": "VAR_HFL",
"expression": "float h_fl = raw[0].length;"
},
{
"name": "Half of Width stored as an integer",
"regex": "w_in_2",
"tag": "VAR_WIN_2",
"expression": "int w_in_2 = raw.length / 2;"
},
{
"name": "Half of Height stored as an integer",
"regex": "h_in_2",
"tag": "VAR_HIN_2",
"expression": "int h_in_2 = raw[0].length / 2;"
},
{
"name": "Half of Width stored as a float",
"regex": "w_fl_2",
"tag": "VAR_WFL_2",
"expression": "float w_fl_2 = raw.length / 2f;"
},
{
"name": "Half of Height stored as a float",
"regex": "h_fl_2",
"tag": "VAR_HFL_2",
"expression": "float h_fl_2 = raw[0].length / 2f;"
},
{
"name": "Effective Length",
"regex": "effectiveLength",
"tag": "VAR_EL",
"expression": "int effectiveLength = (int) (fadeLength * AppUtil.ROOT_2);"
}
],
"example": "..."
}
Okayyy that's quite a big chunk of mysterious code, but if you look at it after creating a few segments it's actually very easy and small.
Let's begin from the content
. It starts with a big chunk of JavaDocs as
/**,
<< * @param PD:NAME PD:DOCS.>>,
* @param fade If true...by fadeLength.,
* @param fadeLength T... takes effect.,
* @param raw If it's ...on this array.,
* @param interpolator...de the pixels.,
* @param clone If tru...n array (raw).,
* @param deNull If tr...parent colors.,
* @return <<RD:DOCS>>,
* The dimensions rema...r Transparent.,
*/",
Wow! There are actually just three references.
The first reference is << * @param PD:NAME PD:DOCS.>>
. If it repeats, it will copy " * @param "
every time, and pick a suitable replacement for PD:NAME
and PD:DOCS
.
To clean up this segment, let's assume PD:NAME
and PD:DOCS
are the arrays [A, B, C]
and [1, 2, 3]
Therefore, it will generate this:
* @param A 1.
* @param B 2.
* @param C 3.
About the last reference, ie, RD:DOCS
it doesn't necessarily repeats and does a simple job of inserting some text.
Next comes the method declaration segment:
" public static Color[][] <<MN:NAME>>(<<int PD:NAME, >>boolean fade, int fadeLength, Color[][] raw, FloatFunction interpolator, boolean clone, boolean deNull) {",
" raw = arrayPreCheck(raw, clone);",
" <<VAR_WIN>>",
" <<VAR_HIN>>",
" <<VAR_WFL>>",
" <<VAR_HFL>>",
" <<VAR_WIN_2>>",
" <<VAR_HIN_2>>",
" <<VAR_WFL_2>>",
" <<VAR_HFL_2>>",
" <<VAR_EL>>",
"<< ArrUtil.retainByPredicate(raw, (x, y) -> CROP:EXPR);>>",
" if (fade) {",
"<< ArrUtil.fade(raw, interpolator, FADE:PARAMS);>>",
" }",
" if (deNull) ArrUtil.deNull(raw, Color.INVISIBLE);",
" return raw;",
" }"
Okay, so to begin, wherever you are reading it, say out loud with me, "The heck!"
This place contains a lot of references. Let us first focus on only on the first line - the method signature defination.
Here we have a 2 variables, the MN:NAME
and PD:NAME
. MN:NAME
doesnt necessarily repeats, but PD:NAME
does. Proceeding with the assumption from before, we the code generated will be:
(Let MN:NAME
be [name]
)
public static Color[][] name(int A, int B, int C, boolean fade, int fadeLength, Color[][] raw, FloatFunction interpolator, boolean clone, boolean deNull) {
Easy right?
Next we have a bunch of Expressions
which will be replaced with some code only if they satisfy a condition. So there isnt much to discuss except explaining the expressions itself, which I'll cover soon.
Finally, the method ends with some fairly length references like << ArrUtil.retainByPredicate(raw, (x, y) -> CROP:EXPR);>>
.
But once again, they dont do anything super special except repeating the ArrUtil.retainByPredicate
part and replacing CROP:EXPR
for every element provided.
With this, I hope it gave a fairly good idea, what we really want to generate.
Just giving an example for one such final product:
/**
* @param h_abv """height_above: The height above the middle of original image to be summed with h_btw and be used as the height of the rectangle to be cropped.""".
* @param h_blw """height_below: The height below the middle of original image to be summed with h_abv and be used as the height of the rectangle to be cropped.""".
* @param fade If true, fades the image about the cuts by fadeLength.
* @param fadeLength The length by which the fade takes effect.
* @param raw If it's null, a new array is returned based on the original pixels taken in by the constructor. If it's not null, the effect os applied on this array.
* @param interpolator The interpolator to be used to fade the pixels.
* @param clone If true returns a completely new array and doesn't disturbs values in the given array (raw).
* @param deNull If true changes all null values to transparent colors.
* @return Returns the middle part of original pixels cropped like a rectangle with full width.
* The dimensions remain the same, ie, the remaining pixels are Null or Transparent.
*/
public static Color[][] getHorRect(int h_abv, int h_blw, boolean fade, int fadeLength, Color[][] raw, FloatFunction interpolator, boolean clone, boolean deNull) {
raw = arrayPreCheck(raw, clone);
int h_in = raw[0].length;
float h_fl = h_in;
int h_in_2 = (int) (h_fl / 2);
float h_fl_2 = h_fl / 2;
ArrUtil.retainByPredicate(raw, (x, y) -> y > h_fl_2 - h_abv - fadeLength && y < h_fl_2 + h_blw + fadeLength);
if (fade) {
ArrUtil.fade(raw, interpolator, 0, h_in_2 - h_abv, 0, h_in_2 - h_abv - fadeLength);
ArrUtil.fade(raw, interpolator, 0, h_in_2 + h_blw, 0, h_in_2 + h_blw + fadeLength);
}
if (deNull) ArrUtil.deNull(raw, Color.INVISIBLE);
return raw;
}
Now, before we discuss the regex for this identity, we need to clear up, how we would like to define all those variables as mentioned above.
Because I love Java, I will be creating a syntax similar to Java only. Let's go with this:
createDissectorMethod("nameOfTheMethod")
.parameter("h_abv", """some docs about param1""")
.parameter("h_blw", """some docs about param2""")
.description("""
A doc about what the method returns.
""")
.crop(y > h_fl_2 - h_abv - fadeLength && y < h_fl_2 + h_blw + fadeLength)
.fade(0, h_in_2 - h_abv, 0, h_in_2 - h_abv - fadeLength)
.fade(0, h_in_2 + h_blw, 0, h_in_2 + h_blw + fadeLength);
As you can see, h_abv
and h_blw
are two such parameters we define and h_abv_2
and h_blw_2
are their halves respectively.
Inside of crop
it's just a complicated boolean expression, we shouldnt be bothered about what exactly it is.
Similarly, inside of fade
we have a pair of coords given as 4 parameters. Once again, we can ignore what exactly it is.
What maters here is:
- Create more variables like
h_blw_2
only if required. - Feeding 1 boolean expression to
crop
. - Feeding 4 parameters to
fade
.
Let's first handle the regex for our identity. Note, that it shouldnt bother about the different method calls, we just need to grab this whole block.
\\n([ ]*createDissectorMethod\\(\"(\\w+)\"\\)([^;]+);)
Note, that \n is outside of the first regex group, therefore it wont be replaced: that is, everything inside of the first group will be replaced.
This regex starts simply by matching the method call, ie, createDissectorMethod and matches until a ;
is reached.
Here,
- Group 1 represents the whole method call.
- Parenthesis starts.
- Group 2 represents some word inside a pair of double quotes.
- Group 3 anything after group 2 until/except ;.
Thus the identity part ends here.
Next we should move on to elements.
TODO