[KDYv2] Development Blog Thread

By ThatRobHuman, in Star Wars: Armada

Progress since last night:

I've added the following content types to the API system:
- Damage Cards
- Defense Tokens
- Defense Token Types (Green/Red is an example of this)
- Damage Types (Crew vs Ship)
- Factions
- Keywords
- Objectives
- Objective Types (Assault, Defense, etc)
- Upgrade Flags ("modification" or "small ships only", etc)
- Upgrades
- Upgrade Types

Remaining Content Types
- Die Types
- Ships
- Squadrons
- Ships
- Stations
- Fleets
- Expansions

Not sure how I'm going to handle this yet...
- Misc Tokens
- Misc Cards
- Misc Card Types

Fleets and Expansions are going to need to wait until I have the rendering engine fleshed out. The reason for this is because I want to have the ability to have people select different looks/feel for each item they add to an expansion. For example, the Raider has an FFG Default version (rendered by renderer #1), the KDY classic version (rendered by renderer #2) and the FFG Alt Art version (rendered by renderer #3). Well, when you add the Raider to a fleet, you can choose which render version you want to use. It's purely an aesthetic thing, but something that will make the Tabletop Simulator thing a **** of a lot easier.

To do for tonight: The Renderer Engine.... once I get home from the commute.

Coding stream anyone? Gonna hang out and stream me working on KDYv2 some.

https://www.twitch.tv/the_foas

The rendering system is coming along really nicely. I've built my first (albeit very mininmal) Damage Card renderer through the API. Now to just flesh out more of them.... lots more of them.

Finally rendered my first card using the under-development API:

here's an example of the JSON request that defines the card renderer:

{
	"name":"KDY Classic",
	"width":"1.625in",
	"height":"2.5in",
	"bleed":"0.0625in",
	"node_obverse": {
            "node_class": "ROOT",
            "node_id": "mciy3YfbKnNXMF7K",
            "properties": {
                "anchor": "relative",
                "background": "#ffffffff",
                "height": "100%",
                "spacing": "collapse",
                "visibility": "1",
                "width": "100%"
            },
            "content": [
                {
                    "node_class": "PLATE",
                    "node_id": "h6UVkqZvP2uvAQpL",
                    "properties": {
                        "anchor": "absolute",
                        "background": "transparent",
                        "height": "100%",
                        "image_size_mode": "cover",
                        "visibility": "1",
                        "width": "100%"
                    },
                    "content": "YJPjFbIt"
                },
                {
                    "node_class": "CONTAINER",
                    "properties": {
                        "anchor": "absolute",
                        "background": "transparent",
                        "position_bottom": "<renderer.bleed>",
                        "position_left": "<renderer.bleed>",
                        "position_right": "<renderer.bleed>",
                        "position_top": "<renderer.bleed>",
                        "spacing": "collapse",
                        "visibility": "1"
                    },
                    "content": [
                        {
                            "node_class": "TEXT",
                            "properties": {
                                "align_y": "center",
                                "anchor": "absolute",
                                "background": "#ffffffff",
                                "border_color": "#000000ff",
                                "border_style": "solid",
                                "border_width": "1pt",
                                "corner": "3pt 50%",
                                "dropshadow_blur": "3pt",
                                "dropshadow_color": "#000000ff",
                                "dropshadow_y": "3pt",
                                "flow": "block",
                                "height": "0.25in",
                                "padding_top": "2pt",
                                "position_left": "0.0625in",
                                "position_right": "0.0625in",
                                "position_top": "0.0625in",
                                "spacing": "collapse",
                                "text_align": "center",
                                "text_font": "HE210HPU",
                                "text_size": "8.5pt",
                                "visibility": "1",
                                "text_variant":"smallcaps",
                                "innershadow_color":"#0003",
                                "innershadow_blur":"3pt"
                            },
                            "content": "<label>"
                        },
                        {
                            "node_class": "TEXT",
                            "node_id": "owsro7qMfxw2XFKr",
                            "properties": {
                                "anchor": "absolute",
                                "background": "#ffffffff",
                                "border_color": "#000000ff",
                                "border_style": "solid",
                                "border_width": "1pt",
                                "corner_bottomleft": "50% 3pt",
                                "corner_bottomright": "50% 3pt",
                                "dropshadow_blur": "3pt",
                                "dropshadow_color": "#000000ff",
                                "dropshadow_y": "3pt",
                                "margin_left": "3pt",
                                "margin_right": "3pt",
                                "padding":"2pt",
                                "padding_bottom": "4pt",
                                "position_bottom": "0.125in",
                                "position_left": "0.0625in",
                                "position_right": "0.0625in",
                                "position_top": "0.375in",
                                "spacing": "collapse",
                                "text_font": "dMMvRXsY",
                                "text_size": "7pt",
                                "visibility": "1",
                                "innershadow_color":"#0003",
                                "innershadow_blur":"3pt"
                            },
                            "content": "<text_body>"
                        },
                        {
                            "node_class": "TEXT",
                            "properties": {
                                "align_y": "center",
                                "anchor": "absolute",
                                "background": "#ffffffff",
                                "border_color": "#000000ff",
                                "border_style": "solid",
                                "border_width": "1pt",
                                "corner": "3pt 50%",
                                "dropshadow_blur": "3pt",
                                "dropshadow_color": "#000000ff",
                                "dropshadow_y": "3pt",
                                "flow": "block",
                                "height": "0.1875in",
                                "padding_top": "1pt",
                                "position_left": "0.0625in",
                                "width":"0.5in",
                                "position_bottom": "0.0625in",
                                "spacing": "collapse",
                                "text_align": "center",
                                "text_font": "HE210HPU",
                                "text_size": "8pt",
                                "visibility": "1",
                                "text_variant":"smallcaps",
                                "innershadow_color":"#0003",
                                "innershadow_blur":"3pt"
                            },
                            "content": "<type.label>"
                        }
                    ]
                }
            ]
        },
	"node_reverse":{
		"node_class": "ROOT",
        "properties": {
            "anchor": "relative",
            "background": "#ffffffff",
            "height": "100%",
            "spacing": "collapse",
            "visibility": "1",
            "width": "100%"
        },
        "content": [
        	{
                "node_class": "PLATE",
                "properties": {
                    "anchor": "absolute",
                    "background": "transparent",
                    "height": "100%",
                    "image_size_mode": "cover",
                    "visibility": "1",
                    "width": "100%"
                },
                "content": "vDKwOjjo"
            }
        ]
	}
}

and here's the result (bear in mind that I had to scale it down for showing-off purposes).

jCmODkq.jpg

Now, I manually created this renderer using a hard-coded request to the API, but part of the project will be creating an intuitive Front-End UI for the API, so you don't have to sit there and know how it all works.

Edited by FoaS

So.... how about that SSD

Good news:
KDYv2 is already planned to support more than Small, Medium, and Large bases (actually being able to support ANY custom base sizes for ships is already planned to be a thing).

Bad News:
I did not anticipate the ability to have more than four hull zones.

Good News:
I think I can figure out how to do it.

Bad News:
There's an element to the rendering system that I only just realized might be a problem. Suppose you have a upgrade - that upgrade has a primary type, say "Offensive Retrofit" - suppose you use the icon of that primary type on the upgrade card - as well you should. Now suppose you CHANGE that upgrade type's icon. Now the system not only has to re-render anything that uses that upgrade type, but any upgrade that references that type. Now the trick of this is that if you change the icon, I only want it to force a re-render of an upgrade ONLY IF that upgrade's renderer USES that icon (if you don't use that icon in your renderer, why waste cycles re-rendering something).

