Raised This Month: $ Target: $400
 0% 

Redirect servers crash on mapchange


  
 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
Author Message
darrin
Senior Member
Join Date: Jun 2009
Old 04-07-2011 , 07:47   Redirect servers crash on mapchange
Reply With Quote #1

Code:
/*
    AMXX Plugin: DuplicateServerInfo
    Author: Sylwester
 
    Plugin information and updates available at:
    http://forums.alliedmods.net/showthread.php?p=1326999
*/
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <fun>
#include <sockets>
#define UPDATE_INTERVAL 1.0
#define TID_TIMER 3536
new pcvar_target
new pcvar_password
new pcvar_fake_map
new pcvar_query_interval
new g_socket = 0
new g_ch_ret[4] = {255,255,255,255}
new g_s_hostname[128]
new g_s_map[64]
new g_s_desc[64]
new g_s_max_players
new g_s_players
new g_s_bots
new g_s_player_name[33][33]
new g_s_player_kills[33]
new g_timer_entid
new Float:g_t_time
new g_max_players
new pcvar_hostname
new pcvar_visiblemaxplayers
new pcvar_dsi_hostname
new pcvar_dsi_gamedesc
new pcvar_dsi_map
new pcvar_dsi_players
new pcvar_dsi_nobots_str
new pcvar_dsi_bots_str
new pcvar_dsi_maxplayers
new g_map[64]
new g_base_hostname[128]
public plugin_init(){
    register_plugin("DuplicateServerInfo", "1.44", "Sylwester")
    g_max_players = get_maxplayers()
    pcvar_target = register_cvar("dsi_target", "0.0.0.0:0")
    pcvar_password = register_cvar("dsi_password", "")
    pcvar_fake_map = register_cvar("dsi_fake_map", "dummy.bsp")
    pcvar_query_interval = register_cvar("dsi_query_interval", "10")
    pcvar_visiblemaxplayers = get_cvar_pointer("sv_visiblemaxplayers")
    pcvar_dsi_hostname = register_cvar("dsi_hostname", "1")
    pcvar_dsi_gamedesc = register_cvar("dsi_gamedesc", "1")
    pcvar_dsi_map = register_cvar("dsi_map", "1")
    pcvar_dsi_players = register_cvar("dsi_players", "1")
    pcvar_dsi_maxplayers = register_cvar("dsi_maxplayers", "1")
 
    pcvar_dsi_nobots_str = register_cvar("dsi_nobots_str", "")
    pcvar_dsi_bots_str = register_cvar("dsi_bots_str", "")
    pcvar_hostname = get_cvar_pointer("hostname")
    get_mapname(g_map, 63)
    register_forward(FM_GetGameDescription, "GameDescryption")
    set_task(1.0, "start_dsi")
    //create (if necessary) and execute cfg file storing name of dummy map
    new cfgdir[256], fh
    get_configsdir(cfgdir, 255)
    format(cfgdir, 255, "%s%s", cfgdir, "/dsi_fake_map.cfg")
    if(!file_exists(cfgdir)){
        fh = fopen(cfgdir, "wt")
        if(!fh){
            log_amx("Error: Could not open file for writing (%s).", cfgdir)
            return
        }else{
            fputs(fh, "dsi_fake_map dummy.bsp^n")
            fclose(fh)
        }
    }
    server_cmd("exec %s", cfgdir)
}
 
public start_dsi(){
    set_cvar_num("sv_allowdownload", 0) //make sure it's impossible to download fake map
    get_pcvar_string(pcvar_hostname, g_base_hostname, 127)
    create_timer()
    if(connect_server())
        send_request()
}
 
public timer_cycle(){
    static cycles
    cycles++
    check_socket()
    if(cycles*UPDATE_INTERVAL >= get_pcvar_num(pcvar_query_interval)){
        cycles = 0
        disconnect_server()
        if(!connect_server())
            return
        send_request()
    }
}
 
public plugin_end(){
    if(g_socket > 0){
        socket_close(g_socket)
        g_socket = 0
    }
    set_pcvar_string(pcvar_hostname, g_base_hostname)
}
 
public update_hostname(){
    static hostname[128], tmp[32], dsi_hostname
    dsi_hostname = get_pcvar_num(pcvar_dsi_hostname)
    if(dsi_hostname==0){
        copy(hostname, 127, g_base_hostname)
    }else{
        copy(hostname, 127, g_s_hostname)
    }
    if(g_s_bots <= 0){
        get_pcvar_string(pcvar_dsi_nobots_str, tmp, 31)
    }else{
        get_pcvar_string(pcvar_dsi_bots_str, tmp, 31)
    }
    if(strlen(tmp)>1 && containi(hostname, tmp)==-1)
        add(hostname, 127, tmp)
    set_pcvar_string(pcvar_hostname, hostname)
}
 
public update_maxplayers(){
    if(get_pcvar_num(pcvar_dsi_maxplayers)==0)
        return
    if(g_s_max_players < 1)
        return
    set_pcvar_num(pcvar_visiblemaxplayers, g_s_max_players)
}
 
