Skip to content

Introduction to Game Mode Development

redwall_hp edited this page Feb 26, 2017 · 1 revision

AthenaGM's core principle is to do as much as possible to cover functionality shared by many game modes, while employing a modular philosophy to game mode specific logic. Each game mode is implemented as a separate Bukkit plugin that shares AthenaGM's Events and public class APIs. So if you want a King of the Hill game, you need to implement that specific gameplay in a plugin that works with AthenaGM.

This guide will illustrate the basics of developing a game mode plugin for AthenaGM, using the very simple example of "Sponge King" as an example. The goal: build a game mode where one team wins if they place ten sponge blocks on top of a beacon before the other team can.

  1. Starting Your Plugin

This guide assumes that you already are familiar with Bukkit plugin development and have already set up a basic skeleton project. Once you have your SpongeKing project created, you'll need to add AthenaGM as a Maven dependency in your pom.xml:

<dependencies>
        <dependency>
            <groupId>org.spigotmc</groupId>
            <artifactId>spigot-api</artifactId>
            <version>1.9-R0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>io.github.redwallhp</groupId>
            <artifactId>AthenaGM</artifactId>
            <version>1.0.4</version>
        </dependency>
</dependencies>

You'll first have to check out the AthenaGM source, and then build and install it so Maven can find the dependency. Only then will your plugin build.

git clone https://github.com/redwallhp/AthenaGM.git
cd AthenaGM
mvn clean package
mvn install
  1. Basic Plugin Structure

A game mode plugin has two important responsibilities:

  1. It must check to see if AthenaGM is running, and safely not do anything if that check fails.
  2. It must ensure, in every Bukkit event it listens to, that it only applies its custom logic in a Match with the game mode name specific to the plugin. (Maps define a gamemode key that determines which game mode plugin should spring into action to handle the Match created from the Map.)

Here is an example of a basic plugin class:

public class SpongeKing extends JavaPlugin {


    AthenaGM athena;


    @Override
    public void onEnable() {
        if (checkAthena()) {
            new SpongeListener(this);
        }
    }


    /**
     * Load the server's AthenaGM instance, returning false if AthenaGM is not installed.
     * @return true if AthenaGM is installed and active, false otherwise
     */
    private boolean checkAthena() {
        Plugin plugin = getServer().getPluginManager().getPlugin("AthenaGM");
        if (plugin == null || !(plugin instanceof AthenaGM)) {
            this.setEnabled(false);
            return false;
        } else {
            athena = (AthenaGM) plugin;
            return true;
        }
    }


    /**
     * Get the server's AthenaGM instance
     * @return AthenaGM instance
     */
    public AthenaGM getAthena() {
        return athena;
    }


}
  1. Example Listener Class

This example class illustrates the use of AthenaGM events and methods, including safety checks to ensure that we're not operating on an event from a different Match.

Using a regular BlockPlaceEvent, we increment a team's score every time they place a sponge block. At the end of the Match, Athena will declare a winner based on this score.

public class SpongeListener implements Listener {


    private AthenaKOTH plugin;


    public KOTHListener(AthenaKOTH plugin) {
        this.plugin = plugin;
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
    }


    @EventHandler
    public void onMatchCreate(MatchCreateEvent event) {
        if (!isSK(event.getMatch())) return; //return early if this isn't a Sponge King Match
        //do any setup needed here
    }


    @EventHandler
    public void onMatchStateChanged(MatchStateChangedEvent event) {
        if (!isSK(event.getMatch())) return;
        if (event.getCurrentState().equals(MatchState.ENDED)) {
            //do end of match things and clean up any objects we won't need after this Match
        }
    }


    @EventHandler
    public void onBlockPlace(BlockPlaceEvent event) {
        if (!isSK(event.getMatch())) return;
        if (event.getItemInHand().getType().equals(Material.SPONGE)) {
            Team playerTeam = PlayerUtil.getTeamForPlayer(plugin.getAthena().getArenaHandler(), event.getPlayer());
            PlayerScorePointEvent event = new PlayerScorePointEvent(event.getPlayer(), playerTeam, 1);
            Bukkit.getPluginManager().callEvent(event);
        }
    }


    /**
     * Check if a given Match/Map is calling for a KOTH gamemode
     * @param match The Match to check
     */
    private boolean isSK(Match match) {
        return (match.getMap().getGameMode().equalsIgnoreCase("spongeking"));
    }


    /**
     * Check if a given Player is in a Match/Map calling for a KOTH gamemode
     * @param player The Player to check
     */
    private boolean isSK(Player player) {
        Arena arena = PlayerUtil.getArenaForPlayer(plugin.getAthena().getArenaHandler(), player);
        return (arena != null && isSK(arena.getMatch()));
    }


}
Clone this wiki locally