Thursday, July 31, 2014

FMod - Editable Dependency Files

It's official: all features that are going to appear in Abiathar v2.0 have been completed and are in testing. Once I get some feedback from Gridlock (or even if I don't soon), I will begin the probably large documentation update required.

I completed the New Project Wizard refactor I mentioned a while back, creating a function to save the tab's data to the dependency file and approve the move-next command. The Back button is no longer a giant crash bug, and appears to be stable and predictable.

Relatedly, there is now an option to modify the dependency file in-editor! It's called "Project Settings" under Edit, and it produces a pre-filled, slightly renamed version of the New Project Wizard. It's all the same procedures, of course, just all marked visited so that it's loaded from the existing dependency file. The menu option actually just closes the original file, modifies an in-memory copy, takes advantage of the new unified loader to open it, and performs a variable shell game to get it associated with the old path. I was careful to not immediately save the modified file so the user can close without saving to undo it.

Finally (topically but not chronologically - Hebrew style!), the Level Inspector's report has been given an actual GUI. Previously, it just threw up a standard message box with each issue on one line. Now, I have a form containing a list view control, which lets the user sort by importance or name - and scroll, which is important if there are a lot of problems (previously, the box could be so tall that the buttons were off the screen). I even added a button to export the report as a text file.


Wednesday, July 30, 2014

FMod - Better Find

The other bug Gridlock reported yesterday was that Abiathar's Tile Instance Locator (find tool) does not update the highlight overlay when you select a tile from the tile palette instead of by right-clicking in the level. I fixed that bug today with a new event bus.

All that remains before the v2.0 update is a working Back button in the New Project Wizard and the ability to edit existing dependency files.

Tuesday, July 29, 2014

FMod - Graphics Reload Fix

Amid intense studying for my econ final tomorrow, I checked the IRC client I was running in the background and noticed that Gridlock had reported that Abiathar's Reload Graphics feature was still bugged. The first bug he discovered was caused by the mouse-move handler accessing the level view states, which are null while graphics are reloading. I had inserted a null check there, but it seems the level view states are accessed in other places too, possibly by delayed clicks or scrolling (or maybe even moving the mouse in the tileset, which may or may not have a separate handler). So, the graphics reloader now disables all the level and tileset viewer panels, making it impossible for them to handle things while it's rebuilding the view states.

Sunday, July 27, 2014

FMod - Back Button Issues

Gridlock mentioned in an IRC session that he would very much like Abiathar to allow editing of a dependency file after it is created. This is a really difficult problem for me, but of course I can't hide behind my implementation to excuse the lack of a possibly very useful feature.

As I mentioned, there's a Back button now. I have discovered that being able to move back and being able to modify things are very closely related, so I am performing refactoring to make both of those things work better. Specifically, there is now a lot more logic in the "show tab" function. It keeps track of whether a tab has been visited before: if it has, its settings are loaded from the dependency file, otherwise it is given some defaults.

The problem is that it's really hard to keep the tab UI, other dependent tabs' UIs, and the dependency file updated without blowing everything up with a null pointer. When the user can go back and pull a precondition out from under you, the visited list gets confused and tries to load settings that have been deleted from the compound. This is made a lot worse by the UI controls not firing the update event when assigned their current value, which is one of the most subtly terrible bugs ever.

I suppose I'll have to create a "save data" or "on leave tab" handler to manage all the data instead of trusting the update events and Next button to fix everything for me.

Saturday, July 26, 2014

FMod - API Cleanup

There was a part of Abiathar's API that I really didn't want to be there; it was an ugly hack that I included just to get all the view planes migrated to that API style. That part is IAbiatharCoreViewSettings, a little object under IAbiatharState.ViewState that holds a few Boolean values representing whether things under the View menu are checked. This is an ugly hack because extensions shouldn't need to know about that, and Abiathar's own processing shouldn't leak into the API.

