Update notice 2:
Although it was frozen, I continued developing a bit and the very basics are almost complete. Ignore the update notice.
This project has been released/quit - the code, documentation and a few words are a bit down.
Today, I’d like to talk a bit about ZS, a gamemode I started developing a few months back. I wanted to have a RP gamemode that I know inside out, that was easily adjustable (for clients and the server), easily maintainable, documented, generic to some extent (i.e. fitting for all possible RP modes and themes, not just one), extendable, does not rely on networked variables and all in all uses as less space or traffic as possible while still being able to offer an open RP environment that does not rely too much on the script. This introduction is a bit sober, including the screens. It’s all using the Derma default skin and therefore it’s not really impressing at all - however, design is one of the last things I will do, if ever. For me, functionality is way more important. Also, it’s very technical because that’s more interesting in my humble opinion. However, if you skip this wall of text, you will find a shorter list of features along a list of things that I are not going to be in ZS as well as a list of things that are planned - and at the very end, I could need a bit of help.
It was written completely from scratch and did not have another script as target. That means, at no point I wanted to replace a certain script or have its functionality completely. However, I can say that it was somewhat inspired from TacoScript, 1 and 2.
One of the most important things was the open environment. In my opinion, a script should guide and support players in their RP experience, not restrict them. In addition, GMod RP is always heavily text based - there might be animations, guns and all in all a three dimensional world but in the end, the important stuff happens in a chatbox.
Therefore, the chat was one of the first things that was completed and one of the most advanced. ZS uses a system called OLM for chat messages. OLM splits up too long messages into several chunks to send them. In addition, OLM is heavily customizable on the client side: Every chat message type (so called MessageFilters) is shared between server and client, allowing them to define the type of a message using a simple char (and therefore restricting the amount of possible filters to 255 - but then again, who’s going to use about 255 different types of chat). On the client side, these tables can easily be modified to adjust the feel-and-look: For the basics, the color for the name and the chat message as well as the font can be defined and changed on-runtime (although they are not saved, there are plans for a options GUI that allow to change these values easily). For advanced users (and the script itself), it’s possible to define a lua function per filter which "refines” the incoming messages. For example, this function prefixes all YELL messages with "[YELL] " - but it’s not restricted to that. Changing names, text, re-structuring the way it is displayed and more is possible using that little function.
The chatbox itself supports tabs. However, these tabs are not hardcoded - it’s possible to add, remove or change tabs on runtime. However, you can define what message should be delivered into what box. In addition, the chat has a target channel display, i.e. it shows what channel you are talking right now (as an example, writing "/y " will change the target to "Yell”, erasing the chat message. Upon sending, the "/y " is attached again so the server can understand it). This applies for all commands and aliases that are defined as well as private messages (/pm), which is using the ZS command target system to show you directly if your PM will hit somebody or not. Also, it has an input history - you are able to browse between earlier sent messages using the up and down key. Using a bit of lua, it’s possible to add additional aliases for each of those types - for example, it’s possible that "!” on the beginning of a line is interpreted as a YELL message automatically using one function call (ZS.AddAlias(’!’, ZS.MessageFilters.YELL)).
ZS also provides a logging tool for chats which allows logging the chats completely into the database including the time, the sender, the receivers, the message and what kind of message it was. Therefore, it’s possible to completely re-construct the chat for a person (within a certain timeframe). This will later be used in a complaint form - players will be able to give admins the permissions to view their RP log within a certain timeframe that they can choose. For example, I can choose to provide 30 minutes of my log and every admin that can view complaint forms can see these 30 minutes as well. Directly from the database, no screenshots required, no way of manipulating them (there is really no reason anybody should mess around with the ZS database outside of ZS, with exceptions being ZS.web)
If you ever played World of Warcraft, the chat is pretty much like that - except that you can’t drag tabs around to form new chats and there isn’t a settings GUI right now. But it’s already planned.
As database, ZS relies on MySQL. However, I’ve written a wrapper for it - the script itself will never call any mysql.* function directly. In addition, this wrapper handles escaping and "threaded queries”. Threaded queries are queries that are sent but do not return immediately. Instead, ZS queues them and executes them one after another. As soon as the first query’s results are available, the (previously given) callback is called with the result as argument. Like timers, these callbacks can have a variety of other passed arguments. After the callback was executed, the next query in the queue is executed and history repeats itself. These queries are not "blocking” the server and should be used whenever possible. However, I’ll be honest: Most of the queries ZS uses do not rely on this technique because it can get really annoying with callbacks after callbacks. However, this might change in the future.
Another more dynamical thing in ZS is the flag system. There are two different flags: One per-player (bound to SteamID), one per-character. Also, it’s not possible to set complete flag strings. Instead, you can only set or unset a single flag at a time. This is supposed to avoid setting the wrong flag or an invalid flag string. However, both have the same functionality, they are stored in a lua table and can have various callbacks. These callbacks are either event based (upon connecting/selecting a character, upon any spawn, upon getting the flag set or unset) or permission based (can X set the flag for Y, can X unset the flag for Y). Additionally, flags have at least two letters, of which the first is uppercase and all following are lowercase. This allows grouping of flags - for example, all administrative flags are within "A” - developer is "Ad”, super admin is "As” and basic admin is a simple "Ab”. Flags are also required to have an unique name which identifies themselves in the script. For example, to check if somebody is a developer, you can use ply:IsDeveloper. This string is also sent upon (un-)setting a flag so you know what flag was just (un-)set.
However, for some things, flags are just too strict or too inaccurate. For example, prop limits or ragdoll limits. ZS introduces player and character variables for that. There are three different "levels” of them: The ones that are saved directly in the
players table (and therefore require a table change), the ones that are saved in
playerVariables and do not require a change, but generate some overhead when used with common variables, and the ones that are only existing on runtime. Each of them can be defined using one function. After that, set and get functions for these variables are available. ZS handles the storing completely independent, it doesn’t matter what kind of variable it is, you call the function, ZS stores it. If you want to change the type later, you are not required to rewrite the script (but of course need to re-structure the database). All in all, it’s possible to store additional player or character data in an easy accessible way.
Speaking of storing things, let’s talk about inventories. ZS uses grid-inventories. A grid is a table with a predefined width and a certain height. Items also have a width and a height. Unlike some other scripts however, ZS does not have one giant grid per character but more, smaller grids. For example, each character starts with two grids (think of them as the right and the left pocket), each 2x2. This isn’t enough to carry a weapon anywhere else but in your hands. And while this restricts roleplay to a certain amount, it’s more important that players cannot run around as walking armories. However, if you wish to, you can modify it easily to have just one giant grid - ZS won’t care how many inventories you define. However, due to database storage things, you can only define up to 255 different inventory templates. But who is going to define more than 255 different inventories anyway?
However, let’s come back to items: Items that are placed in a grid block that spot in the grid, therefore disallowing other items to take this space. To avoid having unpleasant gaps in the inventory that are unusable, they can be rotated by 90°. In addition, certain items can add additional grids, for example could a backpack give you an additional, unique 3x3 grid (unique as in "It’s not possible to stack 140 backpacks to have a mega inventory”). This does not solve all problems with grid inventories, but it’s the best implementation of an inventory that I could think of with the least disadvantages.
And back to items again: Items are lua tables/objects that can be attached to an entity. This allows items to remember their state even when they are dropped and picked up again. Also, they are serialized upon saving them into the database and deserialized once they are loaded again. Therefore - assuming the item was coded properly - nothing can get lost.
Items are also always behaving like SENTs in certain aspects. For example, items can always communicate with players and vice versa. ZS broadcasts messages not only to players but also to items, giving them the opportunity to parse the message. This could, for example, allow in a wire that broadcasts whatever it hears directly to your PDA or whatever. Or they could react to certain chat input, for example giving simple responses upon simple questions (having a lamp that insults you whenever you yell? No problem!) This does not only apply to items but any entity that has the callback for chat messages. This will be useful in dynamic mapping.
To make life a bit easier for coders, ZS contains so called wizards. They are more or less the same as you know them from installation programs - page-by-page applications. Wizards validate the input given and can therefore already tell if an input will be rejected by whatever processes it. So far, the only wizard used is within the character creation where it sends its data to the server at the end. They are a bit boring to describe but allow to easily creating forms to gather data from an user. For example for the character creation, a feedback form, a complaint form, anything that requires a bit more input.
Animation-wise, it’s a bit boring: ZS is using pre-defined tables that contain the sequence name or an array of sequence names (in which case a random one is picked). This doesn’t allow us to play animations that are not defined in the original models, but it’s enough I suppose. After all, I still stick to the idea that GMod RP is more a text RP than a graphical one - it would just be dessert and there are more important things to focus on right now.
"Dynamic maps” is a term I made up at some point. Basically, it means that you can re-shape the map at runtime to make it more fitting to your community needs. This does not mean reshaping it in the real sense; it is restricted, more or less, to entities. Dynamic mapping is a lua script that is executed upon map change and removes or changes existing entities or adds new ones. An example for dynamic maps could be that you add buttons to open certain doors (which can be spawned again by the script). It is not implemented yet, however, I made some thoughts about it and probably already wrote an essay in my internal forum about that.
Kind of behind the scenes, but a pretty nice feature: Custom CVars. That sounds a bit odd, and perhaps it is. Basically, it’s an API that allows developers to add client console vars and access their values easily as well as assuring that they are in-range for whatever cause might serve. For example, until the chat configuration is implemented completely, the chat behavior (when tabs fade, how long they take for that, when lines fade, how many lines are saved in the history) is saved in various cvars that are all prefixed with zs_ and are accessible using a simple function. In this case, ZS assures that the numbers are always greater or equal to zero and less than a reasonable time.
The last point on the technical part is ZS.web. ZS.web is a collection of Perl scripts that can be used to give users web access to some things, for example lists of users that just play, played in the last X minutes, list of administrators, users with a certain flag, chatlogs and more. For chatlogs, I could imagine that it’s possible to have a Steam OpenID login to access more sensible parts. However, the web and the script itself will be kept differently, meaning that it will be necessary to configure ZS.web on its own. Of course it’s possible to access the database with any script in any language you wish, it’s not restricted to Perl. However, the example code I will provide will be in Perl.
Okay, that’s it for the talk-a-lot part. Although it might sound like it’s not much, I think it is. However, without seeing it in action, it’s a bit hard to describe it. For now, let’s just say that I really put a lot of thinking into everything I made - and basically, I’ve written whole essays about certain features before I even began implementing them. Now, the more easy-to-read part with a few lists describing things that are already implemented and things that need to be implemented… soon.
Features to date:
[li]A stable database wrapper that could be used with almost any SQL compliant database system, including less important queries and escaping. Per default powered by MySQL which allows external scripts easy access - for example web access, dynamic generated user-, admin- or playerlists[/li][li]Player and character variables, allowing easy storing and accessing of dynamical data per player or character.[/li][li]Wizards as an UI element to get valid data from users in a simple and fast way with the option of being easily extendible[/li][li]Behind the scenes: A response system that allows ZS to give users response to their actions, i.e. if they succeeded or not, and why not.[/li][li]Character creation using a wizard, character selection using a selection screen[/li][li]Characters having a name, two (optional) titles, optional age and a optional rather long character description.[/li][li]Looking at something (a player, a prop, an item, anything that has a scripted callback for that) will provide additional information (name, description) using a system that produces as less traffic as possible[/li][li]Behind the scenes: A so called cooldown system helps to keep cooldowns between two actions (for example selecting a character, creating a character, looking at something) on client and server synced, therefore avoiding unnecessary traffic by clients asking if they could do something[/li][li]Restricted toolgun and spawning of non-props[/li][li]Configurable prop- and ragdoll limits as player variables that can be per-player[/li][li]Behind the scenes: A stable chat system that can transmit chat messages of any length, however configurable-wise capped at 500 characters.[/li][li]A customizable chat interface that allows to define the look-and-feel of each type of chat line (say, whisper, yell, emotes, etc.) and a chat box that has fully configurable tabs, allowing users to set in what tab they want to receive what message[/li][li]Behind the scenes: Chatlogs that can be used to completely reconstruct the chat of a player or character[/li][li]Behind the scenes: An easy-to-access API that allows developers to add and control custom client cvars to change ZS’ behavior and look on the client[/li][li]Animation tables for the NPC models that should persist GMod updates and can be extended easily to add more models, including ones with different animation sets.[/li][li]Easily scriptable items (~ same effort as SWEPs) that can interact with characters through chat and keep their state upon being dropped or stored in the database. In addition, items can be derived from other items (therefore inheriting their attributes and functions).[/li][li]Grid-based inventories, as many per character as you want, as well as having a panel to view all of them at once, including drag-and-drop of items from one inventory to another and rotating items.[/li][li]The whole UI scales according to your resolution within predefined borders (target resolutions are 800x600 up to 1920x1080).[/li][li]A command targeting system allowing easily to find players using “RPName”, “>Steamname” or “#UserID”. This is shared and works pretty much everywhere, for example in PMs and all console commands. In case of PMs, it can give players feedback if the recipient can be found by the script, therefore avoiding to have to send messages again because of an invalid receiver.[/li][li]A pretty simple-to-use ITEM editor that allows to create or edit nasty stuff regarding items. Loads and writes directly lua that can be copypasted into the item definition.[/li][li]Behind the scenes: Various log and debugging functions on client and server help to debug code and spot errors easily (assuming they are used wisely)[/li][li]Behind the scenes: Various pre-defined API functions to handle common stuff, for example functions for admin commands that include target finding or argument count validation.[/li][li]Behind the scenes: Documented source code and a Wiki that explains the important mechanisms.[/li][/ul]
Features that are planned (and thought of) but not implemented:
[li]Special animations, i.e. knocking, throwing[/li][li]Dynamical mapping[/li][li]Option menus for the custom cvars, chat settings, flags and other related stuff[/li][li]A few performance tweaks (including getting rid of datastream wherever possible)[/li][li]A SWEP base[/li][li]A global chat interface ("radio API”) to allow entities to communicate over long distances over pre-defined open or secure (“encrypted”/“closed”) channels.[/li][li]Item crafting, item qualities and dynamic item spawns for low-quality items (perhaps put in a different modification)[/li][li]A simple-to-use API for chat commands on client and server (‘triggers’), allowing for example third party scripts to easily embed themselves into the chat[/li][li]Wearable items[/li][li]Several, different menus (AMX-like and some kind of ringmenu) that allow interaction with the server (e.g. votings) or the world (e.g. Use-menus)[/li][/ul]
Things that ZS will most likely not have:
[li]Jobs or anything like that. I want it to be an open RP environment where nobody is restricted to whatever he was voted right now or whatever hat he is wearing.[/li][li]An economy. If you want to have an economy within ZS, there might be a branch that adds that (extending the item tables, adding a character variable, a few user messages), but there won’t be anything economy like in the main core. ZS aims to be generic, not restricting, and it’s easier to add features than to remove them. Although there was some thinking regarding item shops (SNPCs, SENTs), item crafting and item spawns that would provide probably lots of passive.[/li][li]Some specific RP theme. Again, there might be example branches provided by me or somebody else later that show how to adapt ZS to various RP situations, but that won’t happen in the first few releases.[/li][li]Most likely any kind of stat system. It’s possible that some things (for example item crafting, is it ever to be implemented) is using something similar (for example, a techtree) but stats itself like “speed”, “health”, “strength”, “agility” won’t be implemented. All characters are the same, script-wise (this can change due to having certain items equipped, for example a vest)[/li][/ul]
A few screenshots
Keep in mind that the graphical design was not a point of ZS until now. ZS uses extended Derma skins to style itself and various fonts (although they all look the same, right now). Additionally, every UI element is created using ZS.UI.Create, which then involves various hooks for it - it’s possible to do small last-minute changes to elements before they are finally set and displayed.
All screenshots were captured on 1024x768. I’ll just link them with a short description instead of embedding them directly.
[li]A page of the character creation wizard. Invalid fields are highlighted, which is this kind of cyan in the default derma. This validation is done on client and server, of course.[/li][li]Character selection screen. Not much to say here - pretty simple.[/li][li]A bit of the chat while holding a bukkit (the first and pretty much only item so far).[/li][li]A bukkit reacting to the chat. A very simple reaction, it just does some conspiracy talk upon saying “bukkit”. The first line, the yelling from before, has already faded out.[/li][li]The item editor. It’s kept pretty simple but does the majority of the annoying job - the preview model position.[/li][li]And the last picture, the inventory. The inventories are templates (i.e. they have to be defined and are shared). Each inventory template has a width, height, a name, an ID and relative offset (relative to the panel’s complete width, the best thing that came in my mind regarding the scaling UI so far).[/li][/ul]
Why I am posting this at this stage:
The plan has been and still is to develop ZS alone until its first release (under the MIT license). There are various reasons for me to do this. Also, I am not looking for any kind of testers. What I need is some advice regarding some strange behaviors in GMod that I encountered and that I need help with. In addition, it’s always good to have a few more opinions about certain things.
For example, there are various unclear things. Should there be item crafting? In what way (like TF2, like Minecraft)? Can players disassemble items? Do they require tools to do that? What about stats? There are many open, but at the moment not important questions. As soon as I encounter a serious one that needs to be cleared ASAP I’ll post it.
I’m not sure if I was able to give a picture of the mode so far. Like I said, it isn’t going to be a precious designed thing. I aim at clean, maintainable code, not being pretty for a week.