In the month that has passed since I asked my question on Super User about what the "Who owns this PC?" question in the Windows 10 setup actually means, some other people asked the same question on Microsoft forums, Some answers have been posted on those forums (none on my question yet), indicating that it has to do with Azure Active Directory, Microsoft's organization cloud service. Choosing that the organization owns it results in the question of whether a normal domain or an Azure AD environment is in place. Nobody is really sure why it's allegedly difficult to change, though.
Further reading: a question on TechNet, a question on Microsoft Answers
Various technical articles, IT-related tutorials, software information, and development journals
Monday, August 31, 2015
Saturday, August 29, 2015
Weirdness with Windows Update and Windows 10 Upgrade
While messing around with Windows Update (on my Windows 8.1 Pro machine) today, I noticed some strange behavior with the Windows 10 upgrade mechanism that got installed a few months ago along with the Get Windows 10 app.
Whenever I manually select some updates to install (not including the Win10 upgrade of course), the progress indicator retains the "Downloading Windows 10" caption/style. Once the updates finish, the Windows 10 upgrade files start downloading again, despite them having already been downloaded and my having canceled my reservation. Fortunately, a press of the "Stop download" button saves the day, or at least the network utilization.
I have tried hiding the Windows 10 upgrade entry in the available updates list by right-clicking it and choosing "Hide update" as I would do with any other update, but it does not seem to have an effect. The checkbox next to it grays out, but next time I open the dialog, even after a reboot, the entry is back.
Hopefully I won't accidentally upgrade to Windows 10 before I'm ready.
Whenever I manually select some updates to install (not including the Win10 upgrade of course), the progress indicator retains the "Downloading Windows 10" caption/style. Once the updates finish, the Windows 10 upgrade files start downloading again, despite them having already been downloaded and my having canceled my reservation. Fortunately, a press of the "Stop download" button saves the day, or at least the network utilization.
I have tried hiding the Windows 10 upgrade entry in the available updates list by right-clicking it and choosing "Hide update" as I would do with any other update, but it does not seem to have an effect. The checkbox next to it grays out, but next time I open the dialog, even after a reboot, the entry is back.
Hopefully I won't accidentally upgrade to Windows 10 before I'm ready.
Friday, August 28, 2015
Canceling Windows 10 Upgrade
Personally, I would like to wait a little while longer before upgrading to Windows 10. There are still some issues, mostly performance problems, that I would like worked out before I update. Some poking around revealed that the Get Windows 10 program that was installed via Windows Update shortly before Windows 10 was released has an option to cancel the reservation in the "Check your upgrade status" section. Click that button, confirm the decision, and the program reports the reservation as no longer in existence.
There appears to be some strange behavior with Windows Update after canceling a reservation; it still seems to think I want to download/install Windows 10. The Windows 10 preinstall files are still on the disk, in $Windows.~BT and $Windows.~WS in the root of the system drive. Hopefully nothing unexpected will come of that.
There appears to be some strange behavior with Windows Update after canceling a reservation; it still seems to think I want to download/install Windows 10. The Windows 10 preinstall files are still on the disk, in $Windows.~BT and $Windows.~WS in the root of the system drive. Hopefully nothing unexpected will come of that.
Thursday, August 27, 2015
ImfPreview Bug: Re-registered Event Handler
For quite a while, I have been occasionally experiencing a strange issue with ImfPreview: right-clicking songs in Music Mappings (to play them) sometimes results in the player dialog reopening once or a few times after it is closed. Only recently did I pinpoint the problem.
When the Music Mappings dialog is opened, ImfPreview hooks the songs list's MouseClick event and adds a handler that converts the IMF and plays it. The problem is that the handler is added every time the dialog is opened, so the dialog appears once for every time the user has opened Music Mappings after starting Abiathar.
The fix will be to check whether the dialog-opening code has already run and skip the AddHandler if it has.
Wednesday, August 26, 2015
Protecting Abiathar VeriMaps Certificates in a Synchronized Environment
Since v2.2, Abiathar has included a feature called VeriMaps with which users can cryptographically sign their levels. The signing certificate for each user should be kept private, because it is used to identify that user to those who might wish to check the authenticity and integrity of downloaded levels. That presents a bit of a problem to those working in shared, synchronized folders (like Dropbox). Fortunately, Abiathar has ways to deal with that.
By default, Abiathar looks for a file called VeriMaps.asign as the signing certificate. However, that can be changed with the VeriMapsCertPath option in editor.aconf. The configuration file must reside in the same directory as Abiathar to be recognized. The value of that option can be a relative or absolute path, so it can be pointed to a file outside of the shared folder. The best choice would probably be to have enough upward traversals to store the certificate immediately outside of the shared folder. If the file does not exist, Abiathar understands that the user does not have a VeriMaps certificate available.
For major projects that truly involve multiple people (rather than one getting assistance from another), I would be happy to issue a signing certificate named for the project. That way, there is no risk of key leakage.
By default, Abiathar looks for a file called VeriMaps.asign as the signing certificate. However, that can be changed with the VeriMapsCertPath option in editor.aconf. The configuration file must reside in the same directory as Abiathar to be recognized. The value of that option can be a relative or absolute path, so it can be pointed to a file outside of the shared folder. The best choice would probably be to have enough upward traversals to store the certificate immediately outside of the shared folder. If the file does not exist, Abiathar understands that the user does not have a VeriMaps certificate available.
For major projects that truly involve multiple people (rather than one getting assistance from another), I would be happy to issue a signing certificate named for the project. That way, there is no risk of key leakage.
Tuesday, August 25, 2015
ActiveNav - Forgot Everything
I downloaded ActiveNav onto my reissued school laptop today (because it's a nice tool that I like to have around), and realized that despite having written it, I cannot remember how to use it. The help command was helpful for the basics (bind, ce, and meta), but it's almost completely useless for more complicated things like find. Fortunately, I have the source code to remind me what subcommands do interesting things.
I suppose I should, when I have time, put a little effort into improving the in-program documentation, since having to reference an external manual would be inconvenient. Another reasonable area of exploration is writing to the Active Directory; currently it only supports reading operations.
I suppose I should, when I have time, put a little effort into improving the in-program documentation, since having to reference an external manual would be inconvenient. Another reasonable area of exploration is writing to the Active Directory; currently it only supports reading operations.
Monday, August 24, 2015
FMod - Tileset Improvements
A while ago, I received two Abiathar requests from a member of the community. Today I got around to implementing them.
First, he suggested keeping track of the scrolling position for each tileset. Previously, the Y offset was reset whenever the user moved to a different tileset; that is, there was only one variable to store the scrolling position. Implementing the request required a small reworking of one of the oldest parts of Abiathar, but it wasn't too difficult, and was definitely a good thing.
The other request was for a mode in which selecting a different tile causes the tile palette to automatically scroll, making sure the selected tile is always visible. I thought that would be best implemented as a configuration option, so that's how it is. When SnapToSelTiles is enabled in editor.aconf, it is ensured that newly selected tiles are always visible in the palette. This option is most useful with Simultaneous Tileset, but it also works well in the other mode.
Before I release a new version, I want to make some improvements to sound management, especially the handling of the two different "formats" of sound chunks.
First, he suggested keeping track of the scrolling position for each tileset. Previously, the Y offset was reset whenever the user moved to a different tileset; that is, there was only one variable to store the scrolling position. Implementing the request required a small reworking of one of the oldest parts of Abiathar, but it wasn't too difficult, and was definitely a good thing.
The other request was for a mode in which selecting a different tile causes the tile palette to automatically scroll, making sure the selected tile is always visible. I thought that would be best implemented as a configuration option, so that's how it is. When SnapToSelTiles is enabled in editor.aconf, it is ensured that newly selected tiles are always visible in the palette. This option is most useful with Simultaneous Tileset, but it also works well in the other mode.
Before I release a new version, I want to make some improvements to sound management, especially the handling of the two different "formats" of sound chunks.
Saturday, August 22, 2015
How Abiathar Uses GAMEMAPS Editor Signatures
If you've ever poked at Keen Galaxy levels in a hex editor, you've noticed that the first eight bytes are used to identify the level editor that created the maps file. (It's " FLEEXY " for Abiathar or "FleexRSA" for Abiathar with VeriMaps.) One might be inclined to think that this signature is entirely cosmetic. Though Abiathar won't have any problems if the signature is absent or unusual, it does check that space and make some use of that information.
Nitpick: Abiathar proper doesn't do any level loading. That's all handled by FleexCore2, also known as FMod.dll. "Abiathar" from here on in the context of level loading refers to FleexCore2's INextGenLevelSet implementers, usually GalaxyLevels.
Of course, in the case of VeriMaps, the FleexRSA signature signals that the maps are signed. Abiathar, upon encountering that fact, reads the author and signed hash, retrieves the alleged author's public key from the VeriMaps server, computes its own hash, and compares that with the one provided. The result of the check is displayed in the status bar.
Otherwise, the signature is checked against a list of editors known to be more or less well-behaved. At the moment, that list includes TED5 (TED5v1.0) and the various versions of TOM, plus of course the two possible Abiathar signatures. A "well-behaved editor" is one that never places a level header at the very beginning of the maps file. In that case, Abiathar knows that if the map header file points to zero for the first level, there really is no level there.
If an unknown signature is there, a level header could conceivably start at zero. In that case, Abiathar has to perform some heuristics if the first level's header claims to be at zero to determine whether there is actually a level there. Even if Abiathar wrongly guesses that there is a level there, exceptions are swallowed for the first run of the loop, so finding a bogus level header that isn't actually there won't cause the entire load operation to fail. (It will still complain big-time if other levels are in a bad format.)
Editor writers who want to ensure compatibility with all other editors should be careful to never place level headers at the very beginning of the maps file. That issue can be easily avoided by signing the editor name in the first eight (or more) bytes.
Nitpick: Abiathar proper doesn't do any level loading. That's all handled by FleexCore2, also known as FMod.dll. "Abiathar" from here on in the context of level loading refers to FleexCore2's INextGenLevelSet implementers, usually GalaxyLevels.
Of course, in the case of VeriMaps, the FleexRSA signature signals that the maps are signed. Abiathar, upon encountering that fact, reads the author and signed hash, retrieves the alleged author's public key from the VeriMaps server, computes its own hash, and compares that with the one provided. The result of the check is displayed in the status bar.
Otherwise, the signature is checked against a list of editors known to be more or less well-behaved. At the moment, that list includes TED5 (TED5v1.0) and the various versions of TOM, plus of course the two possible Abiathar signatures. A "well-behaved editor" is one that never places a level header at the very beginning of the maps file. In that case, Abiathar knows that if the map header file points to zero for the first level, there really is no level there.
If an unknown signature is there, a level header could conceivably start at zero. In that case, Abiathar has to perform some heuristics if the first level's header claims to be at zero to determine whether there is actually a level there. Even if Abiathar wrongly guesses that there is a level there, exceptions are swallowed for the first run of the loop, so finding a bogus level header that isn't actually there won't cause the entire load operation to fail. (It will still complain big-time if other levels are in a bad format.)
Editor writers who want to ensure compatibility with all other editors should be careful to never place level headers at the very beginning of the maps file. That issue can be easily avoided by signing the editor name in the first eight (or more) bytes.
Friday, August 21, 2015
Keen Galaxy Engine Tweak: Switches Doing Multiple Things
It was determined that a certain modding project in the Keen community would benefit greatly from the ability to have each switch do multiple things, specifically enabling a blinking arrow (toward the next part of a confusing level) in addition to performing its normal job. Fortunately, this is a source-modding project, so such changes are certainly possible. Seeing a chance to improve my C-writing skills, I volunteered to implement the feature.
I decided that the simplest way to do it was to move the existing switch-flipping "effect" logic into its own method and call that in a for loop from the entry switch-flipping function. The for loop decreases the Y coordinate, moving up in the level, until a non-switch tile is encountered. Practically speaking, the change causes all switches above a flipped switch to also flip. It has the added bonus of not breaking any existing switches. Players are unable to flip a switch at the top of a stack because there is no ground from which to flip them on.
That method was all good when there was room for extra switch tiles in the foreground above the switch that needs to do multiple things. I realized that many switches are in narrow/short corridors where there is an important foreground tile already above the switch. So, I made a special infoplane value that identifies a switch as a multiple-effect switch. When such a switch is flipped, infoplane values are checked in a similar upward fashion, but the foreground tile below them doesn't matter. In this mode, the type of every action (foreground/bridge or infoplane/platform) is determined by the type of the original switch rather than the type of the switch at each position.
The code change request was accepted, and the feature was implemented with my code, which will appear in the mod's source alongside the final compiled release.
I decided that the simplest way to do it was to move the existing switch-flipping "effect" logic into its own method and call that in a for loop from the entry switch-flipping function. The for loop decreases the Y coordinate, moving up in the level, until a non-switch tile is encountered. Practically speaking, the change causes all switches above a flipped switch to also flip. It has the added bonus of not breaking any existing switches. Players are unable to flip a switch at the top of a stack because there is no ground from which to flip them on.
That method was all good when there was room for extra switch tiles in the foreground above the switch that needs to do multiple things. I realized that many switches are in narrow/short corridors where there is an important foreground tile already above the switch. So, I made a special infoplane value that identifies a switch as a multiple-effect switch. When such a switch is flipped, infoplane values are checked in a similar upward fashion, but the foreground tile below them doesn't matter. In this mode, the type of every action (foreground/bridge or infoplane/platform) is determined by the type of the original switch rather than the type of the switch at each position.
The code change request was accepted, and the feature was implemented with my code, which will appear in the mod's source alongside the final compiled release.
Thursday, August 20, 2015
Abiathar Online - Actually Online
Today I read up on GitHub Pages, which is GitHub's web hosting service. Each repository (project) can have a special branch that contains the project's web page(s). I created that branch after some fiddling around with the command line, and copied the important client-side files into it. My plan for that branch is to update it only when I have a "stable" release or a milestone; day-to-day development will be done on the main "master" branch.
So, Abiathar Online is actually online now, and you can try it if you like. (Requires a Dropbox account, and existing level files. Those requirements may eventually be lifted.) I noticed that it's kind of broken on mobile devices, so my next goal is to address that.
So, Abiathar Online is actually online now, and you can try it if you like. (Requires a Dropbox account, and existing level files. Those requirements may eventually be lifted.) I noticed that it's kind of broken on mobile devices, so my next goal is to address that.
Wednesday, August 19, 2015
Abiathar Online - Saving!
After yesterday's discovery of URL length limitations, I had to figure out some way to get the level data to Dropbox via a real URL but not in the query string. Some thinking and two quick-and-dirty PHP scripts later, I had a way to upload levels and a page that Dropbox can hit to download them, which causes the server to delete the file to save space. Unique IDs for each file are generated by JavaScript. Security isn't super tight (this is PHP after all), but I do prefix the filenames with "OpenThar" to prevent easy exploits, and if it gets hacked, nothing is lost.
Some problems were had in the XMLHttpRequest upload. At first I didn't realize that the equals signs sometimes added by Base64 could cause issues for x-www-form-urlencoded data. That was easily solved with an encodeURIComponent call in JavaScript. Then there was the baffling issue of the XHR's readyState property always being 1. Apparently, that property will not work correctly in Chrome if any of the following are true:
- The server doesn't send all of the necessary headers (I had PHP explicitly set the Access-Control-Allow-Origin header so the JavaScript could export data to it)
- No handler is hooked up to the onreadystatechange event (a while loop that checks the state will not work)
- The main thread is busy (e.g. in an infinite loop, or waiting for the state to change)
I thought at first that the Dropbox Saver wouldn't appear if I had its invocation in an XMLHttpRequest completion handler, but it seems to be working. If it doesn't, people can just add an exception in their pop-up blocker for my place.
After a good while of fiddling around with JavaScript and PHP, I finally got it to save to my Dropbox. There was a bit of corruption in the level headers in the GAMEMAPS, but I think that was from the lack of URL encoding, which has since been added. I added some extra padding at the end just in case. It seems to be working consistently now. Abiathar Online can load, modify, and save levels!
Tuesday, August 18, 2015
Abiathar Online - Saving, Kind Of
Today I hammered out the level serialization code for Abiathar Online. Data arrangement and compression were easy thanks to my already having implemented them in FleexCore2. However, there was still the problem of how to get the data to Dropbox.
I did indeed decide to take advantage of a free PHP host to perform the conversion/echo of a Base64 query string to a binary response. One quick PHP script later (my first ever), I had an echo server up and running. Well, it was almost that simple. The hosting service injects a bit of HTML and JavaScript so they can provide me with analytics, but the snippet was getting injected into binary files as well, which is clearly not good. I fixed the problem with an exit; statement to halt execution after dumping the binary data down the wire.
The echo server is available at abiathar.site40.net/echo.php?data= (fill in your own Base64 data after the equals sign). For good measure, I had it also supply a downloaded file name, which can be specified with a filename parameter.
I wired up the serialization function to the Dropbox Saver and the PHP server, and quickly discovered that there is definitely a limit on URL length. The URL for the main maps file is so long that even Chrome won't display the entire thing, no matter how hard I try to scroll right in the address bar. The map header one works, though, and came out unscathed by the long process it went through! Tomorrow I will have to think of something clever to get around this URL length problem.
I did indeed decide to take advantage of a free PHP host to perform the conversion/echo of a Base64 query string to a binary response. One quick PHP script later (my first ever), I had an echo server up and running. Well, it was almost that simple. The hosting service injects a bit of HTML and JavaScript so they can provide me with analytics, but the snippet was getting injected into binary files as well, which is clearly not good. I fixed the problem with an exit; statement to halt execution after dumping the binary data down the wire.
The echo server is available at abiathar.site40.net/echo.php?data= (fill in your own Base64 data after the equals sign). For good measure, I had it also supply a downloaded file name, which can be specified with a filename parameter.
I wired up the serialization function to the Dropbox Saver and the PHP server, and quickly discovered that there is definitely a limit on URL length. The URL for the main maps file is so long that even Chrome won't display the entire thing, no matter how hard I try to scroll right in the address bar. The map header one works, though, and came out unscathed by the long process it went through! Tomorrow I will have to think of something clever to get around this URL length problem.
Monday, August 17, 2015
Abiathar Online - Functional Tile Palette
Today I added four lines of code to the mouseHappened function to handle clicks on the tile palette. That means it is now possible to choose tiles from the tilesets and place them in levels, the main activity in level editing. Sadly, switching between the level and tilesets is rather slow; Abiathar-style caching will almost certainly be necessary.
While I was not writing those four lines, I was researching binary file management for the saving component, which is pretty important for level editors. Dropbox still doesn't support data URLs in the Saver, the Datastore API which looked nice is deprecated, and the Core API is super complicated. It seems that I'll need an echo server to bounce data off of, but I cannot find a public server that does what I need.
Therefore, I have started researching PHP. PHP as a language is the exact opposite of everything I find reasonable, but there are ten zillion free hosting sites for PHP and none for ASP.NET, which I would strongly prefer. Fortunately, I'll only need to write a single PHP script to parse a URL- or Base64-encoded query string and respond with a binary file containing that data.
While I was not writing those four lines, I was researching binary file management for the saving component, which is pretty important for level editors. Dropbox still doesn't support data URLs in the Saver, the Datastore API which looked nice is deprecated, and the Core API is super complicated. It seems that I'll need an echo server to bounce data off of, but I cannot find a public server that does what I need.
Therefore, I have started researching PHP. PHP as a language is the exact opposite of everything I find reasonable, but there are ten zillion free hosting sites for PHP and none for ASP.NET, which I would strongly prefer. Fortunately, I'll only need to write a single PHP script to parse a URL- or Base64-encoded query string and respond with a binary file containing that data.
Sunday, August 16, 2015
Abiathar Online - Basic Editing, Now With Less Bafflement!
I noticed that in addition to the strange non-cursor-changing of links, the standard Chrome scrollbar had stopped functioning for Abiathar Online - it was there, but it could not be moved, but the arrow keys worked fine. I tried switching the context menu preventer to use only event.preventDefault() rather than doing that and returning false (which I read was problematic), and suddenly everything worked. The scrollbar was fixed, the cursor went back to normal, and best of all the canvas events started working again.
I then noticed that simply clicking (rather than holding/dragging) on the canvas did not result in actions being taken. That's a problem, especially for people who - unlike me - use a real mouse instead of a pen&touch. So I wired up a new event handler that translates the button values (which are for whatever reason different than those used in mouse-move events) into IDs that can be used in the main handler. When I tested it, I found that the strange symptoms had returned. Commenting out the handler wireup didn't help, but after a couple attempts at fiddling, Chrome froze and then crashed. When it came back up, it had apparently updated, and suddenly everything was working correctly. Maybe the problems weren't my fault!
Finally, I realized that having the tile IDs in the selected tile bay is actually very useful (e.g. to disambiguate bogus blanks from the zero tile). After a good while of fiddling with CSS, I got a monospaced hex representation displaying in the upper-right of each bay.
Abiathar Online now has basic tile tweaking functionality. Next, I'll see about getting tile palettes working.
I then noticed that simply clicking (rather than holding/dragging) on the canvas did not result in actions being taken. That's a problem, especially for people who - unlike me - use a real mouse instead of a pen&touch. So I wired up a new event handler that translates the button values (which are for whatever reason different than those used in mouse-move events) into IDs that can be used in the main handler. When I tested it, I found that the strange symptoms had returned. Commenting out the handler wireup didn't help, but after a couple attempts at fiddling, Chrome froze and then crashed. When it came back up, it had apparently updated, and suddenly everything was working correctly. Maybe the problems weren't my fault!
Finally, I realized that having the tile IDs in the selected tile bay is actually very useful (e.g. to disambiguate bogus blanks from the zero tile). After a good while of fiddling with CSS, I got a monospaced hex representation displaying in the upper-right of each bay.
Abiathar Online now has basic tile tweaking functionality. Next, I'll see about getting tile palettes working.
Saturday, August 15, 2015
Abiathar Online - Editing Time
I started working on the editing parts of Abiathar Online, that is, the code that allows picking up and tweaking tiles. I am using the mousemove event of the canvas element to process user input, but I have run into some very strange problems. The context menu preventer (returning false from a contextmenu event) does not appear to work, but it does if I set that same anonymous function to the oncontextmenu property of the canvas. The mouse movement handler was working at one point, then it suddenly decided to only fire once for each level, and now it has stopped working completely. I do not understand.
I learned that the comparison operators have higher precedence than the bitwise operators, which is weird. Oh, and I no longer get the hand cursor over links on the editor page. I have no idea what I did to make that happen.
I learned that the comparison operators have higher precedence than the bitwise operators, which is weird. Oh, and I no longer get the hand cursor over links on the editor page. I have no idea what I did to make that happen.
Friday, August 14, 2015
Abiathar Render Plane Management
I may have to clone Abiathar's rendering model into Abiathar Online to give it a speed boost, so I figured I'd document that model here for my own reference and for anybody wanting to develop Abiathar extensions.
The "view state" of each level and tileset consists of a bunch of planes, which are anything that implements ILevelRenderPlane or ITilesetRenderPlane as appropriate. Each has a name by which it can be accessed, preferably prefixed with the extension name and a colon. For instance, the normal background plane is called Abiathar:Background. There are two types of planes: those that hold an image to render on top of others below it, or those that store no image and instead render directly onto a Graphics object (called "ephemeral").
Both standard and ephemeral planes get queried on each rendering as to whether they are visible, that is, whether they should be rendered now. Standard planes are also queried for freshness (NeedsUpdate) and receive a Render call if they require a repaint. Their image is then accessed through the Image property, which can be null, in which case nothing will be rendered. Ephemeral planes simply receive a RenderEphemeral call with a Graphics object and several other parameters concerning the view settings.
Upon creation, each plane receives a SetRenderLevel (or the appropriate tileset-related method) and SetStateAccessor call, which set up necessary infrastructure for them to access level/tileset data. Level render planes can publish the ID of the technical plane that they represent, like 1 for foreground, in which case Abiathar will notify them (by calling UpdateTile) when tiles change in that plane. That way, the whole level doesn't have to be rerendered each time. The return value from that function indicates whether changes were made to the displayed image, but that value is currently never used.
The "view state" of each level and tileset consists of a bunch of planes, which are anything that implements ILevelRenderPlane or ITilesetRenderPlane as appropriate. Each has a name by which it can be accessed, preferably prefixed with the extension name and a colon. For instance, the normal background plane is called Abiathar:Background. There are two types of planes: those that hold an image to render on top of others below it, or those that store no image and instead render directly onto a Graphics object (called "ephemeral").
Both standard and ephemeral planes get queried on each rendering as to whether they are visible, that is, whether they should be rendered now. Standard planes are also queried for freshness (NeedsUpdate) and receive a Render call if they require a repaint. Their image is then accessed through the Image property, which can be null, in which case nothing will be rendered. Ephemeral planes simply receive a RenderEphemeral call with a Graphics object and several other parameters concerning the view settings.
Upon creation, each plane receives a SetRenderLevel (or the appropriate tileset-related method) and SetStateAccessor call, which set up necessary infrastructure for them to access level/tileset data. Level render planes can publish the ID of the technical plane that they represent, like 1 for foreground, in which case Abiathar will notify them (by calling UpdateTile) when tiles change in that plane. That way, the whole level doesn't have to be rerendered each time. The return value from that function indicates whether changes were made to the displayed image, but that value is currently never used.
Thursday, August 13, 2015
Query String to Binary Response Echo Server, Please
I learned that the Dropbox Saver control does not currently support data URLs, which is a real shame since I'd think it'd be easy to implement and would make a lot of people (including me for Abiathar Online) very happy. I now have to either produce a real URL to save the levels or abandon Dropbox integration, which I don't really want to do.
That's why I would very much appreciate a public echo server that can transform a Base64 (or URL-encoded) query string to a binary response. I would tell Dropbox to save the resource from that server with the URL that includes the file data and it would receive the binary version of that (as an application/octet-stream resource).
If somebody knows of such a server, I would love to hear of it.
That's why I would very much appreciate a public echo server that can transform a Base64 (or URL-encoded) query string to a binary response. I would tell Dropbox to save the resource from that server with the URL that includes the file data and it would receive the binary version of that (as an application/octet-stream resource).
If somebody knows of such a server, I would love to hear of it.
Wednesday, August 12, 2015
Abiathar Online - Tileset Rendering and Keyboard Shortcuts
The only "// TODO" comment I had after yesterday's development on Abiathar Online was in renderLevel, specifically in the branch that should display the tileset (tile palette). Rendering the tile palette requires knowing how many tiles there are, so I also added a little code to editorReady to figure out the number of tiles based on the tile sheet height and width (that is, which graphics program created it). I decided that 14 infoplane rows ought to be enough for anybody, and declared the number of infoplane icons to be constant: 252.
I then learned about DOM events to add a key-down handler. I basically copied Abiathar's plane state management key layout; 1-3 toggle editability, 4-6 toggle visibility, 7-9 show the tileset, and 1-3/4-6 show the tileset if a different tileset is already showing. PageUp and PageDown do exactly what they do in Abiathar (move between levels), as does Space (switch between last-seen level and last-seen tileset). The tilde shows the level list, but I don't know how I would make keyboard shortcuts for a variable number of levels, so the mouse still has to select which level to switch to.
I also noticed that Abiathar Online works very nicely as a full-screen web page. I'll try to make sure a good editing experience is always had in that mode.
Tuesday, August 11, 2015
Abiathar Online - Plane Controls
Today I made some serious additions to Abiathar Online's top pane, which is internally (and in my mind) called the editBar. There is now an Abiathar-style tile bay for each plane (using the inline-block CSS display type about which I learned today), containing an image for the selected tile, a label for the plane state, links to change the plane state, and a link to the tileset. When the tileset is showing, a new link appears above the current-level label to return to the level. There is not currently a way to change the selected tile, but I have the JavaScript function in place to deal with it.
I updated the renderer to respect plane states; it will no longer show hidden planes. I think that means I've completed all the important "reading" parts of a level editor, so next I'll have to get to "writing" features.
I updated the renderer to respect plane states; it will no longer show hidden planes. I think that means I've completed all the important "reading" parts of a level editor, so next I'll have to get to "writing" features.
Monday, August 10, 2015
Abiathar Online - Level Viewing
The only thing missing from level rendering after my initial implementation yesterday was the hex composites for infoplane values that are not icons (very high values like FA17h, as seen in links). Today I wrote that part of carveImage. It uses a small "tileset" image containing the nybble images used in Abiathar.
I then gave function to the Switch Level link. When clicked, it hides the level-viewing canvas and shows a div containing a link for each level. (The level switching event handler was a bit tricky because JavaScript has no block scoping, only function scope. Combine that with closures and you get problems!) After using that feature to look at some horizontally wide levels, I noticed that the "editbar" div does not stay in view when the page is scrolled. So, I looked up some CSS tweaks to make it stay in one place.
Abiathar Online is now a working level viewer. Next, I'll see about plane states and tweaking tiles.
I then gave function to the Switch Level link. When clicked, it hides the level-viewing canvas and shows a div containing a link for each level. (The level switching event handler was a bit tricky because JavaScript has no block scoping, only function scope. Combine that with closures and you get problems!) After using that feature to look at some horizontally wide levels, I noticed that the "editbar" div does not stay in view when the page is scrolled. So, I looked up some CSS tweaks to make it stay in one place.
Abiathar Online is now a working level viewer. Next, I'll see about plane states and tweaking tiles.
Sunday, August 9, 2015
Abiathar Online - Decompression and Rendering!
Today I finished up the decompression code for Abiathar Online. It wasn't terribly difficult, especially because I already had a working implementation in FleexCore2 and the ModdingWiki has a good description of the algorithm. There were a couple silly bugs in my first JavaScript implementation, but they were easily fixed with the Chrome debugging tools.
I then started on the tricky part, the rendering. After slapping a <canvas> tag onto editor.aconf, I started writing some drawing code. The new renderLevel method will be responsible for the drawing of levels and tilesets, but today I just wrote the level handling code. All the real work is done in the carveImage function, which carves an individual tile image out of the appropriate tileset and applies transparency as called for. That was actually fairly difficult to accomplish; it required tweaking image data with JavaScript. Getting the locations of tiles based on tile sheet width (i.e. graphics program) was fairly easy since I could copy it from Abiathar.
I have not yet implemented the infoplane hex composite part of carveImage, but everything else (background, foreground, infoplane icons) is rendering! Tomorrow I'll see about those hex composites and get level switching going.
I then started on the tricky part, the rendering. After slapping a <canvas> tag onto editor.aconf, I started writing some drawing code. The new renderLevel method will be responsible for the drawing of levels and tilesets, but today I just wrote the level handling code. All the real work is done in the carveImage function, which carves an individual tile image out of the appropriate tileset and applies transparency as called for. That was actually fairly difficult to accomplish; it required tweaking image data with JavaScript. Getting the locations of tiles based on tile sheet width (i.e. graphics program) was fairly easy since I could copy it from Abiathar.
I have not yet implemented the infoplane hex composite part of carveImage, but everything else (background, foreground, infoplane icons) is rendering! Tomorrow I'll see about those hex composites and get level switching going.
Saturday, August 8, 2015
Abiathar Online - Byte Crunching JavaScript
Since the setup UI for Abiathar Online is done, it's time to start on the map loading code. I added two XMLHttpRequest usages to confirmSetup(), both of which call levelResReady() when complete. The duty of that latter function is to process the maps files and populate the levels array. Writing that function is very difficult because JavaScript doesn't seem to have a nice binary processing API. I'm making do with typed arrays (Uint8Array and Uint16Array). So far I've written the level header processing code (to get the level name and data pointers); next I'll finish the Carmack decompressor. Hopefully it won't be terribly slow.
Friday, August 7, 2015
Abiathar Online - Setup Complete
Today I completed the setup UI for Abiathar Online by writing the manual "pick each file manually" setup path. In that mode, the resource type confirmation table from the automatic path is reused and given a "Pick" link in each filename cell. Each of those links creates a single-select Dropbox Chooser window. I also made the "Launch Editor" button appear on its own line so it doesn't create inconsistencies between the setup paths when the button for the chosen path is removed.
I then started investigating JavaScript data processing. It appears that I'm going to have to get the data with an XMLHttpRequest and then get at its data with an ArrayBuffer. I do already have it grabbing the images from Dropbox using the Image class/thing. JavaScript seems to have typed arrays now, at least for certain widths of numbers, so that will help when loading levels.
The aforementioned user interface elements, minus the giant "Choose your files" title |
I then started investigating JavaScript data processing. It appears that I'm going to have to get the data with an XMLHttpRequest and then get at its data with an ArrayBuffer. I do already have it grabbing the images from Dropbox using the Image class/thing. JavaScript seems to have typed arrays now, at least for certain widths of numbers, so that will help when loading levels.
Thursday, August 6, 2015
Abiathar Online - JavaScript Time
Today I jumped into the scripting component of Abiathar Online, which is definitely going to be the area in which I learn the most. I started implementing the "all together" path of the setup wizard, in which all four required resources are in the same folder and can be loaded in one invocation of the Dropbox Chooser. I got Dropbox file loading working; they have very nice API documentation with useful examples. (Very important for me, since I had no idea how to create a JavaScript object.)
After the four files are chosen, I have some script to identify what resource each file represents from its filename. It then displays its guesses in a table and waits for the user to press a button to confirm that the guesses were correct (or use manual load if they're not, which I haven't built yet). Once I get both setup paths working, I'll be ready to start doing things with HTML5, specifically the canvas.
I also made some adjustments to the CSS to remove the extra space above the main title that was pushing the whole content div down since it's centered vertically. A good deal of tinkering was also required to get the table looking nice, but I like what I have so far.
After the four files are chosen, I have some script to identify what resource each file represents from its filename. It then displays its guesses in a table and waits for the user to press a button to confirm that the guesses were correct (or use manual load if they're not, which I haven't built yet). Once I get both setup paths working, I'll be ready to start doing things with HTML5, specifically the canvas.
I also made some adjustments to the CSS to remove the extra space above the main title that was pushing the whole content div down since it's centered vertically. A good deal of tinkering was also required to get the table looking nice, but I like what I have so far.
Wednesday, August 5, 2015
Learning (Ancient) C
Today and yesterday I made efforts to learn C so that I could modify NetKeen, Lemm's competitive multiplayer adaptation of Commander Keen. I would have downloaded Clang or another modern C compiler, but NetKeen requires features only held by very old compilers: the ability to compile inline assembler into the final executable and target real-mode 16-bit DOS. Those requirements led me to use Borland C++ 5.02, an old IDE for C and C++.
Now, Borland C++ 5.02 was built in a time when Windows 2000 was a fancy new OS. That meant that I wasn't going to get far with it on 64-bit Windows 8.1, so I had to make use of a Windows 95 virtual machine that I had sitting around. After some fiddling around with virtual CDs, I had Borland in Windows 95 successfully compile the original NetKeen source. (That virtual machine's resolution is locked at 640x480; there doesn't seem to be a way to change it with VirtualBox as the hypervisor. Oh, and Windows 95 really likes to open new Explorer windows when I navigate to other folders. Thanks to those two facts, using the VM is kind of painful.)
My original means of transferring files between host and guest was to create a FAT-formatted VHD and attach it to the VM as a separate hard drive. To move a file one way or the other, I shut down the VM, mounted the VHD on my real machine, put files on it or copied them off, dismounted the VHD, and rebooted the VM. It was painful, so I was very happy after I remembered how to enable TCP/IP and file sharing in Windows 95. Now I can just navigate to the VM's shared folder from my host's Explorer and copy files as appropriate.
Editing of source files was initially done by working in Notepad++ and then copying the files onto the VHD. When I broke the build (which happened a few times, since I had literally never any non-trivial C before yesterday), I had to tweak files using Borland's IDE in the VM, which was painful for reasons already explained. Oh, and this is a version of C that splits each method into a declaration section and an action section, so no variables can be declared after normal calls have been made. It's like COBOL! Once the file sharing was set up, I just used Notepad++ directly on the shared files and only used Borland to compile.
It was a saga, but I did finally get some modifications done. In my customized NetKeen, many more hits are required to attain a stun, so strategy and tactics are required. Running out of ammo is always a real possibility! I also changed the penalty for getting stunned by non-player sources to award points to others rather than taking them away from the victim. (That change strongly discourages suicide to regain starting health.)
Now, Borland C++ 5.02 was built in a time when Windows 2000 was a fancy new OS. That meant that I wasn't going to get far with it on 64-bit Windows 8.1, so I had to make use of a Windows 95 virtual machine that I had sitting around. After some fiddling around with virtual CDs, I had Borland in Windows 95 successfully compile the original NetKeen source. (That virtual machine's resolution is locked at 640x480; there doesn't seem to be a way to change it with VirtualBox as the hypervisor. Oh, and Windows 95 really likes to open new Explorer windows when I navigate to other folders. Thanks to those two facts, using the VM is kind of painful.)
My original means of transferring files between host and guest was to create a FAT-formatted VHD and attach it to the VM as a separate hard drive. To move a file one way or the other, I shut down the VM, mounted the VHD on my real machine, put files on it or copied them off, dismounted the VHD, and rebooted the VM. It was painful, so I was very happy after I remembered how to enable TCP/IP and file sharing in Windows 95. Now I can just navigate to the VM's shared folder from my host's Explorer and copy files as appropriate.
Editing of source files was initially done by working in Notepad++ and then copying the files onto the VHD. When I broke the build (which happened a few times, since I had literally never any non-trivial C before yesterday), I had to tweak files using Borland's IDE in the VM, which was painful for reasons already explained. Oh, and this is a version of C that splits each method into a declaration section and an action section, so no variables can be declared after normal calls have been made. It's like COBOL! Once the file sharing was set up, I just used Notepad++ directly on the shared files and only used Borland to compile.
It was a saga, but I did finally get some modifications done. In my customized NetKeen, many more hits are required to attain a stun, so strategy and tactics are required. Running out of ammo is always a real possibility! I also changed the penalty for getting stunned by non-player sources to award points to others rather than taking them away from the victim. (That change strongly discourages suicide to regain starting health.)
Tuesday, August 4, 2015
Abiathar Online - CSS Fiddling
Over the last few days I've made a start on Abiathar Online, my first serious foray into web development. What I have so far is a simple stylesheet and a couple pages that look nice but don't do anything yet. I've decided on a simple blue-centered design with square buttons for links/commands and cyan gradients for edges. The main font is Open Sans (embedded with CSS3, look at me with these fancy web features!), with Lucida Console for monospace texts.
There's a start/splash page with two buttons ("learn more" and start) that I'm not sure is actually useful. I guess people can bookmark the actual editor page to get there directly, since the opening of files has to be done on the same page as the editing anyway. No JavaScript has been written yet, but I am almost ready to start putting together the file opener, which is backed by Dropbox.
Check out the GitHub repository if you're interested. I'll take pull requests after the important parts of the application are written.
There's a start/splash page with two buttons ("learn more" and start) that I'm not sure is actually useful. I guess people can bookmark the actual editor page to get there directly, since the opening of files has to be done on the same page as the editing anyway. No JavaScript has been written yet, but I am almost ready to start putting together the file opener, which is backed by Dropbox.
Check out the GitHub repository if you're interested. I'll take pull requests after the important parts of the application are written.
Monday, August 3, 2015
FMod - Links View Bugfix
Yesterday I confirmed the presence of an Abiathar bug that I had heard about once or twice, but was not sure actually existed. It definitely does - it is possible in certain circumstances for Abiathar's links rendering mode (View | Links) to stop drawing existing links. That was really hard to reproduce, but my Minimal Complete Verifiable Example for it is:
- Make sure View | Links is off
- Move to a level that contains link infoplane values
- Place a link infoplane value
- Turn on View | Links
- See that only the new value renders as a link
The problem was that LinksRenderPlane's Rendered field (which is used to tell the renderer whether to do a full re-render) was set to True by DrawLinks, which is called from the tile change handler to update the link for one tile. So, after that runs (which it does even when the LinksRenderPlane is not visible), Rendered is True so FindLinks (which is responsible for scanning the level for links) is not run.
I moved the Rendered = True statement to the end of the Render implementation so it's only called after the initial full render pass.
Sunday, August 2, 2015
FMod - v2.8.1
I finished up testing the changes to level management and the Flood Filler today. Everything seems to be in order; all actions are easily undoable. I only made one change: all the fillers (rectangle, circle, flood) now allow selecting the tiles under the cursor by right-clicking. That way, you don't have to switch to the Tile Placer if you change your mind about what tiles you want to fill with.
I released the changes from these last few days as v2.8.1.
Saturday, August 1, 2015
FMod - Intuitive Flood Fill
A community member expressed confusion about Abiathar's Flood Filler tool, specifically the difference between bounding planes and filled planes. I can see how adjusting the bound planes might not be an obvious thing to do. So, I added a new configuration option - SimpleFloodFill - that causes the Flood Filler to always use the active planes for bound and fill. The option is adjustable in the old Flood Fill Properties (now called Flood Fill Policy) dialog as well. The tool status text for the Flood Filler in simple mode now tells the user that pressing Space opens a dialog with more options.
I also fixed several little issues that caused the "current level" check mark to not appear in the Level menu after certain level management operations were performed. They were all caused by calls to UpdateLevelList (which purges and refills the Level menu) after UpdateLevelLabel (which updates the current level status label and adjusts the check mark). Switching the order of those calls resolved the issue.
I also fixed several little issues that caused the "current level" check mark to not appear in the Level menu after certain level management operations were performed. They were all caused by calls to UpdateLevelList (which purges and refills the Level menu) after UpdateLevelLabel (which updates the current level status label and adjusts the check mark). Switching the order of those calls resolved the issue.
Subscribe to:
Posts (Atom)