So, I removed that section. Those renderers now check directly with the main form's settings to report whether they should be rendered.

In other news, I fixed a crash bug with Reload Graphics and made the Level Inspector not issue as many spurious complaints.

Friday, July 25, 2014

FMod - Back Button

I did actually manage to implement a Back button for the New Project Wizard today. It was actually a lot easier than I expected; there were only two things that caused issues with my first implementation, and they were easily fixed. So, that's pretty much the last feature requested by Gridlock for v1.5; I'll ask him again for feedback before I write up the documentation and release it.

Also, I added some self-documenting behavior to the configuration file. Through yet another attribute on the fields, a comment line is automatically added before the config entry. I have added such attributes to most of the fields in editor.aconf.

Finally, performance improvements! The Tile Tweaker and Freeform Tile Placer no longer register mouse movement handlers when single tile preview is off. This makes the coordinate display and tile scanner much faster.

Thursday, July 24, 2014

FMod - Change Everything

Today was another one of those talk-with-important-community-modders-and-implement-everything-they-say day! This time, Gridlock caught me on IRC in addition to sending me a message on the PCKF. The following changes and additions ensued:

  • Pressing a tool's shortcut key while it's active now acts as a toggle, turning it off and switching back to the default tool.
  • Pressing the space bar opens the previous tileset in addition to closing an open one.
  • The Y offset in the tile palette is remembered until a different palette is opened.
  • The Tile Instance Locator now allows placing tiles.
  • Plane state labels change font and color depending on the represented plane state (to provide multiple and faster means for recognition of the plane state, which is critical while designing).
  • A render-crash bug with Assimilate Infoplane mode is fixed.
  • Assimilate Infoplane mode no longer disables the infoplane palette. Multiple selection in that mode on the combined foreground tileset has been removed.
  • The legacy Dependency Collector no longer appears as an option in the New Project Wizard unless a config option is changed (ShowAdvancedMenuOptions/LegacyDepsCollector).
  • Lots of texts in the New Project Wizard have been changed to make it easier for new/unfamiliar users. Explanatory text has been added for the radio buttons.
  • A leaked file handle bug concerning Infoplane Override was fixed.
  • Tile Instance Locator and Tile Instance Remapper were given shortcut keys.
  • Undo's shortcut was changed from Control+Z to Z.
  • Palette Copier's shortcut key was changed from X to C, in consistency with the normal Copier.
A Back button for the New Project Wizard has been requested, and would probably be very useful. I'll get to that soon, hopefully.

Also, I replaced the cheap-looking default background image (the one with the Fleex and my name) with something much more impressive:

Wednesday, July 23, 2014

FMod - Minor Longstanding Issues

It came to mind today that it's possible to create a configuration file that causes Abiathar to crash with a stack overflow (or go into an infinite loop) on level load. This can be done by setting the default tool to one that terminates immediately, such as the Resource Accountant or Level Inspector. Before I release v1.5 (wow, this has been a huge update), I will add a read-only property to each tool that lets Abiathar know if it's OK to made it the default tool. If it's not, or if the user sets a non-existent tool ID as the default (which probably causes a crash now), I'll have it set the Tile Tweaker to be the default.

Tuesday, July 22, 2014

FMod - Error Reports are Useful

You know the dependency file processing error reporter I wrote about last time? It's already worth it. I received one of its reports from the Bio Menace modder on the K:M forums, and quickly figured out why he was only able to use Abiathar on Bio Menace 2.

In my initial explanation on what to do with all the steps in the New Project Wizard, I glossed over the opening of the GFXINFOE file because it opens the open-file common dialog; I provided no picture of that because the dialog is unnecessarily huge (thanks, Microsoft). What I did provide a picture of, however, was an example result after pressing the From GFXINFOE button as directed. He had copied down the settings that had been loaded for BM2 and tried to use them for the other episodes. Since they have different EGA layouts, that broke in the "loading graphics" section.

