Jump to content
GIGN Forum

Plugins Lai Change /server


Recommended Posts

Sveiki, Nu man ir divi serveri, bet es velos dabut plugin, lai ieejot piemeram kz serveri uzrakstitu komandu /server un man paradiitos mans pub serveris ! un es 4ipa varetu uzreiz konnect pie vinja... ! esmu spelejis dazos serv kur tads plugin ir, bet shodien visu dienu mekleju nevareju atrast! moz kads paliidzes iedos link...

Link to comment
Share on other sites

/*

Server redirect plugin - ? 2006 x0R ([email protected]) - www.n-ice.org

License:

ЇЇЇЇЇЇЇЇ

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; either version 2 of the License, or (at

your option) any later version.

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

In addition, as a special exception, the author gives permission to

link the code of this program with the Half-Life Game Engine ("HL

Engine") and Modified Game Libraries ("MODs") developed by Valve,

L.L.C ("Valve"). You must obey the GNU General Public License in all

respects for all of the code used other than the HL Engine and MODs

from Valve. If you modify this file, you may extend this exception

to your version of the file, but you are not obligated to do so. If

you do not wish to do so, delete this exception statement from your

version.

Description/Features:

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

First of all, if you are too lazy to read all this don't bother me with problems or questions!

The plugin does several things that all can be turned on or off seperately by CVAR's:

- on startup it reads the available servers from SERVERFILE ("amxmodx/config/serverlist.ini" by default),

see next section for an example

- the servers must be in the format "address:port=name" each on a line by itself where address can be

an IP or DNS name - if you use DNS names look at the CVAR redirect_external_address as well

- saying /server shows a list of available servers (if redirect_manual is 1) - people can choose a

number from the list and are immediately sent to that server

- when the server is full (one free slot left, that is) people are automatically forwarded to a random

server from the list - redirect_auto enables or disables this

- when a server from the list is full or down the server is disabled in the menu and players are not

redirected there automatically - to be able to check whether a server is down redirect_check_method

must be > 0 and to check whether it is full redirect_check_method must be > 1

- the servers are announced every redirect_announce seconds - set to 0 to turn announcements off;

the server list is shown as HUD message and for living players displayed at the top and for dead

players displayed somewhere below the top so it is not covered by the "spectator bars"; how much

information the announcements include depends on redirect_check_method

- depending on redirect_check_method servers can be checked for being down/full or even current map, number

of current players and maximum players can be displayed in the menu and in the announcements

- when no server is available for automatic redirection the player is just dropped with an appropriate

message

- when someone is redirected either manually or automatically this is shown to the other players

telling who was redirected and to which server

- it is also announced that people can say /follow to follow this player to the server and they are

redirected as well - both the announcements and the follow feature can be enabled or disabled by

CVAR (redirect_follow)

- the plugin is language aware (thus you need to place the redirect.txt in amxmodx/data/lang/)

- the server can show whether someone that just connects was redirected to the server and from what

server he is coming from

- the own IP address is detected automatically and disabled in the server list - automatic detection

does not work if you use DNS names in the SERVERFILE - in this case set the DNS address of the own

server in redirect_external_address for the detection to work - detecting the own server is NECESSARY

for the plugin to work correctly

- with CVAR redirect_retry set to 1 the server can put people into a retry queue to be redirected back to

the last server (e.g. when they were automatically redirected but only want to play on the server they

connected to)

Server List File:

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

The file is in ini format. The section name is the server name. The following keys are recognized:

- address = server address (can be IP or DNS name)

- port = server port - a value between 1025 and 65536, default 27015

- cmdbackup = defines how often the UDP request is resent to the server (with redirect_check_method > 0), default 2

- noauto = overrides the redirect_auto setting for this server, default is redirect_auto

- nomanual = overrides the redirect_manual setting for this server, default is redirect_manaul

- nodisplay = if this is set to 1 it will hide the server from the /server list and announcements, default 0

- adminslots = if this is set to 1 the plugin will redirect only people with reserved slot there if it's e.g. 12/13 players on the target server, default 0

- password = the password that is needed to connect to the server, default <none>

- publicpassword = if set to 1, all players can connect to passworded servers, when set to 0 only admins, default 0

If a value is not specified the default value is used. The "address" key always must be specified and

doesn't have a default value

Here is an example how the server file could look like:

/ЇЇЇЇЇЇЇЇЇЇ serverlist.ini ЇЇЇЇЇЇЇЇЇЇЇЇ\

[my example server]

address=example.n-ice.org

port=27015

cmdbackup=5

noauto=1

nomanual=0

nodisplay=0

[my 2nd example server]

address=example2.n-ice.org

port=27015

\______________________________________/

I recommend that all servers have the same SERVERFILE. This is not necessary with redirect_show 0 but it's still better,

because it could confuse users when not all servers are in the same place in the menu on every server.

Please be aware that when using more than 5 servers in SERVERFILE you have to change the define

MAX_SERVERFORWARDS and recompile the plugin. If there are more servers in the file than specified by

MAX_SERVERFORWARDS the other servers will be ignored.

Available CVAR's:

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

redirect_active - 1/0 activate/deactivate redirect plugin - when this is set to 0 all other CVAR's are ignored, default 0

redirect_auto - 0 = disable automatic redirecting when server is full/down, 1 = redirect to random server from list, 2 = redirect to next server in list, default 0

redirect_manual - 1/0 enable/disable manual redirecting with /server, default 0

redirect_follow - 1/0 enable/disable following players with /follow to a server they were redirected to - people can still use /server to follow a player though, default 0

redirect_external_address - own external server address - only needed when you use DNS names instead of IPs in SERVERFILE - this must match the name in SERVERFILE - include the port!

redirect_check_method - check the servers in the list - 0 = no checks, 1 = ping only(to check whether a server is down), 2 = check active players and max. players as well, default 0

redirect_announce - announce server list with stats (depends on redirect_check_method) in center every redirect_announce seconds - set to 0 for off, default 60

redirect_announce_mode - control who announcements are displayed for: 1 = alive players , 2 = dead players, 3 = both

redirect_announce_alivepos_x - the vertical position of the announcements displayed to living people, default -1.0

redirect_announce_alivepos_y - the horizontal position of the announcements displayed to living people, default 0.01

redirect_announce_deadpos_x - the vertical position of the announcements displayed to living people, default -1.0

redirect_announce_deadpos_y - the horizontal position of the announcements displayed to living people, default 0.35

redirect_show - 1/0 enable/disable redirection information in chat area, default 1

redirect_adminslots - 1/0 enable/disable adminslots - when set to 1 people are redirected off the server when someone with a reserved slot connects, default 0

redirect_retry - 1/0 enable/disable retry queue feature - when set to 1 players can say /retry and are redirected as soon as a slot on the target server is free (currently only works for redirecting them back to the server that redirected them to the current server), default 0

Advanced users should also check out the defines for more options, especially QUERY_INTERVAL could be interesting.

Min. Requirements:

ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ

- Metamod v1.18

- HLDS v3.1.1.1

- AMXX v1.70

Modules:

ЇЇЇЇЇЇЇЇЇ

The plugin requires the modules engine and sockets to be loaded. You can enable them in your modules.ini.

If you don't want to load the sockets module search for the line containing require_module("sockets")

and comment it out or delete it. When doing this you can only use redirect_check_method 0. If you set

this to something different your server might crash or other problems arise.

Known issues:

ЇЇЇЇЇЇЇЇЇЇЇЇЇ

#1 some people report crashes with CS 1.6 and redirect_check_method 1/2 if the server being checked

is on the same IP (only different port) so set to 0 if your server hangs after some time

#2 as the length of menu items is limited don't specify too long server names - if an item is too long it is just truncated

Changelog:

ЇЇЇЇЇЇЇЇЇЇ

Note:

The first version that was released to the public was v0.3. v0.1 and v0.2 were only running on my

servers for some time before I started the next version.

v0.1:

- reads the available servers from a config file

- people can show a server menu by saying /server

- automatic server forwarding to the next server in the list when server is full

- announcing of redirection for other players on the server

- people can say /follow to follow the last forwarded player

- when redirect_external_address is set the own address is automatically detected

v0.2:

- external address is automatically detected without having redirect_external_address set, for DNS names redirect_external_address

is still needed to be set though

- introduced CVAR redirect_check_method where

0 = disabled

1 = the servers in the list are pinged every QUERY_INTERVAL seconds to check whether they are online

2 = the servers in the list are queried for actual and maximum players and map every QUERY_INTERVAL seconds

- depending on redirect_check_method the menu displays:

0 = own server as disabled, others as available in format: server name (server address)

1 = own server as disabled, others as available in format "server name (server address)" or down in format "server name (server address) (down)"

2 = own server as disabled, others as available in format "server name [current map] (active players/max. players)"

or down in format "server name (server address) (down)"

- servers that are down are displayed as down in the list and people cannot have themselves redirected there (disabled in menu)

- random automatic forward instead of choosing the next free server from the list

- the server doesn't forward to servers considered being down when server is full

- if no server is available (due to being down) players are not redirected and have a message displayed that they couldn't be forwarded

v0.3

- for redirect_check_method 2:

- no automatic redirection to full servers anymore (active players = maximum players)

- full servers are displayed in the menu with red brackets surrounding the player numbers and can't be selected

- the plugin is now language system aware

- introduced CVAR redirect_send_tag where

0 = disabled

1 = when redirecting it prepends [R<server number>] to people's names with <server number> being the own server number in SERVERFILE

indicating to the receive server that this player was redirected from this server

- introduced CVAR redirect_receive_tag where

0 = disabled

1 = when someone connects with prepended [R<server number>] to his name the server will show a message that the player was redirected

from that server and remove the tag from the name

- introduced CVAR redirect_announce:

The value of this CVAR can be 0 for turning announcements of. If set to a higher floating point

value this is the time in seconds how often the announcements are shown.

- made status detection more stable by sending more UDP packets

- made status detection more stable through a completely new code for receive handling

- several small optimizations and bug fixes here and there I don't recall in detail :P

v0.4

- modified default messages for connect and team joining so that they display player names without redirect

tags if redirect_receive_tag = 1

- modified the name change code to be more reliable

- HL1 steam server status querying is now working - this should make status information work for all HL1

mods running on Steam

- plugin now uses the much faster cvar querying introduced with AMXX 1.70

- load routine now checks whether there are more servers in the file than can be loaded

v0.4.1

- name changes from tagged names are now hidden as well - this means with redirect_receive_tag = 1 the

complete procedure of tagging is hidden

v0.4.7

- fixed a bug where automatic redirection didn't work with redirect_check_method 0

- fixed a bug where the PLUGIN_TAG was missing in the message MSG_NO_REDIRECT_SERVER

- fixed many messages that were still displayed with server's default language

- fixed code to display announcement in different height for dead and alive players

- introduced CVAR redirect_announce_mode where

1 = announcements while playing

2 = announcements while dead/spectator

3 = both

default is 3 - only effective when redirect_announce > 0[xOR]

v0.4.8

- added code to require_module sockets

- introduced cvar redirect_version for external version check

v0.5.0

- fixed an error that crashed the server when redirecting automatically

v0.6.0

- sorted out several unused variables

- redirect_auto 2 redirects to next server in list (1 = random server, like before)

- added new format for SERVERFILE - it is now an ini file

- server status (or ping) request should be more stable due to added cmdbackup of 2 (2 additional request packets are sent)

- the default cmdbackup value can be overridden in SERVERFILE for each server

- redirect_manual can be overriden in SERVERFILE for each server

- redirect_auto can be overriden in SERVERFILE for each server

- servers in the list can be hidden (from list + announcements) with a key in SERVERFILE

- added server command redirect_reload which will make the plugin reload the SERVERFILE

v0.6.3

- changed UDP timeout value to default with hope to fix crash problem with redirect_check_method > 0

- sockets are now initialized to 0 after freeing them

- fixed a bug where second server was displayed as being down

- fixed a bug where for first server the map of the second server was displayed

- changed default QUERY_INTERVAL to 20

- changed UDP receive code to be faster and handle responses more secure and reliable

v0.7.0

- UDP timeout value change didn't help and was changed back to 1

- fixed the "unknown command: pickserver" message when using pickserver command

- removed nick tagging

- server now displays where someone was redirected from without nick tagging

- removed text message hooks as they are not needed anymore

- removed CVAR redirect_send_tag

- removed CVAR redirect_receive_tag

- servers are not redirecting back to source servers anymore, thus preventing an endless loop

- fixed a bug where redirect_auto 2 wouldn't choose the next but the first server in list

- introduced CVAR redirect_show where

0 = disabled

1 = show redirection information in chat area when someone was redirected (default)

v0.7.5

- removed support for AMXX versions older than 1.70 to cleanup code

- added command redirect_announce_now which will immediately display server announcement to all players

- introduced CVAR redirect_announce_alivepos_x

- introduced CVAR redirect_announce_alivepos_y

- introduced CVAR redirect_announce_deadpos_x

- introduced CVAR redirect_announce_deadpos_y

- menues now don't have colors anymore when the mod does not support coloured menues

- added command redirect_user which can redirect a user

- added native redirect(id, nServer) which can be called by other plugins

- sentence "say /server..." is no longer displayed in announcement if redirect_manual is set to 0

v0.8.0

- introduced CVAR redirect_adminslots

- plugin will now redirect another user to free up a slot when someone with a reserved slot connects

- improved detection for coloured menues

- servers in server list can have a new setting "adminslots" to tell whether they have adminslots

- plugin will not allow to redirect manually anymore when there is only one free slot left on the target server,

except when the target server has an admin slot and the player to be redirected has reservation flag

- native redirect function got a new parameter to tell whether people are dropped when no valid target server is found

v0.8.2

- setting redirect_announce to 0 will now stop the announcements from being displayed immediately

- fixed a bug where announcements were displayed although redirect_announce is set to 0

- plugin will not allow to redirect manually anymore when there is only one free slot left on the target server,

except when the target server has an admin slot and the player to be redirected has reservation flag [should work now]

v0.8.4

- introduced CVAR redirect_maxadmins - with this the maximum number of admins can be limited

- if the maximum number of connected admins is reached the plugin acts like there were no admin slots

- fixed a bug where server parameters in server list beginning with "no" were always interpreted as "1"

v0.9.0

- added functionality for splitting up servers on several selection pages

- selection menu can now handle up to 999 servers

- server announcements now cycle through servers with same grouping like menu if servers are more than 8

- redirection to passworded servers is now possible, either for admins or even normal players

- introduced serverlist option "password" which sets the connect password needed for this server

- introduced serverlist option "publicpassword":

0 = password not public, only admins can have themselves redirected to this server (if passworded)

1 = password is public, all players can have themselves redirected to this server (if passworded)

- optimized performance of redirect_reload

- changed some messages that were displayed in console to be displayed in chat area

- added a retry queue people can add themselves to with /retry command to be redirected to the server they came from

- added command /stopretry to drop out of the retry queue

- added many messages and error messages

- moved some initialization code from client_putinserver to plugin_cfg to increase performance

- added debug messages (english only) that will show in server log when plugin is running in debug mode

- fixed a bug where message "player has been redirected to server..." was displayed to all others in

the language of the player that has been redirected

- fixed a bug where message "player has been redirected here from..." was displayed to all others in

the language of the player that has been redirected

- added welcome message when a player was redirected from another server

- added announcement that the player can use /retry (displayed only if redirected_retry 1 and redirect_show 1)

v0.9.1

- fixed a bug where the plugin would try to display a welcome message even if the player was not redirected,

causing an error message in AMXX log

*/