All things to figure out next.

Clean-slated.

Not really, just changed a good amount of the file structure and did some refactoring. Continuing to refactor. Ugh.

OH! and I upgraded my dev environment to PHP7, so v2 will run a lot faster.

Edited by FoaS

Completely overhauled error handling on the back end. The API will actually give you errors that are both human-readable as well as code-consumable codes that can enlighten a developer as to what was wrong with their user's input.

Wahoo!

I got the rendering system up and running perfectly. Now it's time to just flesh out what it can do.

So far, when one creates a Damage entry it renders a Damage Card (front and back), when one creates a faction, it renders a 3/4" token with that faction's logo. When one creates a Defense entry, it renders a Defense token - all with a structure defined by user input :3.

This is so awesome, guys.

Expanding the rendering endpoints - I'm almost done with being able to make an Objective card renderer via the API.

After that it's on to Upgrade Cards (that'll be fun) - the good news is that I've figured out how to best handle double upgrade types for the Reverse side of the card without rendering each and every combination that ever exists.

Objective rendering is almost done!

1534610157

Okay guys, I may need some help with this for any experienced programmers out there: I realized that my recursive regex to parse variables is way too expensive.

I need to write a tokenizer that parses a complex input into a specifically structured nested array.

Take a look at this input. It's a bunch of nested "function" calls that will get parsed by the API

FN.if(FN.or(FN.isBlank({var1}),FN.equals({var2},foo)),bar,baz)

For ease of viewing, I've split it out into a proper nested structure

FN.if(
	FN.or(
		FN.isBlank(
			{var1}
		),
		FN.equals(
			{var2},
			foo
		)
	),
bar,
baz
)

Now, this parser needs to return an array structured like this:

[
	function,
	if,
	[
		function,
		or,
		[
			function,
			isBlank,
			[
				variable,
				var1
			]
		],
		[
			function,
			equals,
			[
				variable,
				var2
			],
			[
				literal,
				foo
			]
		]
	],
	[
		literal,
		bar
	],
	[
		literal,
		baz
	]
]

I cannot use regex because there's no way to ensure proper balancing of parenthesis, for example.

... of course I would figure it out as soon a few hours after posting this...

All I need to do now is integrate it into the API system as a replacement to the recursive regex that I'm currently using - that means properly doing some proper error handling, too.

Don't forget to post the Patreon link.

;)

dangit - I keep forgetting....

Also that parser I wrote can go out the window, I'm afraid. It was really sloppy and is causing more issues (like, infinite loops) than the recursive regex parser. Back to the drawing board.

A preliminary version of the new parser has been written - should eliminate a lot of the crap code that I made for myself, but it will take a while to clean it all up. The parser touched a LOT of pieces of code.

After paring down the expression parser (which is actually a small modification to your Shunting Yard algorithm), I can now have the API accept a renderer definition in about 25% the time it took with the recursive regex parser. This is awesome.

Started on upgrade card renderers.

One of the main reasons why I've hesitated on working on this renderer is because it'll be the first time that I allow for what I'm calling an iterative render node. Basically, when you create an upgrade card, you can offer a list of Upgrade Flags that you (or someone else) will have previously defined, such as "Modification" or "Small Ships Only" - well, an upgrade card may have zero of these flags, or may have many. In order for them to show up on the upgrade card at render-time, you need to provide a special kind of node that will repeatedly render it's contents, once for each flag. I'll show an example once I get it coded up and working. The same logic will be applied to things like Squadron Keywords, or the Ship Upgrade bar.

There will also be support for a manual iterative node (that I'm calling a ValueLooper), which is how I'll be getting things like the Health value on the squadron renderer. When you create the node, you'll provide the Start Value, the End Value, and the Step value. It'll then iterate across those values, starting at Start, stepping each time, until the current value exceeds the End value. At each step it'll render the contents of the node with the Current value being accessible as a variable in the renderer nodes.

Chances are I will not be supporting nested ValueLooper nodes unless someone really has a need for it.

Edited by FoaS

I just got the BBCode tags working in the renderer system, so now I can wrap things in Bold, Italic or Emphasis tags as well as render icons, such as Hit Dice or Upgrade Type icons into a card. Upgrade Card rendering had to take a back seat today, as I really wanted to get the BBCode working so I can properly render an objective card - which is almost there. Need to add one or two new features to the renderer. For example, one thing that you'll be able to do is style your Bold, Italic and Emphasis tags to suit what you're looking for. Do you want squadron keywords in your upgrade card to show up as white text with a black background for contrast? You can do that by tweaking the tag properties in your renderer definition.

Poll time:

Common BBCode usage seems to be Bold, Italic, Underline, and sometimes Strikethrough. Right now I suppose Bold, Italic and Emphasis. (I make a distinction between emphasis and bold because I've found it useful to use smallcaps and a different font from Bold, which is very handy).

I'm on the fence about adding suppose for an Underline tag. Such a tag could be styled in any particular way you want, but would default to being the same as normal text, just with an underline, just as the Italic tag can be restyled to whatever you want, but defaults to being just an italic form of the text.

Should I add support for an Underline tag in addition to the existing Bold, Italic, and Emphasis tags?

Edited by FoaS

I know many people have requested the ability to add a unique flag to Ship cards, but can anyone give me a reason NOT to add the same flag to Objectives and Damage Cards? I don't know why you'd ever use it, except maybe for an objective that can only be played once in campaign, or a damage card that can only be applied once? Still - I'm inclined to give people the option if they REALLY want to...

Screw it, I did the thing! Objectives and Damage Cards can be marked as unique, just in case you really want it to.

Also, once I figure out how I want to add ship silhouettes, I might add those to Damage Cards, too, just in case you want to have a special damage deck for epic-scale ships (which may be a thing with the SSD?)

I've gotten so very close with the upgrade renderer, but it's made me realize something. I will probably need to write some kind of preview function for when people go to build renderers so that they can get live feedback rather than making guesses and potentially polluting the system.

The problem is that while rendering a piece of content in itself is not too expensive, because of the asynchronous system I put in place, parsing and defining a renderer does take a while. Imagine polling the API each time you make a change to a value and having to wait several seconds for it to show you what that will look like.

I think this means that I will need to rely on the front end to parse input and show a preview before it even touches the API. In effect, this means that I'll be writing all my renderers twice. Once in PHP for the API, and once in JavaScript for the front end.

This will be a problem for future Rob, rather than present Rob, but it will get very interesting. Doing a UI right is not always easy, but it's always better.

Upgrade rendering is done except for tweaking the positions of icons on the back.

Next up is Squadrons, which presents yet another fun thing to revisit: Die Types. I don't have an endpoint class defined for either one (squadrons or dietypes), so I'm going at it from scratch, but I've got a decent idea on how I want to take care of it. I expect that I'll be making decent headway on the Squadron class tomorrow, and then shift gears back to dietypes when it beomes necessary, then switch back to squadrons to build the renderer.

Hopefully, once squadrons are done, Stations and Ships will come easily... I hope...