Without the ability to see the attempted dependency file, I never would have figured out what was causing the problem. I made a good investment here!

Monday, July 21, 2014

FMod - Code Correctness

Since the Bio Menace modder on the Keen:Modding forums is still experiencing problems using Abiathar on Bio Menace 3, I put up a new beta for him today. It includes the error reporter I wrote yesterday, and some other interesting things.

In Bio Menace and other games, there are some infoplane values I do not understand. They're not links, and not sprites, but some other sort of data attached to the tile. Interpreted as links, they usually point inside the level, which makes Abiathar think they're valid links. Therefore, they get adjusted (to point to the same relative location) by the Row and Column Adjusters when you insert or delete rows. Unfortunately, this messes up values that are not actually links. So, I added a setting to control this behavior. The default is still to update links when they have no icon and point inside the level, but there are two new ones: to not update links and to only update links where the foreground tile has one of a few specific properties. The tileinfo-checking one looks to make sure that the special-effect property of the foreground tile is one amenable to links (e.g. doors, keys, switches). It is not the default because it typically doesn't work on the Keen 5 world map - the doors have different properties at edit time - and because it takes a little longer to check every tile with a possible link. The option can be found in the settings for the adjuster tools.

Then, just for laughs, I ran Code Analysis on all the projects in the Abiathar solution. The default rule set found one issue, right in the loading of the non-Carmackized maps: a double disposal of a stream object. The analyzer claims that it could throw ObjectDisposedException, but I've never seen that happen on my machine. On the other hand, it is entirely possible that this was the bug causing trouble for the Bio Menace modder. After fixing that, I tried analyzing with all the rule sets. That didn't work well - apparently I am horrible at naming variables and designing interface contracts - and so I removed all the rule sets except Performance and something else I can't remember - maybe Usage or Reliability. (I had Maintainability in there for a while, but it was just complaining about things I can't fix now, specifically everything having an unacceptable cyclomatic complexity, class binding count, or maintainability index.) Going through Performance found a boatload of methods that could be made Shared, which I did, and also a generous helping of unused variables and methods, which is not terribly surprising given the number of nontrivial changes the code base has gone through. The other rule set helped me discover a lot of IDisposable things that were not disposed - who knew the browser dialogs could cause memory leaks? Of course, it also raised silly complaints about not disposing things before they went out of scope: they were used out of the local scope. After going through most of the issue logs and suppressing the spurious warnings, Abiathar runs a little faster!

And somewhere along the way, I changed a straggler "* 13" to a "* 18" in the New Project Wizard, making the Tile Partitioning step finally use the MAPTHEAD file correctly to get the number of infoplane icons.

Sunday, July 20, 2014

FMod - Better Error

"Error creating dependency file", or after the v1.5 unified opening and creating dependency files, "Error processing dependency file" is the most common Abiathar error message. It's also the most useless thing ever, it tells you nothing about what went wrong and what you might do to fix it. Simple things like referencing non-existing files are caught in the New Project Wizard, but there is still a lot than can go wrong (e.g. switching some files around) that I don't want to write a lot of complicated checks for.

So, today, I did something better. Somebody on Keen:Modding suggested that Abiathar generate an error report that could be sent to me when something bad happens. This is already done when the entire program crashes, but it would likely be far more helpful here, since I have never actually seen the program crash, nor has anybody reported it. I added a lot of things to that exception handler to gather details about the environment and write it to an error file if the user so chooses. The report consists of the following sections:
  • Stage of dependency file opening at which the exception was thrown
  • Name, size, and MD5 of all files in the working directory
  • Exception message, source, and stack trace (and those of the inner exception if applicable)
  • Metadata of all extensions installed
  • Serialization of the core entry in the dependency file
The stage information is gathered by setting an informational string value before entering a new section of the loader, which obviously stops updating if an exception happens. The MD5 calculation is skipped if the file is already open (or if it is Abiathar).

