Skip to content

Instantly share code, notes, and snippets.

@EntityReborn
Created January 16, 2014 17:01
Show Gist options
  • Save EntityReborn/8458776 to your computer and use it in GitHub Desktop.
Save EntityReborn/8458776 to your computer and use it in GitHub Desktop.

Developing an extension

Extensions provide a means of adding functionality to CommandHelper and the MethodScript engine. While the API used is under construction still, it is still deemed stable enough for production use. Any breakages will be minimal, and deprecation will be used where it applies.

An extension currently consists of three core parts:

  1. The lifecycle class, which takes care of the life and identity of the extension.
  2. Events, which add new events that MScript can use, and
  3. Functions, which add new functionality to MScript. These can make use of the optimization engine as well, to be integrated with the MScript compilation process.

###LifeCycles

The lifecycle class is the central part of your extension and does two things:

  1. Provide identity to your extension.
  2. Facilitate lifecycle operations, such as system events, utility methods, etc.

The minimal definition is as follows:

@MSExtension("ExtensionName") // Place your extension name here!
public class MyExtension extends AbstractExtension {
    @Override
    public Version getVersion() {
        return new SimpleVersion(1,2,3); // Set your version here.
    }
}

The class name given by the definition doesn't matter, but does assist with debugging in case of a stacktrace. See the source code of AbstractExtension for the full set of methods available to this class.

###Functions Functions will usually be the first thing a simpler extension will be used for. Usually, functions are "wrapped" in a parent class, which provides general documentation for that group of functions. The full class definition for functions is as follows:

public class FunctionGroup {
	public static String docs() {
		return "These functions provide an example to new extension creators!";
	}

	@api
	public static class some_function extends AbstractFunction {
		<required methods>
	}

	<more functions>
}

While functions can be "integrated" into the compiler as well as set up to optimize, those are beyond the general scope of this document. One can join our channel #CommandHelper on irc.esper.net and discuss this with us directly!

###Events Events are a three part thing:

  1. The bindable object, which acts as a wrapper or data carrier for the event. This will be a POJO with methods to get the data you need.

  2. The actual extension point, which converts the bindable object into a MethodScript enabled event, with supporting methods.

  3. The actual call to fire the event.

The bindable event layout is simply a class that extends BindableEvent, with one override, _GetObject(). If wrapping a Bukkit event, the bukkit event should be returned here, given that you instantiated your BindableEvent instance with one. Otherwise, just return null.

The actual extension point is laid out as follows:

public class EventGroup {
	public static String docs() {
		return "These events provide an example to new extension creators!";
	}

	@api
	public static class some_event extends AbstractEvent {
		<required methods>
	}

	<more events>
}

Notice that the event classes extend AbstractEvent. As one can see, the layout is very similar to that of functions.

Events can be triggered from anywhere, with a call to EventUtils.TriggerListener(Driver.EXTENSION, <event name>, <event instance>);. The event name given must be the same as given in the event you have defined, and the event instance an instance of that event.

###Maven Our build and dependency manager of choice is maven. While a quick and dirty setup with a bare-minimal pom is possible, you'll miss out on run-time speedups and compile-time checks if you don't include a few details.

Please include the following snippit under your <build><plugins> section in your pom:

<!-- Leave this alone! Compile-time checks so that your extension works. -->
<plugin>
    <groupId>org.bsc.maven</groupId>
    <artifactId>maven-processor-plugin</artifactId>
    <version>2.2.4</version>

    <executions>
        <execution>
            <id>process</id>
            <phase>process-classes</phase>
            
            <goals>
                <goal>process</goal>
            </goals>
        </execution>
    </executions>

    <configuration>
        <outputDirectory>src/main/generated</outputDirectory>

        <processors>
            <processor>com.laytonsmith.core.extensions.ExtensionAnnotationProcessor</processor>
        </processors>
    </configuration>
</plugin>

<!-- Leave this alone! Run-time extension loading speedup. -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.2.1</version>

    <executions>
        <execution>
            <id>cache-annotations</id>
            <phase>process-classes</phase>
            <goals>
                <goal>java</goal>
            </goals>
        </execution>
    </executions>

    <configuration>
        <mainClass>com.laytonsmith.PureUtilities.ClassLoading.Annotations.CacheAnnotations</mainClass>

        <arguments>
            <argument>${basedir}/target/classes</argument>
            <argument>${basedir}/target/classes</argument>
        </arguments>
    </configuration>
</plugin>

###Obfuscation/ProGuard Some extension devs have expressed a desire to obfuscate their code. Unfortunately, there's a gotcha: the caching system we use runs before ProGuard obfuscates things, causing the original class names to be saved to the cache instead of the obfuscated ones. The only way currently known to get around this is to tell ProGuard to not obfuscate any of the extension points (lifecycle, function or event classes), via the -keep class option in the plugin's configuration section.

However, one should be able to use the annotated extension points as wrappers for the true code, which would reside in a different class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment