Friday, March 31, 2017

Policy Plus - Attribution for icons

I noticed while putting together some materials for the upcoming Tech Fair that the FamFamFam "Silk" icons that everyone uses everywhere are under the Creative Commons Attribution 2.5 license, which means there should be a note and a link to the author's site accompanying uses of them. To comply with licensing and generally be a good Internet citizen, I added an attribution document to the Policy Plus repository with the appropriate information. I also linked to the Microsoft documents that were very helpful in writing the ADMX/ADML/CMTX loaders.

Thursday, March 30, 2017

Policy Plus - Documentation

I plan to enter Policy Plus into a "tech fair" at my school, and the judging criteria seem to want documentation and explanation usable by non-programmers. I have noticed that the project involves a lot of terms that might not be intuitively obvious to users, so today I wrote a "lexicon" page that defines the phrases that can be found in the UI and in my other writings about the program.

When I look at other people's open-source projects, I usually have trouble finding where in the codebase a particular feature is implemented. Though Policy Plus is pretty small, it would be nice for new contributors - or non-programmers trying to understand its architecture - to see a brief summary of what each file does and how they interact. So I wrote a "components" page that lists just that.

Neither of these documents are currently online, since I'm still thinking about how best to organize non-code in the repository.

Wednesday, March 29, 2017

FMod - Another tileinfo inspection check

A few days ago while helping a PCKF user fix his NetKeen level, I noticed a type of tileinfo error that Abiathar doesn't detect. If a tile automatically animates (i.e. has both a delay and an offset) to a tile that does not automatically animate, the game will freeze after the first animation occurs. Today I adjusted the Tile Property Modifier's inspection mode to scan for this issue. I also adjusted some other warnings' wordings for consistency.

Tuesday, March 28, 2017

Super User moderator election 2017

Super User held its fourth moderator election this month, with exactly one seat open. I like helping keep Super User clean, and moderators have a lot of tools that do that, so I ran.

Results came out today. As expected, DavidPostill won - he has a ton of activity in all aspects of the site, and his victory is well deserved. I (Ben N) came in second, though! I'm very happy with that; it was an honor to be in the same race, and second is the highest I can get without having to actually do any of the work, heh. The third-place candidate was music2myear, who has also been a prolific contributor. In all, the race had eight candidates.

Each voter ranks their top three choices in order of preference, but that didn't really come into play this time because David flew by the threshold, so no vote transference had to occur.

Interesting fact: the most common ballots (descending order of preference) were:

  1. DavidPostill, Ben N, music2myear (612 instances)
  2. DavidPostill, music2myear, Ben N (230)
  3. Ben N, DavidPostill, music2myear (95)
  4. music2myear, DavidPostill, Ben N (75)
  5. music2myear, Ben N, DavidPostill (62)
  6. DavidPostill, other slots blank (55)
  7. Ben N, music2myear, DavidPostill (50)
  8. DavidPostill, Ben N, last slot blank (39)
  9. DavidPostill, Ben N, td512 (22)
  10. DavidPostill, Ben N, nicorellius (21)
  11. Ben N, DavidPostill, djsmiley2k (13)
  12. Ben N, DavidPostill, nicorellius (12)
  13. Ben N, other slots blank (11)
  14. DavidPostill, Ben N, djsmiley2k (11)
  15. Ben N, DavidPostill, last slot blank (10)
There were 106 completely unique (i.e. appearing only once) ballots. DavidPostill appeared (in any position) on 1602 of the 1887 ballots; I appeared on 1502 ballots. David had 1139 of the first-choice votes, easily passing the threshold of 944. I had 288 first-choice votes and music2myear was close behind with 237.

Congratulations, DavidPostill!

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 26, 2017

FMod - No more ArrayStream

Apparently when I wrote the first version of Abiathar, I didn't know that the MemoryStream class is perfectly capable of being initialized from a byte array. Abiathar has - almost from the very beginning - had an ArrayStream class that wraps a byte array so I can use embedded resources with the same interface as files. The disadvantage is that my code is almost certainly not as optimized as the Framework's (especially in the memory consumption area), so there's absolutely no reason to not be using MemoryStream.