public update_players(){
    static players, p_list[32]
    static p_list2[32], p_list2_cnt, userid, tmp[128]
    static p_name[32], fc_id
    if(get_pcvar_num(pcvar_dsi_players)==0){
        g_s_players = 0
    }
    //now update fake clients - amount, names, frags
    if(g_s_players > g_max_players)
        g_s_players = g_max_players
    players = 0
    for(new i=1; i<=g_max_players; i++)
        if(is_user_connected(i))
            p_list[players++] = i
    p_list2_cnt = g_s_players
    for(new i=0; i<p_list2_cnt; i++)
        p_list2[i]=i
    //remove fakeclients with names that do not appear in info of target server
    //update score of fakeclients
    for(new i=0; i<players; i++){
        new j
        get_user_name(p_list[i], p_name, 31)
        while(j<p_list2_cnt && !equal(p_name, g_s_player_name[p_list2[j]]))
            j++
        if(j==p_list2_cnt){
            //name not found - kick
            userid = get_user_userid(p_list[i])
            server_cmd("kick #%d", userid)
        }else{
            //name found - update data
            set_user_frags(p_list[i], g_s_player_kills[p_list2[j]])
            p_list2[j] = p_list2[--p_list2_cnt]
        }
    }
    //create fakeclients for remaining names
    for(new i=0; i<p_list2_cnt; i++){
        fc_id = engfunc(EngFunc_CreateFakeClient, g_s_player_name[p_list2[i]])
        dllfunc(DLLFunc_ClientConnect, fc_id, g_s_player_name[p_list2[i]], "127.0.0.1", tmp)
        dllfunc(DLLFunc_ClientPutInServer, fc_id)
        if(0 < fc_id < 33)
            set_user_frags(fc_id, g_s_player_kills[p_list2[i]])
    }
}
 
public check_socket(){
    if(g_socket <= 0)
        return
    new cnt
    while(socket_change(g_socket, 1) && cnt < 10){
        cnt++
        receive_data()
    }
}
 
public connect_server(){
    static host[64], port, tmp[128], error, szError[64], tmp2[32]
    get_pcvar_string(pcvar_target, tmp, 127)
    strtok(tmp, host, 63, tmp2, 31, ':')
    port = str_to_num(tmp2)
    if(strlen(host) < 2 || port <=0 || port >= 65536){
        log_amx("incorrect data stored in dsi_target cvar ( ^"%s^" ), must be ^"ip:port^" or ^"dns:port^"", tmp)
        return false
    }
    if(g_socket > 0){
        socket_close(g_socket)
        g_socket = 0
    }
    g_socket = socket_open(host, port, SOCKET_UDP, error)
    if(g_socket <= 0 || error){
        switch(error){
            case 0: szError = "unknown"
            case 1: szError = "error while creating socket"
            case 2: szError = "could not resolve hostname"
            case 3: format(szError, 63, "could not connect to %s:%d", host, port)
        }
        log_amx("Socket error: %s", szError)
        return false
    }
    return true
}
 
public disconnect_server(){
    if(g_socket > 0){
        socket_close(g_socket)
        g_socket = 0
    }
}
 
public client_connect(id){
    static ip[32], pw[64]
    get_pcvar_string(pcvar_password, pw, 63)
    if(strlen(pw)>0){
        client_cmd(id, "password %s", pw)
    }
    get_pcvar_string(pcvar_target, ip, 31)
    client_cmd(id, "Connect %s", ip)
}
 
public create_timer(){
    g_timer_entid = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString,"info_target"))
    if(pev_valid(g_timer_entid)){
        set_pev(g_timer_entid, pev_classname, "dsi_timer")
        global_get(glb_time, g_t_time)
        set_pev(g_timer_entid, pev_nextthink, g_t_time + UPDATE_INTERVAL)
        register_forward(FM_Think,"fwd_Think")
    }else{
        log_amx("Warning: Failed to create timer entity, using task instead")
        set_task(UPDATE_INTERVAL, "timer_cycle", TID_TIMER, "", 0, "b")
    }
}
 
public GameDescryption(){
    if(get_pcvar_num(pcvar_dsi_gamedesc)==0)
        return FMRES_IGNORED
    if(strlen(g_s_desc)<=1)
        return FMRES_IGNORED
    forward_return(FMV_STRING, g_s_desc)
    return FMRES_SUPERCEDE
}
 
public update_map(){
    if(get_pcvar_num(pcvar_dsi_map)==0)
        return
    if(!equal(g_map, g_s_map)){
        if(!is_map_valid(g_s_map))
            create_fake_map()
        if(is_map_valid(g_s_map)){
            server_cmd("changelevel ^"%s^"", g_s_map)
        }else{
            log_amx("Warning: Unable to change map to %s (map file is not valid or does not exist)", g_s_map)
        }
    }
}
 
public ret_ac(num){ //change byte -128..127 into 0..255
    if(num<0)
        return 256+num
    return num
}
 
