The Future of Zombie Plugins
Introduction
The Zombie:Reloaded project has come to a stage where we need to change our development strategy. In this thread I will give a summary of the current state and what I think we should do next.
This is mainly a discussion for SourceMod developers, but anyone may join the discussion.
TLDR
We need a good standard zombie API and many small plugins that do their thing, and do it well.
Warning
I will do heavy moderation in this thread to make sure it stays on topic. This means that posts asking for support on ZR will be
deleted without warning. This is
not the place to ask for support or feature requests on released versions. You have been warned. However, don't let that scare you from posting questions or comments regarding the subjects I discuss below.
The Problem
The problem can easily be summarized with two words: time and energy. Though, it is a bit more complex than that.
Back in about 2008, ZR was in active development. Today, development has almost stalled completely due to lack of time or energy.
I am the only one who maintains ZR, except for Jargon who does great work on maintaining the unofficial version for CS: GO. Even though I have lots of ideas, development is going really slow. Everyone depends on me to fix a bug or implement a new feature. Strictly speaking they don't, since it's open source, but nobody wants to do it themself.
The result is one inactive developer and a plugin with very low maintenance. We need to fix this.
The Solution
The probably most obvious solution is to get a few additional developers to work on the ZR project. This doesn't solve the actual problem, since then everyone will depend on that team, which is just increased by a few persons.
I suggest a solution where we delegate the responsibility to multiple developers that create and maintain their own zombie game features.
In short, the solution based on this philosophy:
Do one thing and do it well.
Modularity
To achieve this goal, we need a modular plugin. In fact, we need multiple plugins.
Every feature should be its own plugin, with its own responsibilities. They should also react to changes in the environment so that server admins can hot plug features while the server is running (and possibly in the middle of a game/round)!
This will force developers to create robust plugins that are ready to handle any event at any time.
Feature plugins may need to communicate with eachother, or share data. That can be solved with a common extendable API (plugins that create natives in SourceMod). More about this later.
Security
First we need to solve another issue: security.
At the moment ZR is one big plugin binary. We have pretty good control of what we want to expose to other third party plugins (even though ZR's current API is quite small).
With a modular architecture, many features may depend on data from other features. We want to keep this communication restricted to only a sub set of the loaded SourceMod plugins in order to prevent potential malicious plugins messing up internal states in the features.
This is solved by an authentication manager that keeps track of which features each plugin has access to.
Feature plugins will then ask this manager whether a plugin has access to a certain native/feature. It's entirely optional for feature modules to use this manager. If all natvies should be public, that's just fine.
The implementaion of the authentication manager will obviously need a cache to avoid performance issues. Feature plugins could cache the result too.
What Happens to Zombie:Reloaded?
The ZR 3.x branch will continue to exist, as as long as the new solution is in development (4.0). New features will most likely not be added, and only critical game breaking bugs will be fixed (due to my time/energy issue). I keep reminding that everyone are welcome to work on ZR 3.x themself, though I'll have to review the code. Even then there's no one stopping anyone from publishing their own version as long as the source is available and credits preserved.
ZR already use an internal modular architecture. My idea is to move all features into individual plugins (or let other developers do that work).
The plan is to focus on a specification for an API that describes core parts and features in a zombie game. This is a pure specification and does not include any coding. I have some basic ideas on how this should look like, but everyone are welcome to contribute. This thread is for discussing that API.
The Ultimate Zombie Plugin API
We (you and me) are going to define a standard API for zombie games in SourceMod, simply called
The Zombie API!
The Zombie API will define how zombie games can be created on SourceMod. How the zombie games themself behave is undefined. It depends entirely on which feature plugins that exist and which ones server admins choose to install.
We already have a lot of code, and we're going to design the API in a way we can reuse our earlier work. Some modifications must be done, but not anything that would need a major rewrite of all features. Luckily ZR is somewhat loosely coupled and modular (mostly 4.0, but 3.x is usable too), so this isn't impossible.
The API will get a lot of inspiration from the SourceMod Project Base by Greyscale. Many of our issues are solved in that framework.
We also need to be careful when designing the API, since this should be a persistent API that many plugins may use. Newer versions has to be backwards compatible so that we don't break plugins during new releases.
The goal is that everyone can create a simple (or complex) feature for a zombie game, and by using this API their plugin can cooperate with other plugins. There's no need to modify and recompile a big plugin each time you add a new feature.
Extendable API
The most important feature of this API is that it should be extendable. We allow third party developers to declare new natives, events and forwards so that they can be shared between plugins. If someone make a new feature, they may also make an API for it.
This doesn't require any special code, it's just a rule or a convention. Basically we just define a folder structure to organize include files. We cover the core parts of the API that solves the technical stuff. Other features share their APIs in other files.
Example folder structure:
Module Manager
All these individual feature plugins need some coordination and a manager. This is essentially the same as the module manager in the project base framework.
Feature plugins register themself with the module manager plugin. They may also declare dependencies on other feature plugins.
In addition to the modules it also manages a list of named individual features. We need this so that modules can ask the module manager whether a certain feature exist before attempting to use it. This is almost identical to SourceMod's GetFeatureStatus except that our version will check for zombie related features.
In contrast to the project base framework, this module manager doesn't do anything itself. It's just a storage for declaring which features that exists. However, it should watch for when plugins are unloaded and unregister those features.
Event Manager
The event manager allows modules to declare and handle abstract events such as OnPlayerInfected or OnZombiesWin. These are pure forwards. Feature modules may create their own forwards by exposing their own API.
Note that these events should not be confused with game events such as player_spawn. Though, the event manager (or possibly a game specific adapter plugin) may hook events like player_team and player_spawn and convert them into abstract events. This will solve some issues with multimod support.
Forwards are global and an efficient way for sending notifications to plugins. Although there might be some cases where we want to filter events so that only certain plugins receive them. In that case it might be solved by using event hooks and callbacks. That also solves the security issue where unauthorized plugins won't be able to hook the event.
It's important to get type safety on events by using functags or wrappers. Bad code should crash as early as possible. The optimal case is to catch this at compile time.
Hot-plugging Modules
Modules should be prepared for any event at any time (where suitable). A module may be enabled or disabled in the middle of the game and should be ready to handle this, as explained earlier.
For instance, players may suddenly no longer have the teleport feature when the server admin disabled it, but now have new freeze grenades added by the server admin.
Multimod Support
Zombie games can be played on other games than just CS. Instead of creating a feature plugin for each game, we create one plugin that will run on all supported games (such as CS: S, CS: GO, TF2, HL2: DM, etc).
Most of the games have the same event names and similar features, but the parameters are different. Using abstract events we can hide these differences and provide a consistent set of events and natives. In some cases we could implement workarounds for stuff like a flashlight, or implementing rounds in a game that doesn't have it and create fake round start/end events.
Virtual Teams
Due to multimod support, and that a zombie game itself introduce new teams, we need virtual teams.
In the core API this includes zombies and humans, but it could be extended to multiple teams.
Virtual teams are mapped to actual game teams (CT/T on CS:S, Red and Blu on TF2, etc). This is handled by a team manager.
All feature modules use
only virtual teams so that the developers doesn't have to update their plugin if a new game is supported.
Implementing the API
Once we have an API specification, it must be implemented. This is where the community can join and implement their own features.
Libraries
When writing the implementaions you may often discover that you're making something similar to other works. In that case it's a good idea to move that code to a library so it can be reused by multiple features.
Write generic code when possible. Examples are libraries for logging, building menus, parsing config files. Also use SMLIB for simpler stuff. If you're writing something specific to a game, make a library for that game!
Conclusion
Strictly speaking there is none, yet. That's the point of this thread.
We need to figure out how to make it easier to extend zombie games with new features, because I don't have time or energy to do it all by myself.
We need a good standard zombie API and many small plugins that do their thing, and do it well.
StartDiscussion();
__________________