So today, I deleted the ArrayStream class and replaced all uses of it with MemoryStream. Everything works perfectly fine.

Saturday, March 25, 2017

FMod - v2.8.8

Yesterday I released Abiathar v2.8.8, which fixes a couple little things:

  • Generating patches no longer crashes when the patcher program is absent from the output directory.
  • The event bus is faster, since it doesn't have to search all extensions for event handlers every time.
I also eradicated a lot of IIf usages from the codebase in favor of the inline If structure, which doesn't involve a function call and doesn't do unnecessary boxing.

Friday, March 24, 2017

Policy Plus - Show the current policy sources

With Policy Plus's relatively new ability to remember and automatically load the last policy sources, it's pretty important that the user see clearly what the current sources are. The Open Policy Resources dialog configures itself appropriately, but it takes some extra effort and mindfulness to open that before starting to fiddle around with policies.

So today, I added a status bar to the main form that shows the loader information for both policy sources. While working on that, I also found a bug in the Open Policy Resources dialog that caused the "scratch space" option to be restored as the POL file option.

Note the status strip at the bottom
These changes are live on GitHub.

Thursday, March 23, 2017

Device installation restrictions only work on not-yet-installed devices

I was helping someone tweak the Registry to configure device installation restrictions and we hit a snag. Even though the Registry settings were exactly as they should have been, the restricted devices were not disallowed, even on Pro editions where the Group Policy infrastructure is definitely there.

Eventually I found this Microsoft guide that mentions that devices should be uninstalled for these restrictions to work reliably. As the question author discovered, the devices' drivers don't have to be removed, but the devices themselves definitely should. The restrictions only take effect at install time, not plug-in time.

Wednesday, March 22, 2017

FMod - Event bus could be optimized

While looking through Abiathar's code, I noticed that the old event bus system (which has been there forever) could be a lot more efficient than it is. Currently, whenever an event is fired - a moderately common occurrence - Abiathar scans all methods on all loaded extension objects to see if the type signature matches. Reflection isn't the fastest thing, and the stops for the event bus will never change, so a better approach would be to scan for stops after loading all extensions, then run through that list whenever a bus should be driven. Alternatively, using the normal .NET event method would be far simpler, but changing to that now would break all existing extensions.

Tuesday, March 21, 2017

What the ~$ Office files are actually used for

When you open an Office document, a small hidden file is created in the directory. It's named the same as the document, but with ~$ overwriting the first two characters. One might wonder why the Office programs bother doing that.

The answer, as included in this old Microsoft article, is that these little files are there so Office can tell you who's responsible for the file being in use. When a document is opened, Office notes the current user's display name into this file. When another Office instance tries to open the file but receives an error that the file is in use, it looks in the squiggly dollar file to report the human-readable name of the person who's holding the lock.

The advantage of knowing that fact is that users in an office trying to edit a file on a network share can go to the specific person and ask them to maybe finish working with the document.

Based on my Super User answer.

Monday, March 20, 2017

FMod - Patch generation crash bug

A PCKF user reported a crash bug when generating patches for a Keen Dreams level set. I investigated and found that the bug affects all project templates. The crash happens when Abiathar tries to compare the size of an existing patcher program to that of the newest one. Due to a logic error, that procedure is attempted even when the patcher program isn't on disk at all yet. The problem can be worked around by dumping out the right program with the File Emitter, but I'll definitely get this corrected swiftly.

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.

Thursday, March 16, 2017

Markeen - Enjoy this art

At the request of some PCKF members, I generated some more levels with Markeen for art purposes.

This album features levels from all three Galaxy engine games. All three profiles were generated with a profile depth of 2. The profiles were unedited except for Keen 6's, in which I manually banned the inner blue platform tile from being next to air. I had Markeen make 50 levels from each game; I selected the ones that looked the most interesting. Keen 4 is kind of a disaster since it's so open, but the others went reasonably well, Keen 5 most so.

