NESMaker Plugins Part 2

Hello and welcome to Part 2 of the NESMaker plugin guide! By now you have probably started your first plugin to give a better user experience than telling them to go in and edit your asm files by hand. You also might have run into a problem getting info from the base NESMaker model. Fear not! As of version 4.1.1, you will have access to almost everything available from the Project Settings dialog. Let’s talk about how to get there.

When your plugin starts up, you will be passed in an INesMaker interface. If you would like to access the project settings part of the model, it is all done through the ProcessCommand() method. The first thing you should do is check the version of NESMaker that your user is running. To do this, create a class that implements the INESCommand interface, and set the Action property to “GET VERSION”. Version 4.1 will return a blank string and will not support any other calls. Version 4.1.1 and above WILL support additional calls. You should see “4.1.1” (or a higher version) returned in the Result property.

Next, you should call ProcessCommand() with the Action property set to “GET COMMAND_LIST”. This will let you know if the commands that your plugin needs are available and if any newer commands have been added.

Here is a list of all the “GET” commands that you can call as of version 4.1.1. They all return a JSON object in the Result property.

* "GET PROJECT_LABELS"
* "GET PROJECT_TILESETS"
"GET PROJECT_SCRIPTS"
"GET PROJECT_USER_DEFINED_VARS"
"GET PROJECT_USER_CONSTANTS"
"GET PROJECT_ZERO_RAM"
"GET PROJECT_OVERFLOW_RAM"
"GET PROJECT_OBJECT_VARS"

Most of these commands do not require any additional information. There are 2 exceptions however! “GET PROJECT_LABELS” and “GET PROJECT_TILESETS” both require a JSON string to be set in the Target property of your request. To simplify a LOT of the JSON syntax stuff, I prefer to use the Newtonsoft.Json  dll. You can install it from the visual studio Nuget reference manager.

Let’s discuss “GET PROJECT_TILESETS” first. NESMaker has 7 types of tilesets. They are Main, Screen, Path, Monster, specialTiles, objectTiles, and HudTiles. These are located in different graphic banks. To specify the tilesets that I want information on, I need to pass in the graphic bank and the type. An example is shown below:

The key takeaway here is that you specify the extra info that the call needs in the JSON object, then convert it to a string and set the Target property. It might sound confusing, but once you use it a couple times, it will be second nature to you. Your response will be in the Result property. It will be in the form of a JSON object as well, so the easiest way to read it is with a call like this:

JObject jsonTilesets = JObject.Parse(response.Result);

Getting project labels is very similar. It however requires a field named “LabelOffset” as an int in the JSON object. That offset specifies what type of label you are interested in. 0=Tile Types, 1=Change Tile Types, etc…

Besides getting information from the NESMaker model, you can also SET. The table below gives a list of all the SET commands and the JSON parameters that they expect.

CommandParam NameParam Type

 SET PROJECT_LABEL  LabelOffset
ValueOffset
Label
int
int
int
 SET PROJECT_TILESET GraphicBank
TilesetID
TilesetType
DisplayName
BMPFile
int
int
string
string
string
 SET PROJECT_SCRIPT Name
Define
Script
string
string
string
 SET PROJECT_USER_DEFINED_VAR Name
Enabled
InitialValue
Notes
string
bool
int
string
 SET PROJECT_USER_CONSTANT Name
Enabled
InitialValue
Notes
string
bool
int
string
 SET PROJECT_ZERO_RAM Name
Enabled
Bytes
Notes
string
bool
int
string
 SET PROJECT_OVERFLOW_RAM Name
Enabled
Bytes
Notes
string
bool
int
string
 SET PROJECT_OBJECT_VARS Name
Enabled
TotalObjectCount
Notes
string
bool
int
string

I hope that this gives you a good start in working with the INesMaker.ProcessCommand() method. I plan on adding more functionality so that plugin writers will be able to add even greater functionality! Good luck making your games!

–Josh

 

 

NESMaker Plugins Part 1

This post goes into detail on the NESMaker plugin system. It is assumed that you have a copy of NESMaker, you are familiar with all of it’s basic features, and you can write code in C#.

The first thing to do is grab this starter project: NESMakerPluginStarter. Load it into Visual Studio and look at the code. You will see what methods need to be implemented, and what methods should be modified.

