Quake2 Cluster Project
An addition and modification of iD Software's Quake2 shared library sources which enable Quake2 servers running this library to interconnect other servers which speak the protocol developed under the Quake2 Cluster Project.
Copyright (c) 1998 Justin Randall and Todd Bliss

Preamble:

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.

This program is distributed in the hope that it will be 
useful, but WITHOUT ANY WARRANTY; without even the implied 
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.  See the GNU General Public License for more 
details. You should have received a copy of the GNU General 
Public License along with this program; if not, write to 
the Free Software Foundation, Inc., 
59 Temple Place - Suite 330, 
Boston, MA  02111-1307, USA.

See COPYING.txt for more information.


More info: http://www.planetquake.com/logic

QUICK START Example: a 2 Server Cluster
Server1
quake2.exe +set dedicated 1 +set game cluster +set admin_password foo +map base1 +set deathmatch 1 +set port 27910
Server2
quake2.exe +set dedicated 1 +set game cluster +set admin_password foo +map base2 +set deathmatch 1 +set port 27920

Connect to Server1
press your ~ key on the client to bring up a console
enter: password foo

Go to the exit elevator on base1, we will put our exit there
enter: cmd spawn exit base1base2
enter: cmd link base1base2 Server2      (Whatever Server2's IP address is)

step just outside of the elevator
enter: cmd spawn entrance base2base1

OK, this server is set up, lets perform a similar process on Server2
Go to the default entrance elevator on Base2 (Server2's map)
enter: cmd spawn exit base2base1

Step outside the elevator
enter: cmd spawn entrance base1base2
enter: cmd link base2base1 Server1       (Whatever Server1's IP address is)

After a couple of seconds, an exit should appear (glowing BFG blast) in the elevator. Walk through it to test the connection.



Introduction:
The Quake2 Cluster Project was born on January 4th, 1998. Actually, the concept behind the project was born in the days of Doom when the ramifications of networked, first-person shoot-em-up games were realized. It wasn't until Quake2 that such a project seemed feasable.

Overview:
A Quake2 Cluster is a coordinated, logical aggregation of quake2 servers. The whole concept of Master/Slave servers has been removed as of version 0.3. Connectivity is now defined by the link entities between systems. 

Joining the servers, from a player's perspective, consists of using a series of "interlinks". Interlinks are entities spawned by an administrative player in the game. They have a name, and describe a destination map that players should be transported to when the interlink is used. Which servers belong to which maps are really not relavant to creating these entities. That's all handled by the database. If a server handling map base2 dies, and another server running map base2 starts and registers with the database, it will take the old server's place as a viable destination for clients. The master translates the interlink's destination map to a server address for the client.

Interlinks can be dynamically added to and removed from any server in the cluster. Whenever a change in the status of the interlinks is detected, a file is saved on the server. If the server crashes or is shutdown, the interlinks will be reloaded when the server is started.

Instructions:

1. unzip the game distribution into your quake2 directory. Be sure to unzip ip recursively (pkunzip -d, "use folder names" in winzip, or tar zxvf on Linux). This will create a directory called "cluster", with a "game" directory beneath that which contains the source code and copying info for this modification.

2. start the server: quake2 
	+set dedicated 1 
	+set deathmatch 1 
	[+set admin_password <password>] 
	+map <mapname>
	[+set rcon_password <rcon password>]
	[+set port <port #>]         *See note
Parameters in []'s are optional. This mod should be run only on a dedicated quake2 server. "+set deathmatch 1" overcomes some CPU utilization issues in iD's 3.10 patch for quake2. "+set admin_password <password>" sets the cluster administrator password. A client is authenticated using his password variable, so if you want to administer your cluster (add/remove interlinks, list exits, etc..) set your password on your quake2 client by typing 
 set password "the password I used on the server comand line"
at the q2 client console. (press ~ to bring up a console on the client). 

"+set port <port #>" is option, *NOTE: if you are running MORE than one instance of a cluster server on a machine, you MUST set the port number on subsequent instances of the server. This is true for any quake2 server machine that is running more than one game at a time.

The admin_password defaults to "logic", so unless you want everyone in the world to create and remove exits from your cluster, you will need to set this parameter.

The port defaults to 27910, and the map will default to base1 if they are omitted.

If there are multiple cluster servers running on the same machine, then the first one started is running the database. The rest detect this and terminate their referral database processes. If each server in the cluster is on a different machine, then each server will be running a database process. 


Client CMD's

cmd spawn exit <exit name>
This creates an exit link entity. The name is not important until you go to link it. The ENTRANCE on the other server that this entity will link to MUST have the same name! No exit will appear until there is a valid link between servers. If the remote server is full, the exit will not appear (don't worry, it is there).

cmd spawn entrance <entrance name>
This is the other side of the link. Multiple exits can point to the same entrance *as long as they all have the same name*. The entrance entity sends information to various exits on the network --that it exists, and that it will or will not accept players on the server (e.g. full server). Entrance entity names MUST be unique for each machine (just the machine, other machines on the network can have entrances with the same name).

cmd link <exit name> <server address>
This links an exit entity to an entrance entity on the remote Q2 server. The entrance entity must have the same name as the exit that is linking to it. There is no need to know the port number of the remote q2 server. There is a referral service running on the remote system that will point the exit to the correct instance of quake2. 

cmd delete link <name>
Removes a link entity from the server. If it is an entrance, then all of its corresponding exits on the cluster will turn off (not be deleted, just turn off).

cmd list links
Lists all of the link entities on a server, along with a brief status. Entrance entities are always ready to accept connections. Exit entities are either NOT YET LINKED, LINKED TO, or WAITING FOR A HEARTBEAT. If it is NOT YET LINKED to another server, then issue a cmd link <exit name> <server address>. If it is WAITING FOR A HEARTBEAT, then be sure that the entrance on the remote server exists and has the same name.

cmd list servers
Lists all servers participating in the cluster. It is partially broken in this version of the protocol. Servers that leave the cluster are not properly removed from the list.

cmd invinc <player | all> [<time>]
This command grants temporary or permanent invincibility to the player specified. If ALL is specified, then it is applied to all players on the server. If the optional <time> parameter is omitted or set to -1, then invincibility is permanent. If it is set to 0, then it returns the player state to normal. If it is > 0, then a player will be invincible for that many seconds. Players with temporary invincibility have the white "god" colorshell around them. This is automatically set for 10 seconds on respawn. Players with permanent invincibility are invisible, and only their gun model is displayed --pretty cool to see a gun walking around the level. This is intnded for administrators to observe and maintain their servers without getting gibbed while working.

cmd go_hook
This creates the following aliases for Pericle's swinging hook:
alias +hook "cmd hook action; wait; cmd hook shrink"
alias -hook "cmd hook stop"
alias +shrink "cmd hook shrink"
alias -shrink "cmd hook stop"
alias +grow "cmd hook grow"
alias -grow "cmd hook stop"
bind SHIFT +hook
bind w +grow
bind r +shrink


**************************************************

Source distribution

The Cluster Project includes sources. It is GPL'd (see preamble and COPYING.txt). It means, essentially, that you can modify the program, you can even charge a fee for distributing the program, but the software itself can be held and exchanged for free. If you modify it, you *MUST* redistribute the modified sources or make them readily available to anyone that wants them (e.g. if they download a dll from your site, then the sources should be right there for access as well). It also means that the authors retain copyrights to their portion of the source. If your libraries are built against this code, then it too falls under the same conditions of the GPL. Please read it carefully. If you are trying to do something commercially with this code, contact the author for alternative licensing. 

If you are trying to build a kick-ass, free quake2 mod, then have at it. This was written for you.

About the source:
First let me qualify everything in the source tree by stating that I am *not* some kind of star programmer. I knew enough to get this thing working, and when I didn't know enough, Raptor (the code-king himself) was kind enough to point me in the right direction. I would like to thank him here and now for his help teaching me about threads and mutex's in a win32 environment, and his occasional prods about weak points in my coding style. He is included as an Author for his important technical contributions to my own knowledge, and his avowed interest to grow this source tree with me.

Rules about the rules.c
Most modifications should live in rules.c. I have made *some* callbacks from id's source to functions in rules.c, hopefully enough to get most mods working. 

I plan to make 2 abstraction dll's from the game source: cluster.dll, and a rules.dll that lives in a plugin directory. If it's at all possible, I want to make an additive plugin spec for dll's on the cluster (or q2 in general). 

The Cluster Project is a work in progress. If there is something you, as a mod author, need access to in the id source tree, and cannot use in rules.c, please email me and I will make the necessary modifications to the API. I want mod creation to be as painless as possible with the Cluster Project.

====================================================================
RULES_ClientUserInfoChanged(edict_t *ent, chart *userinfo)
CALLED FROM ID SOURCE, This function MUST exist somewhere in your rules.c

This function is called whenever a player updates variables on the client (e.g. I use it to check the password and to get the exit-name the player used to determine the spawn point in the cluster). This is very usefull if you set client side variables and want to retreive them on another server.

====================================================================
RULES_CheckInvincibility(edict_t *ent)
CALLED FROM cluster_links.c to check invincibility, without which the respawn function telefrags --nasty loop can start if 2 or 3 players respawn over and over on each other, server will die. 

If a client is invincible (defined by ent->rules.RespawnInvTimeOut), it will set the model effects, takedamage values, etc... If the current system time (returned from time()) is < RespawnInvTimeOut, then the player is returned to a normal state. This is called during RULES_ClientThink2() to keep the invincibility status up to date. It returns 1 if the player is invincible, 0 if the player is not.

====================================================================
RULES_SetInvincibility(edict_t *ent, int seconds)
CALLED FROM rules.c: --it is there to ensure that the client is invincible when spawning. 

Sets the players's invincibility. If seconds == 0, then invincibility is removed. If it is -1, then invincibility is permanent.

====================================================================
RULES_ClientThink2(edict_t *ent)
CALLED FROM ID SOURCE: p_client.c: ClientThink()

Every time id's own ClientThink function is run, ClientThink2() is called after id's own think routine is complete. I will be adding RULES_****1() functions that are called before id's own as well.

====================================================================
RULES_CmdInvinc(edict_t *ent)
CALLED FROM RULES: rules.c: RULES_ClientCmd

This function is expendable, extendable, whatever. It handles the cmd invinc <player | all> [<time>] function in the game.

====================================================================
RULES_ClientCmd(edict_t *ent)
CALLED FROM ID SOURCE: g_cmds.c

Any command processing your mod would do should happen here. 

====================================================================
RULES_CmdHelp(edict_t *ent)
CALLED FROM cluster_interpreter.c

Additional RULES cmd's are listed to the client.

====================================================================
RULES_MOTD(edict_t *ent)
CALLED FROM rules.c

Sets parameters on the edict_t rules structure to determine what to print, how long to print it, etc..

====================================================================
RULES_PutClientInServer2(edict_t *ent)
CALLED FROM ID SOURCE

Whenever a client respawns or is put in the server the first time, id runs a few setup routines. After id is done doing their thing, I call RULES_PutClientInServer2. Any additiona spawn functions you want to integrate should go here.

====================================================================
RULES_ClientBegin(edict_t *ent)
CALLED FROM ID SOURCE: p_client.c:ClientBegin()

Called as the last item in ClientBegin. This function is *NOT* called from id if it is a deathmatch game.

====================================================================
RULES_CmdClusterSay(edict_t *ent)
CALLED FROM cluster_interpreter.c:Cluster_CmdBPrintf()

If this function returns 0, then the broadcast message is not sent.



====================================================================



***************************************************

Final notes:

This is WAY alpha software. It works where I test it. If it doesn't work for you, send me some email and we'll see if we can make it work.

If you have found a bug that can be reproduced, send me a detailed description of the bug. Include information about your server platform, how many users are connected when you notice the problem, etc... 
My email address is logic@logic.columbus.oh.us. 

Bug fixes will be rolled into the next point release.

If you make a modification, and think it belongs in the main source tree, send it to me and I will roll it in and credit you for it.
