Creating custom zones with the new bz_CustomZoneObject class

Questions, comments, and news on the server side plug-ins and it's API
Post Reply
User avatar
Breaker of Builds
Breaker of Builds
Posts: 784
Joined: Sun Feb 17, 2008 10:01 pm
Location: /dev/null

Creating custom zones with the new bz_CustomZoneObject class

Post by allejo » Fri May 22, 2015 5:03 am

I'm here to talk about a new class in the BZFS API that can be used to make handling and creating custom zones far easier than they ever have. As of commits 8492417 (and for Windows, commit ca88d84 thanks to blast for fixing what I broke), there is a bz_CustomZoneObject class in the API that can be used to create your custom zones.

What does this all mean? Before this, plugins like FlagStay, KOTH, and WWZone all had their own logic for handling custom zones separately and were limited with how they worked; a plug-in author had to write the logic for checking if a player was inside a zone and storing all the information about a zone's size and location and that's what this class is intended to do.

I will be using the CustomZoneSample plug-in, that is now part of the project and will be included in the next distribution, as an example.

Creating a Zone object

In this part of the code, I'm creating a class that will represent a single zone. Each zone will contain data about a flag and contain a message to be sent to players.

Code: Select all

// Our zone will be extending the class from the API
class MsgZone : public bz_CustomZoneObject
  // Our custom constructor will call the parent constructor so we can setup default positions
  // for the zone
  MsgZone() : bz_CustomZoneObject()
    message = "";
    flag = "US";

  // Custom fields that are unique to our zone so we can build on top of the class we're extending
  std::string message;
  std::string flag;
Storing Zones

I'll store all of our zone instances in a vector for easy access. You may use an array, list, etc.

Code: Select all

std::vector<MsgZone> msgZones;
Registering Zones from a BZW file

In the MapObject() function that we'll be overloading, we're going to use the bz_CustomZoneObject's handleDefaultOptions() function to handle the following information:

For rectangular zones:
  • position
  • size
  • rotation
For circular zones:
  • position
  • height
  • radius
This function also handles the BBOX and CYLINDER syntax, but those fields are now deprecated and will be dropped in the future.

Code: Select all

bool CustomZoneSample::MapObject (bz_ApiString object, bz_CustomMapObjectInfo *data)
  // We'll ignore any map object that isn't a MSGZONE
  if (object != "MSGZONE" || !data)
      return false;

  // The new zone we just found and we'll be storing in our vector of zones
  MsgZone newZone;

  // Loop through the object data and pull out the "message" and "flag" fields
  for (unsigned int i = 0; i < data->data.size(); i++)
    std::string line = data->data.get(i).c_str();

    bz_APIStringList *nubs = bz_newStringList();
    nubs->tokenize(line.c_str(), " ", 0, true);

    if (nubs->size() > 0)
      std::string key = bz_toupper(nubs->get(0).c_str());

      // These are our custom fields in the MsgZone class
      if (key == "MESSAGE" && nubs->size() > 1)
        newZone.message = nubs->get(1).c_str();
      else if (key == "FLAG" && nubs->size() > 1)
        newZone.flag = nubs->get(1).c_str();



  return true;
What does this mean for map makers? You will finally be able to use fields such as "position," "size," and "rotation" instead of having to figure out what your position was in bbox syntax or in cynlinder syntax.

What does this mean for plugin developers? You only have to worry about extra information about zones, no need to worry about the math involved in calculating what the rotation of a zone is, or the height, or if a player is in the zone, etc.

Read more about the new syntax here.

How do I use this?

Simply call the pointInZone(float pos[3]) function in the bz_ePlayerUpdateEvent event with a float array.

Code: Select all

case bz_ePlayerUpdateEvent: // This event is called each time a player sends an update to the server
    bz_PlayerUpdateEventData_V1* updateData = (bz_PlayerUpdateEventData_V1*)eventData;

    // Loop through all of our custom zones
    for (unsigned int i = 0; i < msgZones.size(); i++)
        if (msgZones[i].pointInZone(updateData->state.pos))
            // Do something here, the player is in the zone

For more examples, take a look at the flagStay and wwzone plug-ins as examples since they are already using this new API in the latest 2.4.x branch. There's also KOTH, but that's a nightmare.

Feel free to ask any questions or ask for clarification with anything I discussed.

Post Reply