#include <amxmodx>

#include <amxmisc>

#include <engine>

#include <sockets>

// plugin defines

#define PLUGIN_NAME "Server redirect"

#define PLUGIN_VERSION "0.9.1"

#define PLUGIN_AUTHOR "x0R"

#define PLUGIN_TAG "[REDIRECT]"

// maximum values - don't change this if you don't know what you are doing!

#define MAX_FILE_LEN 256 // maximum length of file names

#define MAX_SERVERLINE_LEN 256 // maximum length of a line read from SERVERFILE

#define MAX_SERVERNAME_LEN 50 // maximum length of a server name read from SERVERFILE

#define MAX_SERVERADDRESS_LEN 100 // maximum length of a server address read from SERVERFILE

#define MAX_NAME_LEN 33 // maximum length of a player name

#define MAX_MENUBODY_LEN 512 // maximum length of a menu body

#define MAX_INFO_LEN 1500 // maximum length of info reply - when longer than that the packet is fragmented (due to MTU setting)

#define MAX_MAP_LEN 30 // maximum length of map names

#define MAX_IP_LEN 16 // maximum length of IP addresses

#define MAX_PORT_LEN 6 // maximum length of port numbers (as strings of course)

#define MAX_KEY_LEN 20 // maximum length of a key name in SERVERFILE

#define MAX_PASSWORD_LEN 15 // maximum length of a password in SERVERFILE

#define MAX_VALUE_LEN 255 // maximum length of a value in SERVERFILE

// unique task ID's - currently not needed but who knows when they will be

#define TASKID_QUERY 21934807

#define TASKID_QUERY_RECEIVE 21934808

#define TASKID_ANNOUNCE 21934809

// options - these can be changed by the user, rememeber that you need to recompile for any changes here to take effect

#define SERVERFILE "serverlist.ini" // name of file in /configs containing the server forwards - you can also prepend a subdirectory

#define QUERY_INTERVAL 20.0 // interval of server querying (in seconds)

#define QUERY_TIMEOUT 1.0 // the maximum time to wait for a server answer (in seconds) before it is considered being down

#define MAX_SERVERFORWARDS 5 // maximum number of server forwards in forwards file

#define MAX_MENUPAGES 10 // maximum number of pages the server selection menu can have

#define DEFAULT_CMDBACKUP 2 // how often to resend the UDP request to servers by default

#define MENU_FORCENOCOLOR false // false = display colored menues if the mod supports it; true = never display colored menues

// positions to get information from in server answer

#define STRUCT_INFO_POS_MAP 2

#define STRUCT_INFO_POS_ACTIVEPLAYERS 5

#define STRUCT_INFO_POS_MAXPLAYERS 6

#define STRUCT_INFO_POS_PROTOCOL 7

// server flags

#define SERVERFLAG_NOAUTO 0

#define SERVERFLAG_NOMANUAL 1

#define SERVERFLAG_NODISPLAY 2

// --------------------------------------- end of defines ---------------------------------------

// global variables

new g_saServerNames[MAX_SERVERFORWARDS][MAX_SERVERNAME_LEN] // server names

new g_saServerAddresses[MAX_SERVERFORWARDS][MAX_SERVERADDRESS_LEN] // server addresses

new g_naServerPorts[MAX_SERVERFORWARDS] = {27015, ...} // server ports

new g_saServerPasswords[MAX_SERVERFORWARDS][MAX_PASSWORD_LEN] // server passwords

new g_naServerPublicPassword[MAX_SERVERFORWARDS] = {0, ...} // is the server password public?

new g_naServerActivePlayers[MAX_SERVERFORWARDS] = {-1, ...} // active players

new g_naServerMaxPlayers[MAX_SERVERFORWARDS] = {-1, ...} // maximum players

new g_saServerMap[MAX_SERVERFORWARDS][MAX_MAP_LEN] // current map

new g_naServerSockets[MAX_SERVERFORWARDS] = {0, ...} // server request sockets

new g_naServerCmdBackup[MAX_SERVERFORWARDS] = {DEFAULT_CMDBACKUP, ...} // cmdbackup

new g_naServerFlags[MAX_SERVERFORWARDS] = {0, ...} // server flags

new g_naServerReserveSlots[MAX_SERVERFORWARDS] = {0, ...} // reserve admin slots on this server?

new g_naMenuPageStart[MAX_MENUPAGES] = {0, ...}

new bool:g_baServerResponding[MAX_SERVERFORWARDS] = {false, ...} // is server responding?

new g_nServerCount = 0 // number of found forward servers

new g_nLastRedirectServer = -1 // the last server someone was redirected to - needed for /follow command

new g_sLastRedirectName[MAX_NAME_LEN] = "" // the nick of the person who was redirected - needed for /follow command

new g_nOwnServer = -1

new g_modname[11] = ""

new g_naLastMenuPages[32] = {1, ...}

new g_naServerSelections[32][8]

new g_nNextAnnounceServer = 0

new g_nLastServers[32] = {-1, ...}

new g_nRetryQueue[32][2]

new g_nRetryCount = 0

new bool:g_bDebug = false

// global CVAR's

new cvar_active

new cvar_auto

new cvar_manual

new cvar_follow

new cvar_external_address

new cvar_check_method

new cvar_announce

new cvar_announce_mode

new cvar_announce_alivepos_x

new cvar_announce_alivepos_y

new cvar_announce_deadpos_x

new cvar_announce_deadpos_y

new cvar_show

new cvar_adminslots

new cvar_maxadmins

new cvar_retry

// --------------------------------------- end of global vars ---------------------------------------

/*

public plugin_precache()

{

}

*/

#if AMXX_VERSION_NUM >= 170

public plugin_init() {

register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

register_cvar("redirect_version", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY)

set_cvar_string("redirect_version", PLUGIN_VERSION)

// please see the description at top if you want to know what these CVAR's do

cvar_active = register_cvar("redirect_active", "0")

cvar_auto = register_cvar("redirect_auto", "0")

cvar_manual = register_cvar("redirect_manual", "0")

cvar_follow = register_cvar("redirect_follow", "0")

cvar_external_address = register_cvar("redirect_external_address", "")

cvar_check_method = register_cvar("redirect_check_method", "0")

cvar_announce = register_cvar("redirect_announce", "120")

cvar_announce_mode = register_cvar("redirect_announce_mode", "3")

cvar_announce_alivepos_x = register_cvar("redirect_announce_alivepos_x", "-1.0")

cvar_announce_alivepos_y = register_cvar("redirect_announce_alivepos_y", "0.01")

cvar_announce_deadpos_x = register_cvar("redirect_announce_deadpos_x", "-1.0")

cvar_announce_deadpos_y = register_cvar("redirect_announce_deadpos_y", "0.35")

cvar_show = register_cvar("redirect_show", "1")

cvar_adminslots = register_cvar("redirect_adminslots", "0")

cvar_maxadmins = register_cvar("redirect_maxadmins", "0")

cvar_retry = register_cvar("redirect_retry", "0")

register_dictionary("redirect.txt")

register_dictionary("common.txt")

load_servers()

register_menu("Redirect Menu", 1023, "server_menu_select")

register_srvcmd("redirect_reload", "srvcmd_reload", -1, "- reload redirect servers")

register_clcmd("say /server", "cmd_show_server_menu", 0, "- show server redirection menu")

register_clcmd("say_team /server", "cmd_show_server_menu", 0, "- show server redirection menu")

register_clcmd("pickserver", "cmd_pickserver", 0, "show server redirection menu")

register_clcmd("say /follow", "cmd_follow_player", 0, "- follow the last redirected player to his server")

register_clcmd("say_team /follow", "cmd_follow_player", 0, "- follow the last redirected player to his server")

register_clcmd("say /retry", "cmd_retry", 0, "- redirect back as soon as the foregoing server has a free slot")

register_clcmd("say_team /retry", "cmd_retry", 0, "- redirect back as soon as the foregoing server has a free slot")

register_clcmd("say /stopretry", "cmd_stopretry", 0, "- stop retrying the foregoing server")

register_clcmd("say_team /stopretry", "cmd_stopretry", 0, "- stop retrying the foregoing server")

register_clcmd("redirect_announce_now", "announce_servers", ADMIN_KICK , "- announce server list immediately")

register_clcmd("redirect_user", "cmd_redirect_user", ADMIN_KICK , "<playername|playerid> [servernum] - redirect a player [to a given server]")

set_task(QUERY_INTERVAL, "query_servers", TASKID_QUERY, "", 0, "b")

get_modname(g_modname, 10)

// check whether we are in debug mode or not

new saDummy[2]

new saStatus[6]

get_plugin(-1, saDummy, 0, saDummy, 0, saDummy, 0, saDummy, 0, saStatus, 5)

g_bDebug = bool:equal(saStatus, "debug")

}

public plugin_cfg()