Tuesday, March 14, 2017

AbiathRPC - Last-minute bug fixes

In anticipation of the first release of AbiathRPC today, I did some quick testing to make sure everything worked. To my surprise, I found a few rather serious problems:

  • Connecting could fail across a network with a security-related exception. I set the security mode to "none," which is what it should have been all along.
  • Any operation that replaced a level crashed all connected clients if and only if there was more than one person online at the time. Somehow this was caused by an attempted call to a nonexistent method, though I don't understand why it only caused problems when there were other users available. Fixing the call definitely fixed the problem.
  • Changes to foreground tileinfo always wiped away that tile's foreground-specific properties on all machines except the source. A numeric typo caused this by always making an important conversion step get skipped.
I also noticed that I had forgotten to update the server to use the new VeriMaps certificate repository; that was an easy change. After all of that and a bit more testing, I released AbiathRPC 1.0 for Keen Day 2017.

Monday, March 13, 2017

AbiathRPC - Little touches

I plan to release the first version of AbiathRPC tomorrow (Keen Day 2017). To get it ready for the unveiling, I made a couple small tweaks.

Since undo/redo doesn't work for remote level sets, it doesn't really make sense to have the Undo and Redo menu items appear enabled. Those are now disabled.

It could be useful for server operators to have the IP addresses of connecting clients logged. I added a bit to the sign-on procedure to record that in the "User connects" log entry along with the IP address.

Sunday, March 12, 2017

Checking the display encoding of a web page

Someone asked how to see the encoding Chrome is using to display a page. The poster already found the various indications a server can provide, but sometimes there is no such information supplied with the page.

Fortunately, JavaScript can tell the encoding that the page is actually being rendered with. Just run this in the console:

document.characterSet

Saturday, March 11, 2017

Copying the ACL from one securable object to another

Today I tried to copy the access control list from one securable object to another by calling GetAccessControl on the source and supplying that object to SetAccessControl on the destination. PowerShell printed no errors, but it didn't work - the ACL was not updated on the target.

Instead, I needed to get the binary form of the source's ACL and set that as the binary form of the destination's ACL. That can be done with GetSecurityDescriptorBinaryForm and SetSecurityDescriptorBinaryForm, respectively. Actually saving the altered ACL to the object seems to always require SeRestorePrivilege enabled, even if the owner isn't actually changed.

Friday, March 10, 2017

Installing Windows from a running Windows without booting into setup

A while back, I needed to set up a dual-boot configuration between two different Windows versions, but for whatever reason, the WinPE setup environment refused to continue no matter what physical installation medium I used. So, I decided to do my own setup with dism.

First, I created an NTFS partition on the drive with the normal Disk Management snap-in. Then, using the install.wim file off the installation media for the new OS, I ran this command:

dism /Apply-Image /ImageFile:install.wim /ApplyDir:F:\

Once that command completed, all the files were in place for the new OS, but it had no entry in the boot configuration. It's probably possible to manually fiddle it into existence with bcdedit, but fortunately Windows comes with another helpful tool:

bcdboot f:\windows /addlast

To update the default boot option, you can use the /default switch of bcdedit. After I did all that, the new OS was successfully bootable and continued its installation experience as if I had used the normal setup.

Caution: The final system did seem to be light on drivers; it didn't recognize my network card. Then again, maybe a standard install would have done the same? I was able to grab some drivers off of the previously existing system's partition, fortunately.

Thursday, March 9, 2017

Active partitions are not needed for EFI-based Windows boots

If you look around Disk Management or DiskPart on an older Window system, you'll probably find mentions of a partition being "active." An active partition is needed to boot the machine using the old boot method. It is not necessary, however, using EFI boot. In Windows, a GPT disk almost always goes along with EFI boot. The EFI System Partition contains the critical boot information. Therefore, it's unnecessary - and, in fact, not possible - to set an active partition on a GPT drive with Windows disk management tools.

You can check whether your current boot configuration is EFI with the bcdedit /enum command. If the output's Windows Boot Manager section references .efi files or an EFI folder, the boot is EFI-based.

Based on my Super User answer.

Wednesday, March 8, 2017

Applying an image as an alpha mask in Paint.NET

Suppose you have a grayscale image that you want to use to control the alpha (i.e. opacity) of another image. Paint.NET doesn't seem to have a blend mode that does this. "Screen" is somewhat close, but the mask still shows up.

Somebody wrote a Paint.NET extension to accomplish this task: Alpha Mask. Place that DLL in this directory so Paint.NET will load it:

C:\Program Files\paint.net\Effects

It adds an "Alpha Mask" menu item under the Effects menu. Using that item opens a dialog that allows you to control the masking. You can invert the mask (by default, white means completely solid), conserve existing transparency, and switch between the clipboard and a file for the mask source.

Based on my Super User answer.

Tuesday, March 7, 2017

Viewing the MFT size on any modern Windows version

On Windows 10, you can get a lot of neat information about any given file's disk layout with this command:

fsutil volume filelayout c:\path\to\file.ext

The data size is reported in the Size row of the ::$DATA stream's section. That even works on the $MFT file (the Master File Table) for the volume. Unfortunately, the filelayout subcommand doesn't exist on older versions of Windows.

On earlier versions, the MFT size is reported with the general NTFS information:

fsutil fsinfo ntfsinfo c:

Look for the Mft Valid Data Length line. The value is the hexadecimal number of bytes.

Based on my Super User answer.

Monday, March 6, 2017

AbiathRPC - Tileinfo download

Yesterday I added full tileinfo support to AbiathRPC, minus support for it in the Download Levels feature. Today I filled in that gap. Since downloading the project might now get more than just levels, the menu has been renamed to simply Download. If and only if the current server has tileinfo, the export window has an extra field for the tileinfo file's name. As expected, that file is now saved right beside the levels.

Sunday, March 5, 2017

AbiathRPC - Tileinfo

Abiathar's ability to show tile properties is extremely useful in my opinion, and it's especially important when testing the level requires an extra step like it does with AbiathRPC (seeing as the level set is remote). Obviously, Abiathar can't show tileinfo that it doesn't have, so I today I added support for tileinfo reading and writing in AbiathRPC.

It was less difficult than I expected. The server loads a tileinfo file if indicated in the configuration file. Clients request that when they connect. When a user alters a tile property, the change is noticed when the tool calls MarkChangesMade. The client extension keeps track of the previous ATP IDs so it doesn't have to reupload all the tileinfo. On the network, the properties are transmitted as an array of bytes - 2 long or 8 long for background and foreground, respectively. (I would have used ATP IDs there, but the server application doesn't have a reference to any Abiathar component and therefore can't process those numbers.)

I have yet to incorporate tileinfo into the export feature, but that shouldn't be hard at all.

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.

Wednesday, March 1, 2017

If tiles animate automatically, they must continue to animate

Today I helped a new NetKeen modder with their first map. Upon entering their level and after a tiny delay, NetKeen would freeze solid. It couldn't be level set corruption, since it displayed fine and all the other levels in the set had no problems. I didn't see any obvious mistakes in the level, and the Level Inspector reported no issues. I could add a new map to the level set just fine, so I decided to copy over tiles type by type to see which one caused things to break.

Sure enough, when I introduced a certain foreground tile, the freezing started. Looking at its properties, I noticed that it had an animation delay and offset configured when it definitely didn't need one. The tile that it animated to had no animation properties set. Clearing the animations on the source fixed the problem.

I conclude that if a tile automatically animates (i.e. it has an animation target set and doesn't wait for a switch to flip it), it must animate in a continuous cycle. The Tile Property Modifier's inspection mode doesn't check for this; I will see about adding logic for it.