Showing posts with label psthar. Show all posts
Showing posts with label psthar. Show all posts

Saturday, November 3, 2018

Writing PSThar scripts that compile C# code

PowerShell run scripts inside the PSThar extension for Abiathar automatically have access to Abiathar/FleexCore2 features. But if that PowerShell code tries to use Add-Type to compile and run C# code, it may encounter errors about not being able to find a type or namespace. The solution is to provide the three Abiathar assemblies to Add-Type:
Add-Type $code -ReferencedAssemblies ([Abiathar.Interop.IAbiatharState].Assembly, [FMod.GalaxyLevels].Assembly, $Abiathar.GetType().Assembly)

For most operations, only the first assembly (the Abiathar extension API) should be necessary. The second is FleexCore2, which is needed if using that directly instead of through Abiathar's API. The Abiathar assembly itself shouldn't usually need to be referenced; relying on internal details will lead to fragile scripts.

Tuesday, July 31, 2018

PSThar's ForEach-LevelTile command creates a new scope

I noticed while writing PSThar scripts, most recently this one, that the ForEach-LevelTile cmdlet (abbreviated %t) has different scoping behavior than the normal PowerShell ForEach-Object (abbreviated %). The script block that runs for each level tile is more of a distinct scope from the parent than is the script block run for each object by %. Using variables from outside the %t block in the block pretty much requires explicitly scoping those variables with script: every time they're mentioned, otherwise the variable name inside the block doesn't refer to the variable of the same name outside the block. This is very inconvenient and I will look into tweaking PSThar to fix it.

Saturday, May 26, 2018

PSThar - v1.2

I was hoping to add Simultaneous Tileset support to PSThar so it could set both $CurLevel and $CurTileset in the same console, but in the interest of getting the other new features out to users as soon as possible, I decided to release what I have as v1.2. The only change I didn't mention yet was that, to make it clear which mode the console was opened in, "Level" or "Tileset" is added to the caption of the console window as appropriate.

Friday, May 25, 2018

PSThar - Tileset support

One user was running a PSThar script to migrate some tile properties. She noticed that the PSThar console wouldn't open when only a tile palette was visible, which is to be expected since PSThar gets registered as a level tool. I definitely see how that could be inconvenient, though. So today I made PSThar also register a tileset tool, called with the same hotkey. When the console is started on a tileset, a $CurTileset variable is set instead of $CurLevel.

Wednesday, May 16, 2018

PSThar - v1.1

Over a year ago, I released PSThar, an Abiathar extension that embeds a PowerShell runspace in the Abiathar process to allow scripting of the editor. A week or so after the release, I added the ForEach-LevelTile cmdlet, a convenient shortcut for iterating over every tile in a level. I realized yesterday while writing some scripts for a user that I never released the new version. So today I bumped the version to v1.1, filled in the "long description" metadata field that I had missed before, and published the new AEX.

Monday, March 27, 2017

PSThar - ForEach-LevelTile

I've noticed that a lot of the PSThar scripts I write involve looping through every single point in a level. Doing that in plain PowerShell is kind of a mess, involving either a select -pv plus a % or a C-style loop.

So today, I added a new cmdlet: ForEach-LevelTile. It takes either a level ID or a level wrapper plus a script block. It then executes the script block for every (x, y) coordinate in the level, setting the $x and $y variables (or variables by other names specified in optional parameters) as appropriate.

For convenience, I aliased %t to this cmdlet, like how plain % is ForEach-Object.

Sunday, March 19, 2017

Using PSThar to convert levels from MapTemp to GameMaps

Today I had a chance to demonstrate PSThar in a practical way. For reasons that will become clear in time, a PCKF member needed to convert a TED5-style MAPTEMP file to the Carmackized usable GAMEMAPS version. One approach would have been to write a small console program to load one format and save in the other. Or, Abiathar could open the old format, export a bunch of ASLEVs, then load them into a project file using the new format.

Since PSThar has access to all Abiathar internals and the two formats use the same class in FleexCore 2, the easiest approach - which I ended up using - was to whack the MapType value of the file configuration to Carmack by script, then do a normal save to write out the maps with the new format.

$fc = $Abiathar.FileConfig['Core']
$fc.MapType = 'Carmack'
$fc.MapFiles.GameMaps = 'GAMEMAPS.CK4'

Note that this simple technique wouldn't work for other level format conversions, since Huffman maps and MapTemp/MapTHead maps are processed by different classes. For those, the GalaxyLevel objects would need to be transplanted into a different level set object of the appropriate type.

Saturday, March 4, 2017

PSThar - Selected tile cmdlets

Today I implemented a simple pair of cmdlets for PSThar: Get-SelectedTile and Set-SelectedTile. Each takes either a plane number (0 to 2) or one of three switches (e.g. -Background). The setter version, of course, takes a new tile ID to place in the appropriate selected tile bay. It also performs the bookkeeping task of sending a "selected tile changed" notification.

Friday, March 3, 2017

PSThar - Set-TileProperties

Today I wrote the Set-TileProperties cmdlet for PSThar. As expected, it was much more interesting than Get-TileProperties, mostly because I wanted to have it accept a PSThar tileinfo object of the type appropriate for the tile's plane. (There's one class for background tiles and another for foreground tiles.) One field - and therefore one parameter - can't have two different types, so I learned about dynamic parameters. The -Properties switch changes type depending on whether -Background or -Foreground was supplied.

When setting the new tileinfo on the tile, individual properties can come from different sources; it would be inconvenient to make the user supply every single aspect of the tileinfo every time. Individual switches have the highest precedence, then the property is taken from the tileinfo object if it's supplied, and the property currently on the tile is a fallback.

Thursday, March 2, 2017

PSThar - Get-TileProperties

My goal with the predefined PSThar cmdlets is to provide easier access to the project than is afforded by the normal API. Mostly, that means handling the boring bookkeeping for the user. I already made a getter and setter for level tiles; today I started the pair for tile properties.

So as to not force extensions to take a dependency on FleexCore 2 (FMod), Abiathar translates tileinfo entries to ULongs and provides some helper methods to reconstitute the meaning from those numbers. Those aren't super easy to work with from script, so I made a class with a bunch of read-only properties to represent the tileinfo for a single tile. Get-TileProperties takes a -Background or -Foreground switch, plus a tile ID, and returns one of those objects. My plan for the setter is to give it a bunch of optional switches to alter one or more parts of a tile's tileinfo.

I also noticed that calling $Abiathar.ViewState.RerenderSelTiles() does nothing from script because the pipeline is run on a different thread than the main form's UI. To fix that, I added the call to the method on the PSThar form that cleans up after script completion.

Monday, February 20, 2017

PSThar - All the output streams

People make mistakes and scripts encounter errors, and previously there was no convenient way to get the errors out of a PSThar script. If something bad happened, you'd probably get no output and you'd need to run $error to see what the problem is.

So today, I added a dropdown in the lower left that lets you choose which output you'd like to see in the results pane: normal output, errors, warnings, information, or verbosity. At the completion of a script, the view is automatically moved to the first of those that actually has anything to say.

I also noticed today that entering invalid syntax caused the window to stay as if a script was executing, except that the Stop Script button did nothing. The problem was that syntax errors throw an exception in the Invoke call, which killed the thread that was supposed to compute and report the results. Those exceptions are now caught and handled appropriately.

Sunday, February 19, 2017

PSThar - Asynchronous execution and more

I made a few interesting additions to PSThar today. The first order of business was to make the scripts execute on a different thread so they could be stopped if they ran long or got into an infinite loop. While a script is running, the Run Script button changes into Stop Script and the other controls are disabled.

Since users probably wouldn't appreciate getting a deluge of single-tile undo entries from a single script, I made PSThar inspect the undo stack and roll up the actions caused by the script into a single entry that can be undone and redone with a single keystroke.

Finally, I wrote a Get-Level cmdlet that gets level wrappers by ID or name, or just gets them all if no parameters are specified.

Saturday, February 18, 2017

PSThar - Set-LevelTile cmdlet

There are several steps necessary to correctly change a tile from the Abiathar API. First the tile in the level itself has to be set, then the render planes need to be notified of the change, then the undo stack has to be updated. If not all of those three things go together, bizarre behavior will result. That's too much for every scripter to remember and implement correctly all the time, so I wrote up a Set-LevelTile cmdlet for PSThar that takes care of all the details.

That was slightly trickier than expected because there's no way to get the ID of a given level wrapper without using reflection and scanning through all the current levels. That API oversight is usually mitigated by tools' easy access to the current level ID, but PSThar scripts can affect any level. I used the reflection strategy here, but I'll try to figure out some nice new API feature so other extension authors don't have to.

Tuesday, February 14, 2017

PSThar: PowerShell for Abiathar

Several times, I have wished I could just make a little one-time change to Abiathar's state without editing the main code or taking the time to write a full extension. So yesterday, I made a little extension that allows me to do just that. PSThar embeds PowerShell in Abiathar, allowing user scripts to interact with the same object model that extensions do. The state manager is provided in the $Abiathar variable. It's currently extremely easy to corrupt Abiathar's bookkeeping by not using the API right, so I might create some cmdlets to handle that for the user.

Getting the names of all levels