{

// if we didn't detect our own server yet now do it once - we can't do this in plugin_init because the cvars are not set there already

if (g_nOwnServer == -1)

{

new sFullAddress[MAX_SERVERADDRESS_LEN]

new sTmpServerIP[MAX_IP_LEN + MAX_PORT_LEN]

get_cvar_string("net_address", sTmpServerIP, MAX_IP_LEN + MAX_PORT_LEN - 1)

new sTmpOwnAddress[MAX_SERVERADDRESS_LEN]

get_pcvar_string(cvar_external_address, sTmpOwnAddress, MAX_SERVERADDRESS_LEN - 1)

new nServerCount = 0

while (nServerCount < g_nServerCount)

{

format(sFullAddress, MAX_SERVERADDRESS_LEN - 1, "%s:%d", g_saServerAddresses[nServerCount], g_naServerPorts[nServerCount])

if (equal(sFullAddress, sTmpOwnAddress) || equal(sFullAddress, sTmpServerIP))

{

g_nOwnServer = nServerCount

break

}

nServerCount++

}

}

if (g_nOwnServer == -1) // we don't know who we are so do nothing

return PLUGIN_CONTINUE

if (get_pcvar_float(cvar_announce) > 0.0)

if (!task_exists(TASKID_ANNOUNCE))

set_task(get_pcvar_float(cvar_announce), "announce_servers", TASKID_ANNOUNCE, "", 0, "b")

return PLUGIN_CONTINUE

}

public plugin_natives()

{

register_native ("redirect", "native_redirect", 1)

}

public plugin_modules()

{

require_module("engine")

require_module("sockets")

}

// load servers from file

public bool:load_servers()

{

new sConfigDir[MAX_FILE_LEN], sServerFile[MAX_FILE_LEN]

get_configsdir(sConfigDir, MAX_FILE_LEN-1)

format(sServerFile, MAX_FILE_LEN-1, "%s/%s", sConfigDir, SERVERFILE)

if (!file_exists(sServerFile))

{

log_amx("%L", LANG_SERVER, "MSG_ERROR_NO_FILE", sServerFile)

return false

}

new nFilePos = 0

new sFileLine[MAX_SERVERLINE_LEN]

new nReadLen

new sPort[MAX_PORT_LEN]

new sKey[MAX_KEY_LEN]

new sValue[MAX_VALUE_LEN]

new nCurrentServer = -1

while (read_file(sServerFile, nFilePos++, sFileLine, MAX_SERVERLINE_LEN-1, nReadLen))

{

if ((sFileLine[0] == ';') && (strcmp(sFileLine, "") == 0)) continue // skip comment and empty lines

if ((sFileLine[0] == '[') && (sFileLine[strlen(sFileLine) - 1] == ']')) // a section starts

{

nCurrentServer++

if (nCurrentServer > 0)

{

// check whether the previous server was valid

if ((g_naServerPorts[nCurrentServer - 1] != 0) && (strcmp(g_saServerAddresses[nCurrentServer - 1], "") != 0))

{

g_nServerCount++

num_to_str(g_naServerPorts[nCurrentServer - 1], sPort, MAX_PORT_LEN - 1)

log_amx("%L", LANG_SERVER, "MSG_LOADED_SERVER", g_saServerNames[nCurrentServer - 1], g_saServerAddresses[nCurrentServer - 1], sPort)

}

else

nCurrentServer--

}

if (nCurrentServer >= MAX_SERVERFORWARDS)

break;

copy(g_saServerNames[nCurrentServer], strlen(sFileLine) - 2, sFileLine[1])

continue

}

if (nCurrentServer >= 0) // do we already have found a section?

{

strtok(sFileLine, sKey, MAX_KEY_LEN - 1, sValue, MAX_VALUE_LEN - 1, '=', 1)

strtoupper(sKey)

if (strcmp(sKey, "ADDRESS") == 0)

copy(g_saServerAddresses[nCurrentServer], MAX_SERVERADDRESS_LEN - 1, sValue)

else

if (strcmp(sKey, "PASSWORD") == 0)

copy(g_saServerPasswords[nCurrentServer], MAX_PASSWORD_LEN - 1, sValue)

else

if (strcmp(sKey, "PUBLICPASSWORD") == 0)

{

if (is_str_num(sValue))

if (str_to_num(sValue) == 1)

g_naServerPublicPassword[nCurrentServer] = 1

}

else

if (strcmp(sKey, "PORT") == 0)

{

if (is_str_num(sValue))

g_naServerPorts[nCurrentServer] = str_to_num(sValue)

else

g_naServerPorts[nCurrentServer] = 27015

if ((g_naServerPorts[nCurrentServer] > 65536) || (g_naServerPorts[nCurrentServer] < 1024))

g_naServerPorts[nCurrentServer] = 27015

}

else

if (strcmp(sKey, "CMDBACKUP") == 0)

{

if (is_str_num(sValue))

g_naServerCmdBackup[nCurrentServer] = str_to_num(sValue)

else

g_naServerCmdBackup[nCurrentServer] = DEFAULT_CMDBACKUP

// protect from insane values

if ((g_naServerCmdBackup[nCurrentServer] > 200) || (g_naServerCmdBackup[nCurrentServer] < 0))

g_naServerCmdBackup[nCurrentServer] = DEFAULT_CMDBACKUP

}

else

if (strcmp(sKey, "NOAUTO") == 0)

{

if (is_str_num(sValue))

if (str_to_num(sValue) == 1)

g_naServerFlags[nCurrentServer] = g_naServerFlags[nCurrentServer] | (1<<SERVERFLAG_NOAUTO)

}

else

if (strcmp(sKey, "NOMANUAL") == 0)

{

if (is_str_num(sValue))

if (str_to_num(sValue) == 1)

g_naServerFlags[nCurrentServer] = g_naServerFlags[nCurrentServer] | (1<<SERVERFLAG_NOMANUAL)

}

else

if (strcmp(sKey, "NODISPLAY") == 0)

{

if (is_str_num(sValue))

if (str_to_num(sValue) == 1)

g_naServerFlags[nCurrentServer] = g_naServerFlags[nCurrentServer] | (1<<SERVERFLAG_NODISPLAY)

}

else

if (strcmp(sKey, "ADMINSLOTS") == 0)

{

if (is_str_num(sValue))

g_naServerReserveSlots[nCurrentServer] = str_to_num(sValue)

else

g_naServerReserveSlots[nCurrentServer] = 0

if ((g_naServerReserveSlots[nCurrentServer] > 32) || (g_naServerReserveSlots[nCurrentServer] < 0))

g_naServerReserveSlots[nCurrentServer] = 0

}

}

}

if ((nCurrentServer >= MAX_SERVERFORWARDS) || (nCurrentServer == -1))

return true;

// check whether the previous server was valid

if ((g_naServerPorts[nCurrentServer] != 0) && (strcmp(g_saServerAddresses[nCurrentServer], "") != 0))

{

g_nServerCount++

num_to_str(g_naServerPorts[nCurrentServer], sPort, MAX_PORT_LEN - 1)

log_amx("%L", LANG_SERVER, "MSG_LOADED_SERVER", g_saServerNames[nCurrentServer], g_saServerAddresses[nCurrentServer], sPort)

}

if (g_nServerCount < 2)

{

log_amx("%L", LANG_SERVER, "MSG_ERROR_NOT_ENOUGH_SERVERS")

return false

}

return true

}

public bool:can_redirect(nServerNum)

{

new nCheckMethod = get_pcvar_num(cvar_check_method)

new nAutoMode = get_pcvar_num(cvar_auto)

new bool:bReturn = false

if ((nServerNum != g_nOwnServer) && (nServerNum >= 0) && (nServerNum < MAX_SERVERFORWARDS))

{

if ((nAutoMode == 0) || (g_naServerFlags[nServerNum] & (1<<SERVERFLAG_NOAUTO)))

return false

switch (nCheckMethod)

{

case 0:

bReturn = true

case 1:

bReturn = g_baServerResponding[nServerNum]

case 2:

bReturn = (g_baServerResponding[nServerNum] && ((g_naServerActivePlayers[nServerNum] + 1) < g_naServerMaxPlayers[nServerNum]))

}

}

return bReturn

}

public queue_add(id, nServer)

{

if (g_bDebug)

log_amx("added player %i to queue for server %i in slot %i", id, nServer, g_nRetryCount)

g_nRetryQueue[g_nRetryCount][0] = id

g_nRetryQueue[g_nRetryCount][1] = nServer

g_nRetryCount++

}

public queue_remove(id)