This scheme generates very nice crash reports, which should help me figure out the problem when people receive inexplicable errors.

Friday, July 18, 2014

Resolving the Mysterious Minecraft Missing Texture Issue in Eclipse

I was doing a little bit of messing around on the Wither mod idea, and I ran into a very strange problem. I had added an item texture (than honestly looks pretty awful, but whatever) and registered it with the item, but it was not displaying in-game. Instead, I got the purple-and-black checkerboard of missing textureness. I consulted many tutorials; I had registered and placed it correctly.

No, the issue was something far more obscure. Since I had placed the PNG file manually in the src/main/resources/assets/<mod>/textures/items folder without having the package folder expanded in Eclipse, that resource was not copied into the temporary build directory. This is possibly the strangest of such systems I have ever seen from an IDE, but refreshing the Project Explorer (press F5 with it focused) fixed the problem. Yay, non-obvious and undocumented issues!

Wednesday, July 16, 2014

FMod - File Handle Confusion

The wonderful Bio Menace modder who appeared on the Keen:Modding forums a while ago has given me some help with Abiathar. He reported a crash-corruption bug (!) involved with copying tiles. Though that particular instance of task was not really suited for the copy/paste mechanism and he was actually triggering entirely different functionality than what he wanted, there was still quite a bit of a problem in the program.

He was pressing Enter, probably thinking that it completes the copy, but it actually causes the graphics to reload, like in Mindbelt. That function was causing an IOException to be thrown, citing a file handle being open in another process. I looked all throughout the graphics loading code to find a leaked handle, even liberally sprinkling Using blocks around IDisposable instances. I did that for almost an hour until I discovered that something was wrong in the reload-graphics wrapper, not the graphics loader itself. After the call to DestroyGraphics, the reloader explicitly created handles for the EGA resources! That was an artifact from before bitmap graphics were allowed, and it was definitely the cause of the error. I removed them (they were just throwing the handles away anyway) and the problem was solved.

Also, I did some better clean-up of the selection plane so that it does not show the previous selection in a level when you switch back to the copy tool after canceling a copy.

Monday, July 14, 2014

Minecraft Forge 1.7 - Setting up Networking Components (newEventDrivenChannel)

After core Minecraft changed to using Netty for its network operations, Forge's network model changed considerably. They did a great job changing it, but the full road to getting packet dispatching working is documented literally nowhere. The wiki tutorials that claim to be the new way all have a message from the Forge team telling people that they are wrong.

I think I've done a decent job figuring out what needs to happen, so I'll document it here. Yay, internet learning!

First, you'll need to register a packet channel. Unlike in the pre-1.7 days when you had to register a bunch of different channels for each packet type, we will differentiate them with a map of integers to packet subclasses. Declare an FMLEventChannel variable in your mod class, preferably static:

public static FMLEventChannel NetworkCon;

Then, in your mod's handler for FMLServerStartingEvent, register the channel and assign it to that variable, like this:

@EventHandler
public void serverLoad(FMLServerStartingEvent event) {
FMLEventChannel net = NetworkRegistry.INSTANCE.newEventDrivenChannel(MODID);
NetworkCon = net;
}

(Replace MODID with your mod's ID name or use a constant you defined already.) Now, create a class to hold event handlers related to networking, I'll call mine NetworkHandler.

public class NetworkHandler {
@SubscribeEvent
public void onServerPacket(ServerCustomPacketEvent e) {

}
@SubscribeEvent
public void onClientPacket(ClientCustomPacketEvent e) {

}
}


Register that class as a receiver for the channel. If you get an error on the registration later, annotate the NetworkHandler class with @Sharable. Place this in the handler for FMLServerStartingEvent:

net.register(new NetworkHandler());

It's now up to you to register your packet types, which will be in another article - or you could create your own implementation! You can send them with the obviously named methods in the channel object and handle them in the packet event handlers. On the server, you can get the player by casting e.handler to NetHandlerPlayServer and accessing playerEntity, which is not obvious at all. I have this little utility method:

private EntityPlayerMP getSendingPlayer(ServerCustomPacketEvent e) {
return ((NetHandlerPlayServer)e.handler).playerEntity;
}

Happy modding!

Sunday, July 13, 2014

The Wither Mod - v1.7.10

Today I noticed that Forge has a version for Minecraft 1.7.10, which is considerably newer than the 1.7.2 I had been developing for. So, I used the Gradle script to update to it, but then all the sounds (including vanilla's) were broken. Apparently, I need to provide an --assetsDir switch in the run configuration. After doing that, I tried to run the thing and immediately discovered that Forge had yet again changed and broken my mod (I don't know what I expected). The main issues here were that IEntityOwnable's ID system had changed from using names to UUIDs and that some things referenced by my DiscriminatingExplosion lost their nice names (went back to the obfuscated Searge names). I fixed all those things without much trouble.

Then, in an attempt to make the Wither more interesting, I did some more messing around with its AI tasks. Before, it would frequently get stuck on trees or otherwise find itself unable to get to its target. This was due to EntityAIArrowAttack exiting if the Wither's senses did not have a clear line of sight to the target. I removed that check, and owned Withers will now shoot through barriers to get to their target!

Saturday, July 12, 2014

The Wither Mod - Stronger Bond

In the three hours I had today between waking up after oversleeping and going to church, I did some more things in the Wither-taming mod which has yet to be named. (Internally, it's named "WitherWand" but that was the first thing I thought of when I needed a package ID, it will probably not be kept.) I did a lot of looking at the wolf class and some investigation of the AI task system to see how "actions" are assigned to entities and triggered.

I applied my trick of copy/pasting entire source files on a few AI classes (specifically FollowOwner, OwnerHurtByTarget, and OwnerHurtTarget) and then changing the types to work with my Wither class. Those AI tasks have been registered in my class, causing an owned Wither to follow (and teleport to, if necessary) its owner. In addition, the Wither will give attack priority to first entities that attack the owner, then entities that the owner attacks, then entities that attack the Wither, and finally whatever entities it finds around the world and decides to destroy.

There's one bug with this arrangement: as the Wither goes around attacking whatever it wants, it may leave the player's ownership range, causing it to teleport back, but then it continues trying to attack the entity. This results in a strange rubber-band effect. I will eventually fix this when the owner is allowed to give the Wither instructions (in this case, to not destroy everything).

Friday, July 11, 2014

The Wither Mod - Proof of Concept

Today, since I didn't have a lot of college work to do, I did some things on the Wither-taming mod I was thinking about making. I abandoned trying to subclass EntityWither and instead copy/pasted the whole class's code so I could have control over the private variables as well. To make that work, I had to do the same thing for the renderer and the render model, changing type names. (This will eventually have to happen for some AI tasks that take a class on a different hierarchy instead of an interface like they should.) Once it was all done, I could change things in all the methods I need to, specifically replacing EntityWitherSkull with my own DiscriminatingSkull.

With that done, I have completed the proof of concept! The resulting owned Wither will go destroy all creatures (and I mean all - I changed the selector) except its owner. If one of the skulls does hit the owner, its explosion will not damage him and a few seconds of Regeneration (instead of Wither) will be given. I also removed some checks for creature type, allowing the owned Withers to attack other Withers.

Thursday, July 10, 2014

Possibly a New Mod

I had a great idea for a Minecraft mod while trying to go to sleep last night. I personally think it would be pretty awesome to tame a Wither and have it follow you around, obeying your commands or possibly just destroying everything around while protecting you. I imagine carrying some sort of baton to point the Wither toward what needs to be destroying, feeding it some sort of arcane scroll to teach it new behaviors - maybe sacrificing its health to fill mine?

I was fairly busy with important college things today, but I started messing around with this idea. I opened up a new ForgeGradle installation and threw together some super-messy subclasses of the Wither, its skull projectile, and the explosion class. Right now, I'm just trying to get a Wither to spawn that remembers its owner and doesn't deal damage to it. This is currently not working, but I think I have a separate type of entity spawning (I really quickly made an item to produce one of these guardian Withers with the user set as the owner.) Strange Java behavior when shadowing variables has not helped debugging, and I still can't figure out why the projectiles are still damaging the owner - it did get registered correctly at the spawning.

Since this will be a very small project, it might be the first mod I actually finish!

Wednesday, July 9, 2014

Minecraft: Defeating a Rogue Wither

Everyone knows it's easy to defeat Minecraft's Wither boss if you build it in a claustrophobic space or fight it above the Nether. However, the Wither is much more of a challenge in the varied Overworld surface, where trees get in its way and passive mobs are around to get pummeled and regenerate its health. I, with my friends on the Bare Roots Server, are currently suffering major losses due to many deaths to one escaped Wither. Unfortunately, all our super-powerful gear has already been destroyed, so we need to do something different contain this guy.

I came up with a plan. It doesn't require lots of powerful diamond gear, but a decent supply of gunpowder. Here's the shopping list with recommended quantities:
  • 128 TNT
  • 27 normal bows
  • 64 arrows
  • 2 Ender pearls
  • 1 bed
  • 1 iron pick
  • 1 flint & steel
  • 2 players
  • 2 suits of iron armor
  • 1 normal iron sword
  • 1 good bow
  • 1 good sword
First, in a location somewhat far away from the Wither (it won't rage on you until you directly attack it), dig a 1x1 hole a decent way - say, 50 blocks - down and fill it with TNT. Light it, and get away. Then, at the bottom of the exploded hole, TNT out sideways, producing an artificial cavern. Optionally, light it up, but the lighting will probably get destroyed later. Set up a bed at the surface with the supply chests containing bows and the arrows. Optionally, protect it with cobble you got from the blast.

Now, for this next step, bring nothing but one bow and 2 or 3 arrows. Go shoot the Wither once or twice, just to get it following you. Jump (or Ender pearl, if you have a dispensable supply of them) down to the bottom, making sure the Wither is following. Try to lure it away from the surface opening, but you'll probably die pretty quickly. Repeat this paragraph until the Wither is underground in your artificial cave, a decent way (20 blocks?) away from the surface hole.

At this point, if you aren't confident enough to go in and fight it (or if you like to live dangerously with a Wither below you), you could seal the hole and not worry about it ever again. It will eventually break out (those blue skulls can do a lot over a period of time), but by then you'll probably be geared up.

Here, get the nice bow (optimally Power IV or above, Punch is nice too), put on the iron armor, prepare an iron sword, take some potions if you have them, and go down. Shoot the Wither as much as you can, then go in with the sword, but you're probably close to dead by now. Once you die, grab the other set of iron armor, the good sword, and a normal bow, and finish off the Wither with a sword.

Monday, July 7, 2014

Workaround for Slime Spawning Bug in Minecraft 14w21b

Minecraft 14w21b, the newest snapshot most server administrators trust to not ruin all the worlds, has one annoying bug: Slimes don't spawn. This is actually a really huge problem if you need sticky pistons, which are necessary for automation. Fortunately, using /summon to create Slimes still works.

So, you can use this fact to create an administrative contraption to simulate normal Slime spawning. Do something akin to this:

  • As a server operator, switch into Creative mode
  • Find an unobtrusive spot in a spawn chunk for a small box
  • Create a multiplicative hopper-dropper clock
  • Configure it to pulse every two hours (or whatever you'd like)
  • Hook it up to a command block with the following command:
    • /execute @e[type=Creeper] ~ ~ ~ /summon Slime ~ ~ ~
This command will spawn one Slime at each Creeper. You could change the type, but I recommend Creepers because they are only found in the Overworld and are not spawned from any spawners. So, with this device set up and operating in a spawn chunk on your server, you'll be able to hunt Slimes in a fashion similar to the non-bugged behavior.

Sunday, July 6, 2014

FMod - Reported False Positive

Just a few minutes ago, I reported the Abiathar v1.5 files to Avast as a false positive. They actually have a really nice contact form with a simple file uploader to give them things. Hopefully, they'll figure out some way to make the antivirus not freak out.

Saturday, July 5, 2014

FMod - Antivirus Issues

I have received reports from members of the Keen modding community that Abiathar is setting off antivirus alerts and generally being misidentified as malware or a PUP. I wrote a little post on Keen:Modding about it, which has been adapted here.

I did a VirusTotal scan of it which came up fully clean, except for the Heuristics thinking that it's possibly a PUP. This is due to it packing executables (the updater, but mostly the DOS programs, especially CKPatch, in the File Emitter). 

FMod.dll (FleexCore) contains a whole bunch of bit-twiddling methods necessary to open the graphics, levels, and tileinfo. It's doing low-level operations from a format spec standpoint, but from a managed environment, so this probably isn't the issue. 

The new memory manager might also be causing trouble - there is a possibility that what I'm doing with the memory manager to throw out my cached view states is similar to the way some viruses get into protected memory. 

Antivirus hates the updater because it is, in essence, a benevolent and non-controlling remote access trojan. It works by checking my Dropbox for a newest-version file, using that to find that version's update script, and then running that script according to some very specific and safe rules. The AV programs are right to be suspicious of such activity, but I promise that the updater only updates Abiathar. 

The config files are probably disappearing because Avast likes to place (without telling you) suspicious programs in a "sandbox", which restricts their ability to create files. 

Finally, it now comes to mind that by loading extensions (did I mention the program has an extension API?) from appropriately named dynamic link libraries in the residing folder, Abiathar transfers control out of my safely engineered code. Please don't install Abiathar extensions if you don't trust the publisher. 

So, I'm sorry about this. There are a lot of things that AV can be paranoid about, but it's all quite legitimate. Please trust me :/

Friday, July 4, 2014

Copying Drives without Expensive Software or an Extra Drive

Just now, I needed to duplicate a drive, and so I did Internet research and came up with a nice-looking utility to do it for me. The one I found was free, but there were a whole bunch of super expensive ones (even recommended by PC Magazine). I installed it, fired it up, and found that it would not let me copy the current (OS) drive onto the blank drive I had just inserted. It's apparently not going to let me have cloning access to the OS disk because the files are in use. To use that approach, I would need to boot from a different media and copy that drive to the blank one.

So, I thought of another approach, taking advantage of Windows's awesome RAID capabilities. In Disk Manager (after booting from the drive I wanted to clone), I set the blank disk, which is of the same size, to be a mirror of the OS drive. It's currently "resynching" the RAID-1 arrangement, but when it's done, I'll have a perfect copy of the drive. To make sure the new drive doesn't try to assimilate others that it finds, I will disconnect the RAID when it's finished. Since using Disk Management to remove the mirror would erase the drive, I will reboot the computer physically removing one drive from the machine, open Disk Manager to verify that it says "Missing" for the other drive, and remove the mirror. This will be done again for the new disk.

Once this procedure is complete, I will have a perfect copy of my drive - done without expensive software or a third boot medium.

Thursday, July 3, 2014

FMod - Infoplane Override

Today in Abiathar, I got to hunt down a really awful level-corrupting bug! After the refactor, saving Keen Dreams levels with tileinfo in the map header caused the levels to become totally corrupted (unrecognizable even in a hex editor). It turns out that I had totally misused the optional parameter on DreamsLevels.ToFiles method, thinking it was a flag on whether to save tileinfo with the levels; it was actually the flag to force Huffman compression. Since Abiathar tried to avoid doing the expensive Huffman compression and hadn't set up the levels for recompression, it proceeded to totally mangle the data (really slowly too - it took almost 20 seconds to "save"). After using the correct positional optional parameter (inserting one comma in the code), everything was fine. Programming is hard!

Then, I found that the "changed" events don't fire on UI controls when the value property is set but actually sets what is already in the control. This is actually a massive pain - I was trusting that the event would trigger the controls to save their data into the dependency file in the New Project Wizard. This caused dependency files created on the second run (in one launch of the main application) of the NPW to be missing default data. It was annoying, but I fixed the problem by manually triggering each event in the appropriate Next button press.

Most interestingly, I implemented a new feature! Gridlock's Infoplane Override - having a different tileset for the foreground than the infoplane that uses the entire foreground ID range - is now officially part of Abiathar! It took a little bit of debugging to get right (mostly due to my thinking at first that the bitmap tile sheets are 13 tiles wide instead of the actual 18), but all the tileset components actually work really well with it. It was very simple to make the necessary adjustments to negate the infoplane division and ignore Assimilate Infoplane in the tileset wrappers. I suppose this is the benefit of having a good object model and API!

Wednesday, July 2, 2014

FMod - Actual Bio Menace Support

Ah, today I finally got to write the new unified dependency file loader. This was actually a lot easier than I expected. There were about three pages of code that the function replaced, and it is about two pages long. The Open and New menu items now call this with a minimum of stream shuffling. That's all great, but the new features it allows are really awesome.

Testing is not fully done, but it should be able to understand the two new level formats (MapTemp/MapHead and MapTemp/MapTHead) and bitmap tile sheet graphics. I have confirmed that Bio Menace is fully supported! Abiathar is able to load its levels, graphics, and tileinfo; modify the resources like it could Keen; and save it - the game will use it! Now, I just need to implement Infoplane Override, test more things, and Abiathar v1.5 is ready!

The first level of Bio Menace 2, loaded in Abiathar

Tuesday, July 1, 2014

FMod - Another Refactor

Yay, Abiathar's New Project Wizard is finally complete! I made a few minor adjustments to it today, mainly incorporating the old Dependency Collector as an option. That actually required quite a bit of code to be added to the DC's finish procedure (to convert it to the new way of storing creation information), but it's now a valid third path on the NPW. With that finished, I can move on to refactoring the file loader to use a dependency file instead of a bunch of streams.

That is turning into quite the task. Besides what I expected - the level and tileinfo loaders - the graphics handlers everywhere need to be rewritten. With the promise of bitmap loading (and the infoplane override), I can't depend on the EGA graphics object to provide the tile counts. The settings, however (by some weird placement on my part), are still stored in the chunk settings structure. So, with a little adjustment to the state wrapper and some redirection to use that state wrapper, the tile counts should work again.

I don't think a lot of things use the graphics object directly, so that's nice. I'm replacing it with an interface, IAbiatharGraphics, that simply serves Bitmap objects from a tile ID and plane. Most of the logic from GetCachedTile has been moved into the EGA implementation, leaving that function appropriately named. The bitmap implementation is proving to be more tricky. Thanks to the multiple graphics exporters (mostly ModKeen and KeenGraph) and their various switches and add-ons (grouting for KeenGraph and the KeenGrout utility for ModKeen), there are quite a few configurations of tilesets. My loader has to detect and understand them all, which thankfully can be done simply by looking at the width of the image. It uses that to select a function to find the position of a tile in the tileset image and then uses Graphics.DrawImage to copy that tile out of the set. There are also various transform functions in use to make everything be transparent in the right places (yay, explicit masking).

Currently, it can't do anything because the file loaders and graphics managers are totally broken. I think I'll be able to get most of the pieces tied together tomorrow, and then I just need to clean up the edge cases.