At this point, Once you change a couple things that the comments in the code mention, you should be able to compile, copy your DLL into the NESMaker plugin folder, and test it out! Lets talk a little more about what each method does though. If you have the project open, you can follow along.

The first thing to examine isn’t even a method. It’s an attribute on your plugin class. It looks like this initially:

[ExportMetadata("ID", "YOURNAME/PLUGINNAME/PLUGIN_VERSION")]

This identifies your plugin to NESMaker and keeps it separate from all the other plugins out there. It is what allows NESMaker to locate your plugin and pass in all of the project information that you want to keep when the user loads and saves their project.

Next, comes the constructor and model.

 public PluginModel Model { get; set; }
 public NesMakerPlugin()
 {
 Model = new PluginModel();
 }

This is called when NESMaker initializes. Notice that we create an instance of your model class. This is where you should store any data that you want to save in the users project file.

The  NESMaker plumbing works by examining the node that the user clicks on, and then placing a UserControl in the work area. When the user clicks on a plugin node, NESMaker asks the plugin for something to display to the user. It does this via the GetControl(int offset) method. Just return an object derived from UserControl and you are good! The offset parameter lets your plugin know what node the user clicked on if you had more than one.

The whole point of NESMaker is to write asm for you, and the plugin will want to be able to write files as well. When the user decides to test her project, your plugin will want to generate all the needed .asm files. You can tell NESMaker all the files you want to write by returning a list of filenames from the GetExportFilenames() method. You will likely want your filenames to be named something that is specific to your plugin so that you do not accidentally get overwritten, or overwrite someone else’s file.

Once you have told NESMaker what filenames you want to export, it’s time to tell it the content of those files. NESMaker will call your Export(string filename) function once for every filename that you returned in GetExportFilenames(). I recommend writing header information at the top of the file so the user can verify when the file was last created.

The next couple functions are pretty self explanatory. Init(INesMaker app) gets called only once when NESMaker starts up. The key thing to notice is that it passes in an interface to itself. This is how you can communicate with NESMaker. I will give more information on this interface in the next post. Another thing to be aware of is that if you need to do something right before or right after you export your asm, you can hook into the Pre/PostBuild events.

The “int GetNodeCount()” method lets NESMaker know how many nodes you want. Most plugin writers will only want 1 node, but if your plugin is more complex, you might want multiple nodes. You have the power. Please don;t make this a huge number though as we wouldn’t want the plugin tree too cluttered.

The “string GetNodeName(int offset)” method should return the text that you want the user to see. It should be descriptive enough so the user will know that that node came from your plugin.

The “Image GetNodeIcon(int offset)” method does what it sounds like! It returns an image that will be used as the icon for your node. By default, I have included a file called PluginIcon.bmp, and placed it in your project as a resource. I recommend just painting over this with your icon art, and leaving the code alone. It’s easier that way. 🙂 Both GetNodeIcon, and GetNodeName are only ever called once, when NESMaker initializes.

The last 2 methods are Persist and Recall. This is how you save  your plugin information into the users Project file. Each method has either a BinaryWriter or a BinaryReader. The default implementation just calls your model’s persist and recall methods.  The important thing to consider here is that you must read the data back in the same order that it was written in.  For example, lets say that you had 3 pieces of data, X, Y, and NAME as properties in your model class.  To write those to the users project, you would say:

bw.Write(X);
bw.Write(Y);
bw.Write(NAME);

To read those values back in when the user loads their project, you would write:

X = br.ReadInt32();
Y = br.ReadInt32();
NAME = br.ReadString();

One last thing to consider is what you do when you upgrade your plugin… If you have a version 2 of your plugin, and it tries to load a version 1 of your user data, you do not want it to crash. To do this, put some if statements in your Recall() method so it only reads new properties if the save version is at a certain point.Something like this:

X = br.ReadInt32();
Y = br.ReadInt32();
NAME = br.ReadString();
if (fileVersion >= 2){
   MoreData = br.ReadInt32();
}

I hope this helps and motivates people to write plugins for NESMaker! If you have coded a cool technique, and want to support the community, put it in a plugin, and allow everyone to try it. Thanks to everyone for reading this, and good luck making your games!