{

new nCount = 0

while (nCount < g_nRetryCount)

{

if (g_nRetryQueue[nCount][0] == id)

{ // ok, remove from queue and let all others go one place up

// in case it's the last entry in queue where the following loop would never be executed

if (g_bDebug)

log_amx("removed player %i from queue of server %i, slot %i", id, g_nRetryQueue[nCount][1], nCount)

g_nRetryQueue[nCount][0] = -1

g_nRetryQueue[nCount][1] = -1

// move other entries up

while ((nCount + 1) < g_nRetryCount)

{

g_nRetryQueue[nCount][0] = g_nRetryQueue[nCount + 1][0]

g_nRetryQueue[nCount][1] = g_nRetryQueue[nCount + 1][1]

nCount++

}

g_nRetryCount--

break

}

nCount++

}

}

public reset_info(id[])

{

client_cmd(id[0], "setinfo ^"sredir^" ^"^"")

client_cmd(id[0], "setinfo ^"password^" ^"^"")

}

public announce_servers()

{

if (get_pcvar_num(cvar_active) == 1)

{

if (g_nServerCount > 0)

{

new nCheckMethod = get_pcvar_num(cvar_check_method)

new sAnnounceBody[MAX_MENUBODY_LEN] = ""

new nDisplayCount = 0

new nServerCount = g_nNextAnnounceServer

if (nServerCount >= g_nServerCount)

nServerCount = 0

while ((nServerCount < g_nServerCount) && (nDisplayCount < 8))

{

if (!(g_naServerFlags[nServerCount] & (1<<SERVERFLAG_NODISPLAY)))

{

if (nServerCount == g_nOwnServer)

{

if ((nCheckMethod == 0) || (nCheckMethod == 1))

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s(%s)", sAnnounceBody, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else if (nCheckMethod == 2)

{

new sMap[MAX_MAP_LEN]

get_mapname(sMap, MAX_MAP_LEN - 1)

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s [%s] (%d/%d)", sAnnounceBody, g_saServerNames[nServerCount], sMap, get_playersnum(1), get_maxplayers())

}

}

else

{

if (nCheckMethod == 0)

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s(%s)", sAnnounceBody, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

if (g_baServerResponding[nServerCount])

{

if (nCheckMethod == 1)

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s(%s)", sAnnounceBody, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else if (nCheckMethod == 2)

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s [%s] (%d/%d)", sAnnounceBody, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

}

else

format(sAnnounceBody, MAX_MENUBODY_LEN - 1, "%s^n%s (down)", sAnnounceBody, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

}

}

nServerCount++

nDisplayCount++

}

g_nNextAnnounceServer = nServerCount

set_hudmessage(000, 100, 255, -1.0, 0.01, 0, 0.0, 10.0, 0.5, 0.10, 1)

//show_hudmessage(0, sAnnounceBody)

if (get_pcvar_float(cvar_announce) > 0.0)

{

new nAnnounceMode = get_pcvar_num(cvar_announce_mode)

if (nAnnounceMode > 0)

{

new nPlayers[32]

new nPlayerNum, nPlayerCount

new sAnnounceText[MAX_MENUBODY_LEN]

if ((nAnnounceMode == 1) || (nAnnounceMode == 3))

{

get_players(nPlayers, nPlayerNum, "ac") // alive players

set_hudmessage(000, 100, 255, get_pcvar_float(cvar_announce_alivepos_x), get_pcvar_float(cvar_announce_alivepos_y), 0, 0.0, 10.0, 0.5, 0.10, 1)

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

if (get_pcvar_num(cvar_manual) == 1)

format(sAnnounceText, MAX_MENUBODY_LEN - 1, "%L^n%s", nPlayers[nPlayerCount], "MSG_SAY_SERVER", sAnnounceBody)

else

sAnnounceText = sAnnounceBody

show_hudmessage(nPlayers[nPlayerCount], sAnnounceText)

}

}

if ((nAnnounceMode == 2) || (nAnnounceMode == 3))

{

get_players(nPlayers, nPlayerNum, "bc") // dead players

set_hudmessage(000, 100, 255, get_pcvar_float(cvar_announce_deadpos_x), get_pcvar_float(cvar_announce_deadpos_y), 0, 0.0, 10.0, 0.5, 0.10, 1) // show list at lower position for them so it is not covered by the "spectator bars"

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

if (get_pcvar_num(cvar_manual) == 1)

format(sAnnounceText, MAX_MENUBODY_LEN - 1, "%L^n%s", nPlayers[nPlayerCount], "MSG_SAY_SERVER", sAnnounceBody)

else

sAnnounceText = sAnnounceBody

show_hudmessage(nPlayers[nPlayerCount], sAnnounceText)

}

}

}

}

}

}

return PLUGIN_HANDLED

}

public show_server_menu(id, menupage)

{

new nServerCount

if (get_pcvar_num(cvar_active) == 1)

{

if (g_nServerCount > 0)

{

new bColorMenu = (colored_menus() && !MENU_FORCENOCOLOR)

new nCheckMethod = get_pcvar_num(cvar_check_method)

new sMenuBody[MAX_MENUBODY_LEN]

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "\r%L\R^n", id, "MSG_SELECT_SERVER")

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%L^n", id, "MSG_SELECT_SERVER")

if (menupage <= 1)

nServerCount = 0

else

nServerCount = g_naMenuPageStart[menupage - 2]

new nDisplayNumber = 1

new key = (1<<9)

while ((nDisplayNumber < 9) && (nServerCount < g_nServerCount))

{

if (!(g_naServerFlags[nServerCount] & (1<<SERVERFLAG_NODISPLAY)))

{

new bool:bCanRedirectByPassword = !(!equal(g_saServerPasswords[nServerCount], "") && (g_naServerPublicPassword[nServerCount] == 0) && (!access(id, ADMIN_RESERVATION)))

if ((g_naServerFlags[nServerCount] & (1<<SERVERFLAG_NOMANUAL)) || !bCanRedirectByPassword)

{

if (nCheckMethod == 2)

if (g_baServerResponding[nServerCount])

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

else

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s (down)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s (down)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

}

else

if (nServerCount == g_nOwnServer)

{

if (nCheckMethod == 2)

{

new sMap[MAX_MAP_LEN]

get_mapname(sMap, MAX_MAP_LEN - 1)

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], sMap, get_playersnum(1), get_maxplayers())

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], sMap, get_playersnum(1), get_maxplayers())

}

else

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

}

else

{

if (nCheckMethod == 0)

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \w %s\y(\w%s\y)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

key = key | (1<<(nDisplayNumber - 1))

g_naServerSelections[id][nDisplayNumber - 1] = nServerCount

}

else

if (g_baServerResponding[nServerCount])

{

if (nCheckMethod == 1)

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \w %s\y(\w%s\y)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s(%s)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

key = key | (1<<(nDisplayNumber - 1))

g_naServerSelections[id][nDisplayNumber - 1] = nServerCount

}

else if (nCheckMethod == 2)

{

if (((g_naServerActivePlayers[nServerCount] == (g_naServerMaxPlayers[nServerCount] - 1)) && (g_naServerReserveSlots[nServerCount] > 0) && (!access(id, ADMIN_RESERVATION))) || (g_naServerActivePlayers[nServerCount] >= g_naServerMaxPlayers[nServerCount]))

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \w %s \y[\w%s\y] \r(\w%d/%d\r)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

else

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \w %s \y[\w%s\y] \y(\w%d/%d\y)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s [%s] (%d/%d)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerMap[nServerCount], g_naServerActivePlayers[nServerCount], g_naServerMaxPlayers[nServerCount])

key = key | (1<<(nDisplayNumber - 1))

g_naServerSelections[id][nDisplayNumber - 1] = nServerCount

}

}

}

else

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n\y%d. \d %s \r(\ddown\r)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n%d. %s (down)", sMenuBody, nDisplayNumber, g_saServerNames[nServerCount], g_saServerAddresses[nServerCount])

}

}

nDisplayNumber++

}

nServerCount++

}

if (nServerCount < g_nServerCount)

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n\y9.\w %L", sMenuBody, id, "MSG_MORE")

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n9. %L", sMenuBody, id, "MSG_MORE")

key = key | (1<<8)

}

else

{

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n\y9.\d %L", sMenuBody, id, "MSG_MORE")

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n9. %L", sMenuBody, id, "MSG_MORE")

}

if (bColorMenu)

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n\y0.\w %L", sMenuBody, id, "MSG_CANCEL")

else

format(sMenuBody, MAX_MENUBODY_LEN - 1, "%s^n^n0. %L", sMenuBody, id, "MSG_CANCEL")

show_menu(id, key, sMenuBody, -1, "Redirect Menu")

}

}

g_naMenuPageStart[menupage - 1] = nServerCount