public send_request(){
    if(g_socket <= 0)
        return
    new cache[32]
    //http://developer.valvesoftware.com/wiki/Server_Queries#A2S_INFO
    format(cache, 25, "%c%c%c%c%c%s%c", 255, 255, 255, 255, 84, "Source Engine Query", 0 )
    socket_send2(g_socket, cache, 25)
    //http://developer.valvesoftware.com/wiki/Server_Queries#A2S_PLAYER
    format(cache, 25, "%c%c%c%c%c%c%c%c%c", 255, 255, 255, 255, 85, g_ch_ret[0], g_ch_ret[1], g_ch_ret[2], g_ch_ret[3])  //ping
    socket_send2(g_socket, cache, 9)
}
 
public create_fake_map(){
    new map[64], path_src[128], path_dest[128]
    get_pcvar_string(pcvar_fake_map, map, 63)
    format(path_src, 127, "maps/%s", map)
    format(path_dest, 127, "maps/%s.bsp", g_s_map)
    if(!file_exists(path_src)){
        log_amx("Warning: unable to create fake map file, source file %s does not exist", path_src)
        return
    }
    if(file_exists(path_dest)){
        log_amx("Warning: unable to create fake map file, map file already exists %s (but is not valid map)", path_dest)
        return
    }
    if(!rename_file(path_src, path_dest, 1)){
        log_amx("Warning: unable to create fake map file, renaming failed (%s -> %s)", path_src, path_dest)
        return
    }
    new cfgdir[256], cache[128], fh
    get_configsdir(cfgdir, 255)
    format(cfgdir, 255, "%s%s", cfgdir, "/dsi_fake_map.cfg")
    fh = fopen(cfgdir, "wt")
    if(!fh){
        log_amx("Error: Could not open file for writing (%s).", cfgdir)
        return
    }else{
        format(cache, 127, "dsi_fake_map %s.bsp^n", g_s_map)
        fputs(fh, cache)
        fclose(fh)
    }
}
 
public fwd_Think(Ent){
    if(Ent != g_timer_entid)
        return FMRES_IGNORED
    g_t_time += UPDATE_INTERVAL
    set_pev(Ent, pev_nextthink, g_t_time)
    timer_cycle()
    return FMRES_IGNORED
}
 
public receive_data(){
    static cache[2048], len
    len = socket_recv(g_socket, cache, 2047)
    if(len < 5)
        return
    if(!equal( cache, { -1, -1, -1, -1 }, 4 ) )
        return
    if(cache[4] == 'D'){ //(players details) A2S_PLAYER reply if sent challange number is correct
        g_s_players = cache[5]
        new j=6
        for(new i=0; i<g_s_players; i++){
            j++
            j += copyc(g_s_player_name[i], 31, cache[j], 0)+1
            g_s_player_kills[i] =  ret_ac(cache[j+3])<<24|ret_ac(cache[j+2])<<16|ret_ac(cache[j+1])<<8|ret_ac(cache[j])
            j+=8
        }
        update_players()
    }
     //(correct challange number) A2S_PLAYER reply if sent challange number is unknown/incorrect
    if(cache[4] == 'A'){
        g_ch_ret[0] = cache[5]
        g_ch_ret[1] = cache[6]
        g_ch_ret[2] = cache[7]
        g_ch_ret[3] = cache[8]
        new tmp[16]
        format(tmp, 15, "%c%c%c%c%c%c%c%c%c", 255, 255, 255, 255, 85, g_ch_ret[0], g_ch_ret[1], g_ch_ret[2], g_ch_ret[3])  //ping
        socket_send2(g_socket, cache, 9)
    }
    if(cache[4] == 'I'){ //(server details) A2S_INFO reply
        new i = 6, dir[64]
        i += copyc(g_s_hostname, 127, cache[i], 0)+1
        i += copyc(g_s_map, 63, cache[i], 0)+1
        i += copyc(dir, 63, cache[i], 0)+1
        i += copyc(g_s_desc, 63, cache[i], 0)+1
        g_s_max_players = cache[i+3]
        g_s_bots = cache[i+4]
        new pw[63]
        get_pcvar_string(pcvar_password, pw, 63)
        if(cache[i+7] && strlen(pw)<=0){
            log_amx("Warning: target server is password protected, set dsi_password to allow redirected players to join target server")
        }
        update_map()
        update_hostname()
        update_maxplayers()
    }
}
All my redirect servers crash if the game server changes map, which it does every 20 min. I think this is because I have set the redirect servers to immitate a fake dummy map from the real server, or something.
This plugin is from: http://forums.alliedmods.net/showthread.php?t=140821
I have commented out some of the code to make it work with this plugin:
http://forums.alliedmods.net/showthread.php?p=254620

Code:
 //now update fake clients - amount, names, frags
    /*if(g_s_players > g_max_players)
        g_s_players = g_max_players
    players = 0
    for(new i=1; i<=g_max_players; i++)
        if(is_user_connected(i))
            p_list[players++] = i
    p_list2_cnt = g_s_players
    for(new i=0; i<p_list2_cnt; i++)
        p_list2[i]=i*/

However the redirect servers come back online after 1 minute from the mapchange
darrin is offline
 


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 20:08.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode