Minecraft Modding: Coding Style Recommendations

Background


Although there are many opinions on coding style in general, there are certain recommendations for being consistent with the modding community (which aids in sharing code) and for "good" programming practice (usually meaning improves the readability, debug and maintainability).

Regarding Recommended Text Case For Mod Code


Although Java might let you name your fields and methods any crazy thing like a class called MYaweSOMECLass, there is a standard that has developed that is widely used. Using this standard greatly helps debugging because often a field, method and class might use similar or even same name, differing only in the way case is used.

General Java Recommendations


Classes should be "sentence case", meaning each word has initial letter capitalized. Example: MyCustomClass

Fields and methods should be "camel case", meaning that they start lower case, but use capitals for initial letter of each subsequent word. Example:  mySpecialMethod().

Constants should be "all caps", meaning all capital letters with an underscore ("_") between words. Example: MY_CONSTANT

Modding-Specific Recommendations


Thanks to Choonster for this information.

Mod ID: In the @mod or mcmod.info, modid should always be "lower case". This will be enforced in 1.11, at the moment it's only a recommendation.

Resource domain: in a ResourceLocation, resourceDomain should be "lower case" although technically it can tolerate other case styles because the domain is already converted to lowercase when you create a ResourceLocation.

Resource path: in a ResourceLocation, resourcePath should be "lower case". In 1.11 it will be required all paths in a resource pack (which mod assets are added as) to be lowercase.

Unlocalized names: For unlocalized names (of items, potions, entities, tool tips, custom text strings, etc. can be any case provided it match with the .lang file content.

Commands: in a command, it is recommended but not required to use "lower case" command names.

Damage Sources: a DamageSource is recommended to be "camel case".

Sounds: in a sounds.json file, the keys should be "lower case".
This isn't currently required, but it may be in 1.11 as SoundEvent stores the name as a ResourceLocation.

Property Enumerations: a PropertyEnum name and values should be "lower case" although technically it can tolerate other case styles because it is already converted to lower case when you used in a ModelResourceLocation.

Class Naming


It is considered more readable to name things starting with the class they extend. Also go from generic to more specific so they sort naturally. For example, if you have a custom crop block it is better to call it "BlockCropsCustom" rather than "CustomCropBlock". 

Use Encapsulation


Minecraft was basically developed by amateur programmers and also built up incrementally over the years, so frankly its style has several flaws. One of the most glaring is it is inconsistent in how it scopes the fields and methods in its classes. Some classes have private members that can't be accessed at all, some have private members that can be accessed through setters and getters, and some have public members that can be accessed directly.

"Good" practice should be to "encapsulate" your code. This means that the internal members and methods are all private and are accessed through a controlled API consisting of "setter" and "getter" methods.

The problem with classes that have private members without setters and getters is that it doesn't make modding easy.

The problem with classes that make the members public is that there is no control over what accesses them and how, so theoretically a mod could change them unexpectedly or unsafely.

Benefits of encapsulation:

  • The main benefit of using setters and getters is that it hides the internal workings of the class allowing you to entirely re-write it later without ruining any mod code that accesses them. In other words, it doesn't really matter how the class is coded as long as the public API methods can set and get information about the class in a well-defined way.
  • Another advantage of setters and getters is that you can qualify the input to avoid illegal values. If you had a public field called myEntityHealth and some other mod accesses it directly and sets it to a negative value, it may cause a crash or other weird behavior if some other code uses that value without expecting a negative value. So instead you could create a method for example setMyEntityHealth() which would check for valid values and only update the internal field if it is valid. It can also return a value to indicate whether the setting was successful.
  • In addition to checking that the values are valid, you can also make sure it is safe in terms of other conditions (including timing) to change the value.


So the general idea is that an encapsulated class should looks something like this:

public class myExampleClass
{
   private int myExampleField

   public boolean setMyExampleField(int newValue)
   {
      // check for valid values if you need to here
      // then copy to the private field
      myExampleField = newValue;
      return true; // return false if you reject the value for some reason 
   }

   public int getMyExampleField()
   {
      return myExampleField;
   }
}

Tip: Most IDEs (like Eclipse) have shortcuts to automatically insert setters and getters into your classes. In Eclipse the steps are as follows:

  1. Bring up the context menu (i.e. right click) in the source code window of the desired class. 
  2. Select the Source sub-menu
  3. Select Generate Getters and Setters... that will cause a wizard window will appear.
  4. Select the variables you wish to create getters and setters for.
  5. Click OK.


1 comment:

  1. "sentence case"...
    You couldn't be more wrong. It's PascalCase

    ReplyDelete