g_naLastMenuPages[id] = menupage

}

public srvcmd_reload()

{

new nCounter

// clear all global arrays and variables before reloading

for (nCounter = 0; nCounter < MAX_SERVERFORWARDS; nCounter++)

{

g_naServerPorts[nCounter] = 27015

g_naServerActivePlayers[nCounter] = -1

g_naServerMaxPlayers[nCounter] = -1

g_naServerSockets[nCounter] = 0

g_naServerCmdBackup[nCounter] = DEFAULT_CMDBACKUP

g_naServerFlags[nCounter] = 0

g_naServerReserveSlots[nCounter] = 0

g_baServerResponding[nCounter] = false

g_saServerMap[nCounter] = ""

g_saServerNames[nCounter] = ""

g_saServerAddresses[nCounter] = ""

g_saServerPasswords[nCounter] = ""

g_naServerPublicPassword[nCounter] = 0

}

// reset global variables

g_nNextAnnounceServer = 0

g_nServerCount = 0

g_nLastRedirectServer = -1

g_sLastRedirectName = ""

g_nOwnServer = -1

g_nRetryCount = 0

for (new nPlrCnt = 0; nPlrCnt < 32; nPlrCnt++)

{

// server IDs might change and thus render all currently saved server IDs invalid, so remove them, to be sure

g_nRetryQueue[nPlrCnt][0] = -1

g_nRetryQueue[nPlrCnt][1] = -1

g_nLastServers[nPlrCnt] = -1

}

load_servers()

new sFullAddress[MAX_SERVERADDRESS_LEN]

new sTmpServerIP[MAX_IP_LEN + MAX_PORT_LEN]

get_cvar_string("net_address", sTmpServerIP, MAX_IP_LEN + MAX_PORT_LEN - 1)

new sTmpOwnAddress[MAX_SERVERADDRESS_LEN]

get_pcvar_string(cvar_external_address, sTmpOwnAddress, MAX_SERVERADDRESS_LEN - 1)

// define the own server again

new nServerCount = 0

while (nServerCount < g_nServerCount)

{

format(sFullAddress, MAX_SERVERADDRESS_LEN - 1, "%s:%d", g_saServerAddresses[nServerCount], g_naServerPorts[nServerCount])

if (equal(sFullAddress, sTmpOwnAddress) || equal(sFullAddress, sTmpServerIP))

{

g_nOwnServer = nServerCount

break

}

nServerCount++

}

if (g_nOwnServer == -1)

log_amx("%L", LANG_SERVER, "MSG_OWN_DETECTION_ERROR")

}

// needed so server doesn't display "unknown command: pickserver" (returning PLUGIN_HANDLED in cmd_show_server_menu would supress the chat message)

public cmd_pickserver(id, level, cid)

{

cmd_show_server_menu(id, level, cid)

return PLUGIN_HANDLED

}

/*

bCanOther = if nServer is no valid redirect target can we use another server instead?

bCanDrop = drop user if no server was found?

bIgnoreSource = redirect regardless of redirecting would be back to source server

*/

public redirect(id, nServer, bCanOther, bCanDrop, bIgnoreSource)

{

new nForwardServer = -1

new bool:bFoundServer = false

new bAdminAccess = access(id, ADMIN_RESERVATION)

new nSourceServer

if (bIgnoreSource)

nSourceServer = -1

else

{

new sSourceServer[3]

get_user_info(id, "sredir", sSourceServer, 2)

if (!is_str_num(sSourceServer))

nSourceServer = -1

else

nSourceServer = str_to_num(sSourceServer)

if ((nSourceServer < 0) || (nSourceServer >= g_nServerCount))

nSourceServer = -1

}

new bool:bCanRedirectByPassword = false

if (nServer != -1)

bCanRedirectByPassword = !(!equal(g_saServerPasswords[nServer], "") && (g_naServerPublicPassword[nServer] == 0) && (!bAdminAccess))

if (!can_redirect(nServer) || (!bCanRedirectByPassword))

{

if (!bCanOther)

{

if (bCanDrop)

{

client_cmd(id, "echo %s: %L", PLUGIN_TAG, id, "MSG_NO_REDIRECT_SERVER")

client_cmd(id, "disconnect")

}

return false

}

nForwardServer = 0

// make sure at least one valid server exists or the second loop could be endless

while (nForwardServer < g_nServerCount)

{

bCanRedirectByPassword = !(!equal(g_saServerPasswords[nForwardServer], "") && (g_naServerPublicPassword[nForwardServer] == 0) && (!bAdminAccess))

if (can_redirect(nForwardServer) && bCanRedirectByPassword && (nForwardServer != nSourceServer))

{

bFoundServer = true

break

}

nForwardServer++

}

if (get_pcvar_num(cvar_auto) == 1)

nForwardServer = -1

}

else

{

nForwardServer = nServer

bFoundServer = true

}

if (bFoundServer)

{

while (nForwardServer == -1)

{

nForwardServer = random_num(0, g_nServerCount - 1)

bCanRedirectByPassword = !(!equal(g_saServerPasswords[nForwardServer], "") && (g_naServerPublicPassword[nForwardServer] == 0) && (!bAdminAccess))

if (!can_redirect(nForwardServer) || !bCanRedirectByPassword || ((nForwardServer == nSourceServer)))

nForwardServer = -1

}

new sUserNick[MAX_NAME_LEN]

get_user_name(id, sUserNick, MAX_NAME_LEN - 1)

client_cmd(id, "setinfo ^"sredir^" ^"%d^"", g_nOwnServer)

if (!equal(g_saServerPasswords[nForwardServer], "")) // set the user's server connect password if needed

client_cmd(id, "setinfo ^"password^" ^"%s^"", g_saServerPasswords[nForwardServer])

new sFullAddress[MAX_SERVERADDRESS_LEN]

format(sFullAddress, MAX_SERVERADDRESS_LEN - 1, "%s:%d", g_saServerAddresses[nForwardServer], g_naServerPorts[nForwardServer])

client_cmd(id, "connect %s", sFullAddress)

if (get_pcvar_num(cvar_show) == 1)

{

new nPlayers[32]

new nPlayerNum, nPlayerCount, nCurrentPlayer

get_players(nPlayers, nPlayerNum, "c")

set_hudmessage(000, 100, 255, get_pcvar_float(cvar_announce_alivepos_x), get_pcvar_float(cvar_announce_alivepos_y), 0, 0.0, 10.0, 0.5, 0.10, 1)

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

nCurrentPlayer = nPlayers[nPlayerCount]

if (get_pcvar_num(cvar_follow) == 1)

client_print(nCurrentPlayer, print_chat, "%s: %L - %L", PLUGIN_TAG, nCurrentPlayer, "MSG_REDIRECTED", sUserNick, g_saServerNames[nForwardServer], nCurrentPlayer, "MSG_FOLLOW")

else

client_print(nCurrentPlayer, print_chat, "%s: %L", PLUGIN_TAG, nCurrentPlayer, "MSG_REDIRECTED", sUserNick, g_saServerNames[nForwardServer])

}

}

g_nLastRedirectServer = nForwardServer

g_sLastRedirectName = sUserNick

}

else if (bCanDrop)

{

client_cmd(id, "echo %s: %L", PLUGIN_TAG, id, "MSG_NO_REDIRECT_SERVER")

client_cmd(id, "disconnect")

}

return true

}

public native_redirect(id, nServer, bCanDrop)

{

redirect(id, nServer, (nServer == -1), bCanDrop, true)

return PLUGIN_HANDLED

}

public cmd_redirect_user(id, level, cid)

{

if (!cmd_access(id, level, cid, 2))

return PLUGIN_HANDLED

new nForwardServer = -1

new sName[32]

read_argv(1, sName, 31)

new nCmdID = cmd_target(id, sName, 8)

if (!nCmdID)

return PLUGIN_HANDLED

// contains destination server number?

if (read_argc() > 2)

{

new argtmp[3]

read_argv(2, argtmp, 2)

if (is_str_num(argtmp))

nForwardServer = (str_to_num(argtmp) - 1)

}

redirect(nCmdID, nForwardServer, (nForwardServer == -1), true, true)

return PLUGIN_HANDLED

}

public cmd_show_server_menu(id, level, cid)

{

if (get_pcvar_num(cvar_manual) == 1)

show_server_menu(id, 1)

else

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_MANUAL_DISABLED")

return PLUGIN_CONTINUE

}

public cmd_retry(id, level, cid)

{

if (get_pcvar_num(cvar_retry) > 0)

{

if (g_nLastServers[id] > -1)

{

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_QUEUE_ADD", g_nRetryCount + 1, g_saServerNames[g_nLastServers[id]])

queue_add(id, g_nLastServers[id])

}

else

{

if (g_bDebug)

log_amx("last server for player %i is server %i", id, g_nLastServers[id])

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_QUEUE_NO_LAST")

}

}

else

{

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_QUEUE_DEACTIVATED")

}

}

public cmd_stopretry(id, level, cid)

{

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_QUEUE_REMOVE", g_saServerNames[g_nLastServers[id]])

queue_remove(id)

}

public cmd_follow_player(id, level, cid)

{

if (get_pcvar_num(cvar_active) == 1)

{

if (get_pcvar_num(cvar_follow) == 1)

{

if (g_nLastRedirectServer >= 0)

{

new sFullAddress[MAX_SERVERADDRESS_LEN]

format(sFullAddress, MAX_SERVERADDRESS_LEN - 1, "%s:%d", g_saServerAddresses[g_nLastRedirectServer], g_naServerPorts[g_nLastRedirectServer])

console_print(id, "%s: %L", PLUGIN_TAG, id, "MSG_REDIRECTING", g_saServerNames[g_nLastRedirectServer])

client_cmd(id, "connect %s", sFullAddress)

new sUserNick[MAX_NAME_LEN]

get_user_name(id, sUserNick, MAX_NAME_LEN - 1)

if (get_pcvar_num(cvar_show) == 1)

client_print(0, print_chat, "%s: %L - %L", PLUGIN_TAG, id, "MSG_FOLLOWED", sUserNick, g_sLastRedirectName, g_saServerNames[g_nLastRedirectServer], id, "MSG_FOLLOW")

g_sLastRedirectName = sUserNick

}

else

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_CANT_FOLLOW")

}

else

client_print(id, print_chat, "%s: %L", PLUGIN_TAG, id, "MSG_FOLLOW_DISABLED")

}

return PLUGIN_CONTINUE

}

public server_menu_select(id, key)

{

if (key < 8)

{

new nServerIdx = g_naServerSelections[id][key]

new sFullAddress[MAX_SERVERADDRESS_LEN]

format(sFullAddress, MAX_SERVERADDRESS_LEN - 1, "%s:%d", g_saServerAddresses[nServerIdx], g_naServerPorts[nServerIdx])

console_print(id, "%s: %L", PLUGIN_TAG, id, "MSG_REDIRECTING", g_saServerNames[nServerIdx])

new sUserNick[MAX_NAME_LEN]

get_user_name(id, sUserNick, MAX_NAME_LEN - 1)

if (!equal(g_saServerPasswords[nServerIdx], "")) // set the user's server connect password if needed

client_cmd(id, "setinfo ^"password^" ^"%s^"", g_saServerPasswords[nServerIdx])

client_cmd(id, "setinfo ^"sredir^" ^"%d^"", g_nOwnServer)

client_cmd(id, "connect %s", sFullAddress)

if (get_pcvar_num(cvar_show) == 1)

{

new nPlayers[32]

new nPlayerNum, nPlayerCount, nCurrentPlayer

get_players(nPlayers, nPlayerNum, "c")

set_hudmessage(000, 100, 255, get_pcvar_float(cvar_announce_alivepos_x), get_pcvar_float(cvar_announce_alivepos_y), 0, 0.0, 10.0, 0.5, 0.10, 1)

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

nCurrentPlayer = nPlayers[nPlayerCount]

if (get_pcvar_num(cvar_follow) == 1)

client_print(nCurrentPlayer, print_chat, "%s: %L - %L", PLUGIN_TAG, nCurrentPlayer, "MSG_REDIRECTED", sUserNick, g_saServerNames[nServerIdx], nCurrentPlayer, "MSG_FOLLOW")

else

client_print(nCurrentPlayer, print_chat, "%s: %L", PLUGIN_TAG, nCurrentPlayer, "MSG_REDIRECTED", sUserNick, g_saServerNames[nServerIdx])

}

}

g_nLastRedirectServer = nServerIdx

g_sLastRedirectName = sUserNick

}

else

{

if (key == 8)

show_server_menu(id, g_naLastMenuPages[id] + 1)

}

}

public query_servers()

{

new nCheckMethod = get_pcvar_num(cvar_check_method)

if (nCheckMethod == 0)

return PLUGIN_HANDLED

new socket_error

new sOldRequest[9]

new sNewRequest[25]

if (nCheckMethod == 1)

// ping format didn't change for new style queries so one query for all servers

format(sOldRequest, 9, "%c%c%c%c%s", 255, 255, 255, 255, "ping")

else if (nCheckMethod == 2)

{

// we don't know what server it is so send both old and new style query

format(sOldRequest, 9, "%c%c%c%c%s", 255, 255, 255, 255, "info")

format(sNewRequest, 24, "%c%c%c%c%s", 255, 255, 255, 255, "TSource Engine Query")

}

new nServerCount = 0

new QuerySocket

new nCmdBackup

new nSendCount

while (nServerCount < g_nServerCount)

{

if (nServerCount != g_nOwnServer)

{

QuerySocket = socket_open(g_saServerAddresses[nServerCount], g_naServerPorts[nServerCount], SOCKET_UDP, socket_error)

if ((QuerySocket > 0) && (socket_error == 0))

{

g_naServerSockets[nServerCount] = QuerySocket

nCmdBackup = g_naServerCmdBackup[nServerCount]

for (nSendCount = -1; nSendCount < nCmdBackup; nSendCount++)

socket_send(QuerySocket, sOldRequest, 9)

if (nCheckMethod == 2)

for (nSendCount = -1; nSendCount < nCmdBackup; nSendCount++)

socket_send(QuerySocket, sNewRequest, 25)

}

else

{

g_naServerSockets[nServerCount] = 0

log_amx("%L", LANG_SERVER, "MSG_SOCKET_ERROR", socket_error, QuerySocket, nServerCount)

}

}

nServerCount++

}

set_task(QUERY_TIMEOUT, "receive_serverquery_answers", TASKID_QUERY_RECEIVE)

return PLUGIN_HANDLED

}

public receive_serverquery_answers()

{

new nCheckMethod = get_pcvar_num(cvar_check_method)

new sRcvBuf[MAX_INFO_LEN]

new nCharCnt

new nStructPos

new nActivePlayers

new nMaxPlayers

new nClearCounter

new nRcvLen

new nRecvCount

new sMap[MAX_MAP_LEN]

new nServerCount = 0

while (nServerCount < g_nServerCount)

{

if (!g_naServerSockets[nServerCount])

{

g_baServerResponding[nServerCount] = false

/*

should only happen for the g_nOwnServer

client_print(0, print_chat, "%s no socket", g_saServerNames[nServerCount])

*/

}

else

{

nRecvCount = 0

new nCmdBackup = g_naServerCmdBackup[nServerCount]

g_baServerResponding[nServerCount] = false

while (socket_change(g_naServerSockets[nServerCount], 1) && (nRecvCount <= nCmdBackup))

{

nRecvCount++

// initialize our receive buffer

for (nClearCounter = 0; nClearCounter < MAX_INFO_LEN; nClearCounter++)

sRcvBuf[nClearCounter] = 0

nRcvLen = socket_recv(g_naServerSockets[nServerCount], sRcvBuf, MAX_INFO_LEN)

//log_amx("finished receiving from socket %i (%s), received %i bytes", g_naServerSockets[nServerCount], g_saServerNames[nServerCount], nRcvLen)

if (nRcvLen > 5) // shortest reply is a ping response with length of 6

{

if (nCheckMethod == 1)

{

// ping response

if (equal(sRcvBuf, {-1,-1,-1,-1,'j'}, 5))

{

g_baServerResponding[nServerCount] = true

break

}

}

else if (nCheckMethod == 2)

{

if (equal(sRcvBuf, {-1,-1,-1,-1}, 4))

{

// old style HL1 response || new style HL1 response

if ((sRcvBuf[4] == 'C') || ((sRcvBuf[4] == 'm')))

{

g_baServerResponding[nServerCount] = true

nStructPos = 0

nCharCnt = 0

while ((nStructPos < STRUCT_INFO_POS_MAXPLAYERS) && (nCharCnt < MAX_INFO_LEN))

{

if (equal(sRcvBuf[nCharCnt], {0}))

{

nStructPos++

switch (nStructPos)

{

case STRUCT_INFO_POS_MAP:

{

copyc(sMap, MAX_MAP_LEN - 1, sRcvBuf[nCharCnt + 1], 0)

g_saServerMap[nServerCount] = sMap

}

case STRUCT_INFO_POS_ACTIVEPLAYERS:

{

nActivePlayers = int:sRcvBuf[nCharCnt + 1]

g_naServerActivePlayers[nServerCount] = nActivePlayers

nMaxPlayers = int:sRcvBuf[nCharCnt + 2]

g_naServerMaxPlayers[nServerCount] = nMaxPlayers

break

}

}

}

nCharCnt++

}

break

}

}

}

}

}

/*

if (nRecvCount == 0)

log_amx("no change on socket %i (%s)", g_naServerSockets[nServerCount], g_saServerNames[nServerCount])

*/

socket_close(g_naServerSockets[nServerCount])

g_naServerSockets[nServerCount] = 0

}

nServerCount++

}

if (get_pcvar_num(cvar_retry) > 0)

{

// now search for players who queued themselves to be redirected (/retry)

new bool:bCanRedirectByPassword = false

new bAdminAccess

new nServer

new nPlrCnt = 0

while (nPlrCnt < g_nRetryCount)

{

nServer = g_nRetryQueue[nPlrCnt][1]

if (nServer > -1) // just to be sure

{

new nPlr = g_nRetryQueue[nPlrCnt][0]

bAdminAccess = access(nPlr, ADMIN_RESERVATION)

bCanRedirectByPassword = !(!equal(g_saServerPasswords[nServer], "") && (g_naServerPublicPassword[nServer] == 0) && (!bAdminAccess))

if (can_redirect(nServer) && bCanRedirectByPassword)

{

console_print(nPlr, "%s: %L", PLUGIN_TAG, nPlr, "MSG_RETRY_SUCCESS")

redirect(nPlr, nServer, false, false, true)

g_naServerActivePlayers[nServer]++

}

}

nPlrCnt++

}

}

return PLUGIN_HANDLED

}

public get_admin_count()

{

new nPlayers[32]

new nPlayerNum, nPlayerCount

get_players(nPlayers, nPlayerNum, "ch")

new nAdmins = 0

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

if (access(nPlayers[nPlayerCount], ADMIN_RESERVATION))

nAdmins++

}

return nAdmins

}

public client_disconnect(id)

{

queue_remove(id)

g_nLastServers[id] = -1

}

public client_authorized(id)

{

if (g_nOwnServer == -1) // we don't know who we are so do nothing

return PLUGIN_CONTINUE

g_naLastMenuPages[id] = 1

new nAutoMode = get_pcvar_num(cvar_auto)

if (get_pcvar_num(cvar_active) == 1)

{

if (nAutoMode > 0)

{

if ((get_maxplayers() - get_playersnum(1)) == 0)

{

if (g_nServerCount > 0)

{

new nMaxAdmins = get_pcvar_num(cvar_maxadmins)

if (nMaxAdmins == 0)

nMaxAdmins = 32

if ((!access(id, ADMIN_RESERVATION)) || (get_pcvar_num(cvar_adminslots) == 0) || (get_admin_count() > nMaxAdmins))

{

redirect(id, -1, true, true, false)

return PLUGIN_CONTINUE

}

else

{

// find the user that is connected for the shortest time and redirect him

new nPlayers[32]

new nPlayerNum, nPlayerCount

new nMinConnectedTime = 0x7FFFFFFF

new nMinTimePlayer = 0

new nUserTime

get_players(nPlayers, nPlayerNum, "ch")

new nCurID

for (nPlayerCount = 0; nPlayerCount < nPlayerNum; nPlayerCount++)

{

nCurID = nPlayers[nPlayerCount]

nUserTime = get_user_time(nCurID)

if ((nUserTime < nMinConnectedTime) && (!access(nCurID, ADMIN_RESERVATION)))

{

nMinTimePlayer = nCurID

nMinConnectedTime = nUserTime

}

}

if (nMinTimePlayer != 0)

{

redirect(nMinTimePlayer, -1, true, true, true)

return PLUGIN_CONTINUE

}

}

}

}

}

}

new sSourceServer[4] // maximum is 999 servers, so we have a maximum of 3 digits

get_user_info(id, "sredir", sSourceServer, 3)

if (strcmp(sSourceServer, "") != 0)

{

new nSourceServer = str_to_num(sSourceServer)

g_nLastServers[id] = nSourceServer

if (g_bDebug)

log_amx("saved last server for player %i as server %i", id, g_nLastServers[id])

if ((nSourceServer >= 0) && (nSourceServer < g_nServerCount))

{

if (get_pcvar_num(cvar_show) == 1)

{

new nPlayers[32]

new nPlayerNum, nPlayerCount, nCurrentPlayer

new sConnectNick[MAX_NAME_LEN]

get_user_name(id, sConnectNick, MAX_NAME_LEN - 1)

get_players(nPlayers, nPlayerNum, "c")

set_hudmessage(000, 100, 255, get_pcvar_float(cvar_announce_alivepos_x), get_pcvar_float(cvar_announce_alivepos_y), 0, 0.0, 10.0, 0.5, 0.10, 1)

for (nPlayerCount = 1; nPlayerCount < nPlayerNum; nPlayerCount++)

{

nCurrentPlayer = nPlayers[nPlayerCount]

client_print(nCurrentPlayer, print_chat, "%s: %L", PLUGIN_TAG, nCurrentPlayer, "MSG_REDIRECT_RECEIVE", sConnectNick, g_saServerNames[nSourceServer])

}

}

}

new sID[1]

sID[0] = id

client_cmd(id, "setinfo ^"sredir^" ^"^"")

client_cmd(id, "setinfo ^"password^" ^"^"")

set_task(10.0, "reset_info", 0, sID, 1)

}

return PLUGIN_CONTINUE

}

public welcome_message(id[])

{

new nID = id[0]

new nLastServer = g_nLastServers[nID]

if (nLastServer >= 0)

{

new sAnnounceText[MAX_MENUBODY_LEN]

format(sAnnounceText, MAX_MENUBODY_LEN - 1, "%L", nID, "MSG_REDIRFROM", g_saServerNames[g_nOwnServer], g_saServerNames[nLastServer])

if ((get_pcvar_num(cvar_retry) == 1) && (get_pcvar_num(cvar_show) == 1))

format(sAnnounceText, MAX_MENUBODY_LEN - 1, "%s^n%L", sAnnounceText, nID, "MSG_RETRY_BACK_ANNOUNCE")

set_hudmessage(000, 100, 255, -1.0, -1.0, 0, 0.0, 10.0, 0.5, 2.0, 1)

show_hudmessage(nID, sAnnounceText)

}

}

public client_putinserver(id)

{

new sID[1]

sID[0] = id

set_task(20.0, "welcome_message", 0, sID, 1)

}

#else

public plugin_init()

{

log_amx("ERROR: Your AMXX version is too old for this plugin.")

}

#endif

/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE

*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1031\\ f0\\ fs16 \n\\ par }

*/

kura vieta te ir jaraksta servera nosaukms>?????plise help????
Link to comment
Share on other sites

izlasi pamacibu, nevis uzdod stulbus jautajumus ;)

"amxmodx/config/serverlist.ini" tur raksti ar visu, taja pamaciba saita var visu izlasit soli pa solim, btw man ir tadi gluki kad katreiz kad serveris restartejas vinam pazud

*redirect_active

*redirect_auto

*redirect_manual

*redirect_follow

taka sitie katreiz pa 0 ir kad serveris nokaras un restartejas, tad uz to laiku kamer kads neuzliek configu viniem atkal, tikmer redirect nestrada =/ kads nezin ka lai izdara lia default nava pa 0?

EDITED: vairs nevajg es sma to editoju un vis k tagad ;)

Edited by Ritsuki
Link to comment
Share on other sites

:superlol:

Gadiijumaa, kad pirmo reizi sleedz serveri iekshaa ar redirect pluginu tas fails briinumainaa kaartaa neparaadaas config mapee, luni ?

btw. pats jau arii vinu tur var sataisiit..

Edited by DeimoN
Link to comment
Share on other sites

  • 1 month later...

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...