Its just a little change on the normal in game display behavior
0 removals
939 lines
0 additions
939 lines
#!/usr/bin/perl
#!/usr/bin/perl
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
# http://www.hlxcommunity.com
#
#
# HLstatsX Community Edition is a continuation of
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
# http://ovrsized.neo-soft.org/
#
#
# ELstatsNEO is an very improved & enhanced - so called Ultra-Humongus Edition of HLstatsX
# ELstatsNEO is an very improved & enhanced - so called Ultra-Humongus Edition of HLstatsX
# HLstatsX - Real-time player and clan rankings and statistics for Half-Life 2
# HLstatsX - Real-time player and clan rankings and statistics for Half-Life 2
# http://www.hlstatsx.com/
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
# Copyright (C) 2001 Simon Garner
#
#
# This program is free software; you can redistribute it and/or
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# For support and installation notes visit http://www.hlxcommunity.com
# For support and installation notes visit http://www.hlxcommunity.com
use strict;
use strict;
no strict 'vars';
no strict 'vars';
$SIG{HUP} = 'HUP_handler';
$SIG{HUP} = 'HUP_handler';
$SIG{INT} = 'INT_handler'; # unix
$SIG{INT} = 'INT_handler'; # unix
$SIG{INT2} = 'INT_handler'; # windows
$SIG{INT2} = 'INT_handler'; # windows
##
##
## Settings
## Settings
##
##
# $opt_configfile - Absolute path and filename of configuration file.
# $opt_configfile - Absolute path and filename of configuration file.
$opt_configfile = "./hlstats.conf";
$opt_configfile = "./hlstats.conf";
# $opt_libdir - Directory to look in for local required files
# $opt_libdir - Directory to look in for local required files
# (our *.plib, *.pm files).
# (our *.plib, *.pm files).
$opt_libdir = "./";
$opt_libdir = "./";
##
##
##
##
################################################################################
################################################################################
## No need to edit below this line
## No need to edit below this line
##
##
use Getopt::Long;
use Getopt::Long;
use Time::Local;
use Time::Local;
use IO::Socket;
use IO::Socket;
use IO::Select;
use IO::Select;
use DBI;
use DBI;
use Digest::MD5;
use Digest::MD5;
use Encode;
use Encode;
use bytes;
use bytes;
require "$opt_libdir/ConfigReaderSimple.pm";
require "$opt_libdir/ConfigReaderSimple.pm";
require "$opt_libdir/TRcon.pm";
require "$opt_libdir/TRcon.pm";
require "$opt_libdir/BASTARDrcon.pm";
require "$opt_libdir/BASTARDrcon.pm";
require "$opt_libdir/HLstats_Server.pm";
require "$opt_libdir/HLstats_Server.pm";
require "$opt_libdir/HLstats_Player.pm";
require "$opt_libdir/HLstats_Player.pm";
require "$opt_libdir/HLstats_Game.pm";
require "$opt_libdir/HLstats_Game.pm";
do "$opt_libdir/HLstats_GameConstants.plib";
do "$opt_libdir/HLstats_GameConstants.plib";
do "$opt_libdir/HLstats.plib";
do "$opt_libdir/HLstats.plib";
do "$opt_libdir/HLstats_EventHandlers.plib";
do "$opt_libdir/HLstats_EventHandlers.plib";
$|=1;
$|=1;
Getopt::Long::Configure ("bundling");
Getopt::Long::Configure ("bundling");
$last_trend_timestamp = 0;
$last_trend_timestamp = 0;
binmode STDIN, ":utf8";
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";
binmode STDOUT, ":utf8";
##
##
## Functions
## Functions
##
##
sub lookupPlayer
sub lookupPlayer
{
{
my ($saddr, $id, $uniqueid) = @_;
my ($saddr, $id, $uniqueid) = @_;
if (defined($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}))
if (defined($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}))
{
{
return $g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"};
return $g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"};
}
}
return undef;
return undef;
}
}
sub removePlayer
sub removePlayer
{
{
my ($saddr, $id, $uniqueid, $dontUpdateCount) = @_;
my ($saddr, $id, $uniqueid, $dontUpdateCount) = @_;
my $deleteplayer = 0;
my $deleteplayer = 0;
if(defined($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}))
if(defined($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}))
{
{
$deleteplayer = 1;
$deleteplayer = 1;
}
}
else
else
{
{
&::printEvent("400", "Bad attempted delete ($saddr) ($id/$uniqueid)");
&::printEvent("400", "Bad attempted delete ($saddr) ($id/$uniqueid)");
}
}
if ($deleteplayer == 1) {
if ($deleteplayer == 1) {
$g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}->playerCleanup();
$g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"}->playerCleanup();
delete($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"});
delete($g_servers{$saddr}->{"srv_players"}->{"$id/$uniqueid"});
if (!$dontUpdateCount) # double negative, i know...
if (!$dontUpdateCount) # double negative, i know...
{
{
$g_servers{$saddr}->updatePlayerCount();
$g_servers{$saddr}->updatePlayerCount();
}
}
}
}
}
}
sub checkBonusRound
sub checkBonusRound
{
{
if ($g_servers{$s_addr}->{bonusroundtime} > 0 && ($::ev_remotetime > ($g_servers{$s_addr}->{bonusroundtime_ts} + $g_servers{$s_addr}->{bonusroundtime}))) {
if ($g_servers{$s_addr}->{bonusroundtime} > 0 && ($::ev_remotetime > ($g_servers{$s_addr}->{bonusroundtime_ts} + $g_servers{$s_addr}->{bonusroundtime}))) {
if ($g_servers{$s_addr}->{bonusroundtime_state} == 1) {
if ($g_servers{$s_addr}->{bonusroundtime_state} == 1) {
&printEvent("SERVER", "Bonus Round Expired",1);
&printEvent("SERVER", "Bonus Round Expired",1);
}
}
$g_servers{$s_addr}->set("bonusroundtime_state",0);
$g_servers{$s_addr}->set("bonusroundtime_state",0);
}
}
if($g_servers{$s_addr}->{bonusroundignore} == 1 && $g_servers{$s_addr}->{bonusroundtime_state} == 1) {
if($g_servers{$s_addr}->{bonusroundignore} == 1 && $g_servers{$s_addr}->{bonusroundtime_state} == 1) {
return 1;
return 1;
}
}
return 0;
return 0;
}
}
sub is_number ($) { ( $_[0] ^ $_[0] ) eq '0' }
sub is_number ($) { ( $_[0] ^ $_[0] ) eq '0' }
#
#
# void printNotice (string notice)
# void printNotice (string notice)
#
#
# Prins a debugging notice to stdout.
# Prins a debugging notice to stdout.
#
#
sub printNotice
sub printNotice
{
{
my ($notice) = @_;
my ($notice) = @_;
if ($g_debug > 1) {
if ($g_debug > 1) {
print ">> $notice\n";
print ">> $notice\n";
}
}
}
}
sub track_hlstats_trend
sub track_hlstats_trend
{
{
if ($last_trend_timestamp > 0) {
if ($last_trend_timestamp > 0) {
if ($last_trend_timestamp+299 < $ev_daemontime) {
if ($last_trend_timestamp+299 < $ev_daemontime) {
my $query = "
my $query = "
SELECT
SELECT
COUNT(*),
COUNT(*),
a.game
a.game
FROM
FROM
hlstats_Players a
hlstats_Players a
INNER JOIN
INNER JOIN
(
(
SELECT
SELECT
game
game
FROM
FROM
hlstats_Servers
hlstats_Servers
GROUP BY
GROUP BY
game
game
) AS b
) AS b
ON
ON
a.game = b.game
a.game = b.game
GROUP BY
GROUP BY
a.game
a.game
";
";
my $result = &execCached("get_total_player_counts", $query);
my $result = &execCached("get_total_player_counts", $query);
my $insvalues = "";
my $insvalues = "";
while ( my($total_players, $game) = $result->fetchrow_array) {
while ( my($total_players, $game) = $result->fetchrow_array) {
my $query = "
my $query = "
SELECT
SELECT
SUM(kills),
SUM(kills),
SUM(headshots),
SUM(headshots),
COUNT(serverId),
COUNT(serverId),
SUM(act_players),
SUM(act_players),
SUM(max_players)
SUM(max_players)
FROM
FROM
hlstats_Servers
hlstats_Servers
WHERE
WHERE
game=?
game=?
";
";
my $data = &execCached("get_game_stat_counts", $query, "eSQL($game));
my $data = &execCached("get_game_stat_counts", $query, "eSQL($game));
my ($total_kills, $total_headshots, $total_servers, $act_slots, $max_slots) = $data->fetchrow_array;
my ($total_kills, $total_headshots, $total_servers, $act_slots, $max_slots) = $data->fetchrow_array;
if ($max_slots > 0) {
if ($max_slots > 0) {
if ($act_slots > $max_slots) {
if ($act_slots > $max_slots) {
$act_slots = $max_slots;
$act_slots = $max_slots;
}
}
}
}
if ($insvalues ne "") {
if ($insvalues ne "") {
$insvalues .= ",";
$insvalues .= ",";
}
}
$insvalues .= "
$insvalues .= "
(
(
$ev_daemontime,
$ev_daemontime,
'"."eSQL($game)."',
'"."eSQL($game)."',
$total_players,
$total_players,
$total_kills,
$total_kills,
$total_headshots,
$total_headshots,
$total_servers,
$total_servers,
$act_slots,
$act_slots,
$max_slots
$max_slots
)
)
";
";
}
}
if ($insvalues ne "") {
if ($insvalues ne "") {
&execNonQuery("
&execNonQuery("
INSERT INTO
INSERT INTO
hlstats_Trend
hlstats_Trend
(
(
timestamp,
timestamp,
game,
game,
players,
players,
kills,
kills,
headshots,
headshots,
servers,
servers,
act_slots,
act_slots,
max_slots
max_slots
)
)
VALUES $insvalues
VALUES $insvalues
");
");
}
}
$last_trend_timestamp = $ev_daemontime;
$last_trend_timestamp = $ev_daemontime;
&::printEvent("HLSTATSX", "Insert new server trend timestamp", 1);
&::printEvent("HLSTATSX", "Insert new server trend timestamp", 1);
}
}
} else {
} else {
$last_trend_timestamp = $ev_daemontime;
$last_trend_timestamp = $ev_daemontime;
}
}
}
}
sub send_global_chat
sub send_global_chat
{
{
my ($message) = @_;
my ($message) = @_;
while( my($server) = each(%g_servers))
while( my($server) = each(%g_servers))
{
{
if ($server ne $s_addr && $g_servers{$server}->{"srv_players"})
if ($server ne $s_addr && $g_servers{$server}->{"srv_players"})
{
{
my @userlist;
my @userlist;
my %players_temp=%{$g_servers{$server}->{"srv_players"}};
my %players_temp=%{$g_servers{$server}->{"srv_players"}};
my $pcount = scalar keys %players_temp;
my $pcount = scalar keys %players_temp;
if ($pcount > 0) {
if ($pcount > 0) {
while ( my($pl, $b_player) = each(%players_temp) ) {
while ( my($pl, $b_player) = each(%players_temp) ) {
my $b_userid = $b_player->{userid};
my $b_userid = $b_player->{userid};
if ($g_global_chat == 2) {
if ($g_global_chat == 2) {
my $b_steamid = $b_player->{uniqueid};
my $b_steamid = $b_player->{uniqueid};
if ($g_servers{$server}->is_admin($b_steamid) == 1) {
if ($g_servers{$server}->is_admin($b_steamid) == 1) {
if (($b_player->{display_events} == 1) && ($b_player->{display_chat} == 1)) {
if (($b_player->{display_events} == 1) && ($b_player->{display_chat} == 1)) {
push(@userlist, $b_player->{userid});
push(@userlist, $b_player->{userid});
}
}
}
}
} else {
} else {
if (($b_player->{display_events} == 1) && ($b_player->{display_chat} == 1)) {
if (($b_player->{display_events} == 1) && ($b_player->{display_chat} == 1)) {
push(@userlist, $b_player->{userid});
push(@userlist, $b_player->{userid});
}
}
}
}
}
}
$g_servers{$server}->messageMany($message, 0, @userlist);
$g_servers{$server}->messageMany($message, 0, @userlist);
}
}
}
}
}
}
}
}
#
#
# void buildEventInsertData ()
# void buildEventInsertData ()
#
#
# Ran at startup to init event table queues, build initial queries, and set allowed-null columns
# Ran at startup to init event table queues, build initial queries, and set allowed-null columns
#
#
my %g_eventtable_data = ();
my %g_eventtable_data = ();
sub buildEventInsertData
sub buildEventInsertData
{
{
my $insertType = "";
my $insertType = "";
$insertType = " DELAYED" if ($db_lowpriority);
$insertType = " DELAYED" if ($db_lowpriority);
while ( my ($table, $colsref) = each(%g_eventTables) )
while ( my ($table, $colsref) = each(%g_eventTables) )
{
{
$g_eventtable_data{$table}{queue} = [];
$g_eventtable_data{$table}{queue} = [];
$g_eventtable_data{$table}{nullallowed} = 0;
$g_eventtable_data{$table}{nullallowed} = 0;
$g_eventtable_data{$table}{lastflush} = $ev_daemontime;
$g_eventtable_data{$table}{lastflush} = $ev_daemontime;
$g_eventtable_data{$table}{query} = "
$g_eventtable_data{$table}{query} = "
INSERT$insertType INTO
INSERT$insertType INTO
hlstats_Events_$table
hlstats_Events_$table
(
(
eventTime,
eventTime,
serverId,
serverId,
map"
map"
;
;
my $j = 0;
my $j = 0;
foreach $i (@{$colsref})
foreach $i (@{$colsref})
{
{
$g_eventtable_data{$table}{query} .= ",\n$i";
$g_eventtable_data{$table}{query} .= ",\n$i";
if (substr($i, 0, 4) eq 'pos_') {
if (substr($i, 0, 4) eq 'pos_') {
$g_eventtable_data{$table}{nullallowed} |= (1 << $j);
$g_eventtable_data{$table}{nullallowed} |= (1 << $j);
}
}
$j++;
$j++;
}
}
$g_eventtable_data{$table}{query} .= ") VALUES\n";
$g_eventtable_data{$table}{query} .= ") VALUES\n";
}
}
}
}
#
#
# void recordEvent (string table, array cols, bool getid, [mixed eventData ...])
# void recordEvent (string table, array cols, bool getid, [mixed eventData ...])
#
#
# Queues an event for addition to an Events table, flushing when hitting table queue limit.
# Queues an event for addition to an Events table, flushing when hitting table queue limit.
#
#
sub recordEvent
sub recordEvent
{
{
my $table = shift;
my $table = shift;
my $unused = shift;
my $unused = shift;
my @coldata = @_;
my @coldata = @_;
my $value = "(FROM_UNIXTIME($::ev_unixtime),".$g_servers{$s_addr}->{'id'}.",'".quoteSQL($g_servers{$s_addr}->get_map())."'";
my $value = "(FROM_UNIXTIME($::ev_unixtime),".$g_servers{$s_addr}->{'id'}.",'".quoteSQL($g_servers{$s_addr}->get_map())."'";
$j = 0;
$j = 0;
for $i (@coldata) {
for $i (@coldata) {
if ($g_eventtable_data{$table}{nullallowed} & (1 << $j) && (!defined($i) || $i eq "")) {
if ($g_eventtable_data{$table}{nullallowed} & (1 << $j) && (!defined($i) || $i eq "")) {
$value .= ",NULL";
$value .= ",NULL";
} elsif (!defined($i)) {
} elsif (!defined($i)) {
$value .= ",''";
$value .= ",''";
} else {
} else {
$value .= ",'".quoteSQL($i)."'";
$value .= ",'".quoteSQL($i)."'";
}
}
$j++;
$j++;
}
}
$value .= ")";
$value .= ")";
push(@{$g_eventtable_data{$table}{queue}}, $value);
push(@{$g_eventtable_data{$table}{queue}}, $value);
if (scalar(@{$g_eventtable_data{$table}{queue}}) > $g_event_queue_size)
if (scalar(@{$g_eventtable_data{$table}{queue}}) > $g_event_queue_size)
{
{
flushEventTable($table);
flushEventTable($table);
}
}
}
}
sub flushEventTable
sub flushEventTable
{
{
my ($table) = @_;
my ($table) = @_;
if (scalar(@{$g_eventtable_data{$table}{queue}}) == 0)
if (scalar(@{$g_eventtable_data{$table}{queue}}) == 0)
{
{
return;
return;
}
}
my $query = $g_eventtable_data{$table}{query};
my $query = $g_eventtable_data{$table}{query};
foreach (@{$g_eventtable_data{$table}{queue}})
foreach (@{$g_eventtable_data{$table}{queue}})
{
{
$query .= $_.",";
$query .= $_.",";
}
}
$query =~ s/,$//;
$query =~ s/,$//;
execNonQuery($query);
execNonQuery($query);
$g_eventtable_data{$table}{lastflush} = $ev_daemontime;
$g_eventtable_data{$table}{lastflush} = $ev_daemontime;
$g_eventtable_data{$table}{queue} = [];
$g_eventtable_data{$table}{queue} = [];
}
}
#
#
# array calcSkill (int skill_mode, int killerSkill, int killerKills, int victimSkill, int victimKills, string weapon)
# array calcSkill (int skill_mode, int killerSkill, int killerKills, int victimSkill, int victimKills, string weapon)
#
#
# Returns an array, where the first index contains the killer's new skill, and
# Returns an array, where the first index contains the killer's new skill, and
# the second index contains the victim's new skill.
# the second index contains the victim's new skill.
#
#
sub calcSkill
sub calcSkill
{
{
my ($skill_mode, $killerSkill, $killerKills, $victimSkill, $victimKills, $weapon, $killerTeam) = @_;
my ($skill_mode, $killerSkill, $killerKills, $victimSkill, $victimKills, $weapon, $killerTeam) = @_;
my @newSkill;
my @newSkill;
# ignored bots never do a "comeback"
# ignored bots never do a "comeback"
return ($g_skill_minchange, $victimSkill) if ($killerSkill < 1);
return ($g_skill_minchange, $victimSkill) if ($killerSkill < 1);
return ($killerSkill + $g_skill_minchange, $victimSkill) if ($victimSkill < 1);
return ($killerSkill + $g_skill_minchange, $victimSkill) if ($victimSkill < 1);
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("Begin calcSkill: killerSkill=$killerSkill");
&printNotice("Begin calcSkill: killerSkill=$killerSkill");
&printNotice("Begin calcSkill: victimSkill=$victimSkill");
&printNotice("Begin calcSkill: victimSkill=$victimSkill");
}
}
my $modifier = 1.00;
my $modifier = 1.00;
# Look up the weapon's skill modifier
# Look up the weapon's skill modifier
if (defined($g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon})) {
if (defined($g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon})) {
$modifier = $g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon}{modifier};
$modifier = $g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon}{modifier};
}
}
# Calculate the new skills
# Calculate the new skills
my $killerSkillChange = 0;
my $killerSkillChange = 0;
if ($g_skill_ratio_cap > 0) {
if ($g_skill_ratio_cap > 0) {
# SkillRatioCap, from *XYZ*SaYnt
# SkillRatioCap, from *XYZ*SaYnt
#
#
# dgh...we want to cap the ratio between the victimkill and killerskill. For example, if the number 1 player
# dgh...we want to cap the ratio between the victimkill and killerskill. For example, if the number 1 player
# kills a newbie, he gets 1000/5000 * 5 * 1 = 1 points. If gets killed by the newbie, he gets 5000/1000 * 5 *1
# kills a newbie, he gets 1000/5000 * 5 * 1 = 1 points. If gets killed by the newbie, he gets 5000/1000 * 5 *1
# = -25 points. Not exactly fair. To fix this, I'm going to cap the ratio to 1/2 and 2/1.
# = -25 points. Not exactly fair. To fix this, I'm going to cap the ratio to 1/2 and 2/1.
# these numbers are designed such that an excellent player will have to get about a 2:1 ratio against noobs to
# these numbers are designed such that an excellent player will have to get about a 2:1 ratio against noobs to
# hold steady in points.
# hold steady in points.
my $lowratio = 0.7;
my $lowratio = 0.7;
my $highratio = 1.0 / $lowratio;
my $highratio = 1.0 / $lowratio;
my $ratio = ($victimSkill / $killerSkill);
my $ratio = ($victimSkill / $killerSkill);
if ($ratio < $lowratio) { $ratio = $lowratio; }
if ($ratio < $lowratio) { $ratio = $lowratio; }
if ($ratio > $highratio) { $ratio = $highratio; }
if ($ratio > $highratio) { $ratio = $highratio; }
$killerSkillChange = $ratio * 5 * $modifier;
$killerSkillChange = $ratio * 5 * $modifier;
} else {
} else {
$killerSkillChange = ($victimSkill / $killerSkill) * 5 * $modifier;
$killerSkillChange = ($victimSkill / $killerSkill) * 5 * $modifier;
}
}
if ($killerSkillChange > $g_skill_maxchange) {
if ($killerSkillChange > $g_skill_maxchange) {
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_maxchange") if ($g_debug > 2);
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_maxchange") if ($g_debug > 2);
$killerSkillChange = $g_skill_maxchange;
$killerSkillChange = $g_skill_maxchange;
}
}
my $victimSkillChange = $killerSkillChange;
my $victimSkillChange = $killerSkillChange;
if ($skill_mode == 1)
if ($skill_mode == 1)
{
{
$victimSkillChange = $killerSkillChange * 0.75;
$victimSkillChange = $killerSkillChange * 0.75;
}
}
elsif ($skill_mode == 2)
elsif ($skill_mode == 2)
{
{
$victimSkillChange = $killerSkillChange * 0.5;
$victimSkillChange = $killerSkillChange * 0.5;
}
}
elsif ($skill_mode == 3)
elsif ($skill_mode == 3)
{
{
$victimSkillChange = $killerSkillChange * 0.25;
$victimSkillChange = $killerSkillChange * 0.25;
}
}
elsif ($skill_mode == 4)
elsif ($skill_mode == 4)
{
{
$victimSkillChange = 0;
$victimSkillChange = 0;
}
}
elsif ($skill_mode == 5)
elsif ($skill_mode == 5)
{
{
#Zombie Panic: Source only
#Zombie Panic: Source only
#Method suggested by heimer. Survivor's lose half of killer's gain when dying, but Zombie's only lose a quarter.
#Method suggested by heimer. Survivor's lose half of killer's gain when dying, but Zombie's only lose a quarter.
if ($killerTeam eq "Undead")
if ($killerTeam eq "Undead")
{
{
$victimSkillChange = $killerSkillChange * 0.5;
$victimSkillChange = $killerSkillChange * 0.5;
}
}
elsif ($killerTeam eq "Survivor")
elsif ($killerTeam eq "Survivor")
{
{
$victimSkillChange = $killerSkillChange * 0.25;
$victimSkillChange = $killerSkillChange * 0.25;
}
}
}
}
if ($victimSkillChange > $g_skill_maxchange) {
if ($victimSkillChange > $g_skill_maxchange) {
&printNotice("Capping victim skill change of $victimSkillChange to $g_skill_maxchange") if ($g_debug > 2);
&printNotice("Capping victim skill change of $victimSkillChange to $g_skill_maxchange") if ($g_debug > 2);
$victimSkillChange = $g_skill_maxchange;
$victimSkillChange = $g_skill_maxchange;
}
}
if ($g_skill_maxchange >= $g_skill_minchange) {
if ($g_skill_maxchange >= $g_skill_minchange) {
if ($killerSkillChange < $g_skill_minchange) {
if ($killerSkillChange < $g_skill_minchange) {
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_minchange") if ($g_debug > 2);
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_minchange") if ($g_debug > 2);
$killerSkillChange = $g_skill_minchange;
$killerSkillChange = $g_skill_minchange;
}
}
if (($victimSkillChange < $g_skill_minchange) && ($skill_mode != 4)) {
if (($victimSkillChange < $g_skill_minchange) && ($skill_mode != 4)) {
&printNotice("Capping victim skill change of $victimSkillChange to $g_skill_minchange") if ($g_debug > 2);
&printNotice("Capping victim skill change of $victimSkillChange to $g_skill_minchange") if ($g_debug > 2);
$victimSkillChange = $g_skill_minchange;
$victimSkillChange = $g_skill_minchange;
}
}
}
}
if (($killerKills < $g_player_minkills ) || ($victimKills < $g_player_minkills )) {
if (($killerKills < $g_player_minkills ) || ($victimKills < $g_player_minkills )) {
$killerSkillChange = $g_skill_minchange;
$killerSkillChange = $g_skill_minchange;
if ($skill_mode != 4) {
if ($skill_mode != 4) {
$victimSkillChange = $g_skill_minchange;
$victimSkillChange = $g_skill_minchange;
} else {
} else {
$victimSkillChange = 0;
$victimSkillChange = 0;
}
}
}
}
$killerSkill += $killerSkillChange;
$killerSkill += $killerSkillChange;
$victimSkill -= $victimSkillChange;
$victimSkill -= $victimSkillChange;
# we want int not float
# we want int not float
$killerSkill = sprintf("%d", $killerSkill + 0.5);
$killerSkill = sprintf("%d", $killerSkill + 0.5);
$victimSkill = sprintf("%d", $victimSkill + 0.5);
$victimSkill = sprintf("%d", $victimSkill + 0.5);
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("End calcSkill: killerSkill=$killerSkill");
&printNotice("End calcSkill: killerSkill=$killerSkill");
&printNotice("End calcSkill: victimSkill=$victimSkill");
&printNotice("End calcSkill: victimSkill=$victimSkill");
}
}
return ($killerSkill, $victimSkill);
return ($killerSkill, $victimSkill);
}
}
sub calcL4DSkill
sub calcL4DSkill
{
{
my ($killerSkill, $weapon, $difficulty) = @_;
my ($killerSkill, $weapon, $difficulty) = @_;
# ignored bots never do a "comeback"
# ignored bots never do a "comeback"
#return ($killerSkill, $victimSkill) if ($killerSkill < 1);
#return ($killerSkill, $victimSkill) if ($killerSkill < 1);
#return ($killerSkill, $victimSkill) if ($victimSkill < 1);
#return ($killerSkill, $victimSkill) if ($victimSkill < 1);
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("Begin calcSkill: killerSkill=$killerSkill");
&printNotice("Begin calcSkill: killerSkill=$killerSkill");
&printNotice("Begin calcSkill: victimSkill=$victimSkill");
&printNotice("Begin calcSkill: victimSkill=$victimSkill");
}
}
my $modifier = 1.00;
my $modifier = 1.00;
# Look up the weapon's skill modifier
# Look up the weapon's skill modifier
if (defined($g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon})) {
if (defined($g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon})) {
$modifier = $g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon}{modifier};
$modifier = $g_games{$g_servers{$s_addr}->{game}}{weapons}{$weapon}{modifier};
}
}
# Calculate the new skills
# Calculate the new skills
$diffweight=0.5;
$diffweight=0.5;
if ($difficulty > 0) {
if ($difficulty > 0) {
$diffweight = $difficulty / 2;
$diffweight = $difficulty / 2;
}
}
my $killerSkillChange = $pointvalue * $diffweight;
my $killerSkillChange = $pointvalue * $diffweight;
if ($killerSkillChange > $g_skill_maxchange) {
if ($killerSkillChange > $g_skill_maxchange) {
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_maxchange") if ($g_debug > 2);
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_maxchange") if ($g_debug > 2);
$killerSkillChange = $g_skill_maxchange;
$killerSkillChange = $g_skill_maxchange;
}
}
if ($g_skill_maxchange >= $g_skill_minchange) {
if ($g_skill_maxchange >= $g_skill_minchange) {
if ($killerSkillChange < $g_skill_minchange) {
if ($killerSkillChange < $g_skill_minchange) {
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_minchange") if ($g_debug > 2);
&printNotice("Capping killer skill change of $killerSkillChange to $g_skill_minchange") if ($g_debug > 2);
$killerSkillChange = $g_skill_minchange;
$killerSkillChange = $g_skill_minchange;
}
}
}
}
$killerSkill += $killerSkillChange;
$killerSkill += $killerSkillChange;
# we want int not float
# we want int not float
$killerSkill = sprintf("%d", $killerSkill + 0.5);
$killerSkill = sprintf("%d", $killerSkill + 0.5);
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("End calcSkill: killerSkill=$killerSkill");
&printNotice("End calcSkill: killerSkill=$killerSkill");
}
}
return $killerSkill;
return $killerSkill;
}
}
# Gives members of 'team' an extra 'reward' skill points. Members of the team
# Gives members of 'team' an extra 'reward' skill points. Members of the team
# who have been inactive (no events) for more than 2 minutes are not rewarded.
# who have been inactive (no events) for more than 2 minutes are not rewarded.
#
#
sub rewardTeam
sub rewardTeam
{
{
my ($team, $reward, $actionid, $actionname, $actioncode) = @_;
my ($team, $reward, $actionid, $actionname, $actioncode) = @_;
$rcmd = $g_servers{$s_addr}->{broadcasting_command};
$rcmd = $g_servers{$s_addr}->{broadcasting_command};
my $player;
my $player;
&printNotice("Rewarding team \"$team\" with \"$reward\" skill for action \"$actionid\" ...");
&printNotice("Rewarding team \"$team\" with \"$reward\" skill for action \"$actionid\" ...");
my @userlist;
my @userlist;
foreach $player (values(%g_players)) {
foreach $player (values(%g_players)) {
my $player_team = $player->{team};
my $player_team = $player->{team};
my $player_timestamp = $player->{timestamp};
my $player_timestamp = $player->{timestamp};
if (($g_servers{$s_addr}->{ignore_bots} == 1) && (($player->{is_bot} == 1) || ($player->{userid} <= 0))) {
if (($g_servers{$s_addr}->{ignore_bots} == 1) && (($player->{is_bot} == 1) || ($player->{userid} <= 0))) {
$desc = "(IGNORED) BOT: ";
$desc = "(IGNORED) BOT: ";
} else {
} else {
if ($player_team eq $team) {
if ($player_team eq $team) {
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("Rewarding " . $player->getInfoString() . " with \"$reward\" skill for action \"$actionid\"");
&printNotice("Rewarding " . $player->getInfoString() . " with \"$reward\" skill for action \"$actionid\"");
}
}
&recordEvent(
&recordEvent(
"TeamBonuses", 0,
"TeamBonuses", 0,
$player->{playerid},
$player->{playerid},
$actionid,
$actionid,
$reward
$reward
);
);
$player->increment("skill", $reward, 1);
$player->increment("skill", $reward, 1);
$player->increment("session_skill", $reward, 1);
$player->increment("session_skill", $reward, 1);
$player->updateDB();
$player->updateDB();
}
}
if ($player->{is_bot} == 0 && $player->{userid} > 0 && $player->{display_events} == 1) {
if ($player->{is_bot} == 0 && $player->{userid} > 0 && $player->{display_events} == 1) {
push(@userlist, $player->{userid});
push(@userlist, $player->{userid});
}
}
}
}
}
}
if (($g_servers{$s_addr}->{broadcasting_events} == 1) && ($g_servers{$s_addr}->{broadcasting_player_actions} == 1)) {
if (($g_servers{$s_addr}->{broadcasting_events} == 1) && ($g_servers{$s_addr}->{broadcasting_player_actions} == 1)) {
my $coloraction = $g_servers{$s_addr}->{format_action};
my $coloraction = $g_servers{$s_addr}->{format_action};
my $verb = "got";
my $verb = "got";
if ($reward < 0) {
if ($reward < 0) {
$verb = "lost";
$verb = "lost";
}
}
my $msg = sprintf("%s %s %s points for %s%s", $team, $verb, abs($reward), $coloraction, $actionname);
my $msg = sprintf("%s %s %s points for %s%s", $team, $verb, abs($reward), $coloraction, $actionname);
$g_servers{$s_addr}->messageMany($msg, 0, @userlist);
$g_servers{$s_addr}->messageMany($msg, 0, @userlist);
}
}
}
}
#
#
# int getPlayerId (uniqueId)
# int getPlayerId (uniqueId)
#
#
# Looks up a player's ID number, from their unique (WON) ID. Returns their PID.
# Looks up a player's ID number, from their unique (WON) ID. Returns their PID.
#
#
sub getPlayerId
sub getPlayerId
{
{
my ($uniqueId) = @_;
my ($uniqueId) = @_;
my $query = "
my $query = "
SELECT
SELECT
playerId
playerId
FROM
FROM
hlstats_PlayerUniqueIds
hlstats_PlayerUniqueIds
WHERE
WHERE
uniqueId='" . &::quoteSQL($uniqueId) . "' AND
uniqueId='" . &::quoteSQL($uniqueId) . "' AND
game='" . $g_servers{$s_addr}->{game} . "'
game='" . $g_servers{$s_addr}->{game} . "'
";
";
my $result = &doQuery($query);
my $result = &doQuery($query);
if ($result->rows > 0) {
if ($result->rows > 0) {
my ($playerId) = $result->fetchrow_array;
my ($playerId) = $result->fetchrow_array;
$result->finish;
$result->finish;
return $playerId;
return $playerId;
} else {
} else {
$result->finish;
$result->finish;
return 0;
return 0;
}
}
}
}
#
#
# int updatePlayerProfile (object player, string field, string value)
# int updatePlayerProfile (object player, string field, string value)
#
#
# Updates a player's profile information in the database.
# Updates a player's profile information in the database.
#
#
sub updatePlayerProfile
sub updatePlayerProfile
{
{
my ($player, $field, $value) = @_;
my ($player, $field, $value) = @_;
$rcmd = $g_servers{$s_addr}->{player_command};
$rcmd = $g_servers{$s_addr}->{player_command};
unless ($player) {
unless ($player) {
&printNotice("updatePlayerInfo: Bad player");
&printNotice("updatePlayerInfo: Bad player");
return 0;
return 0;
}
}
$value = "eSQL($value);
$value = "eSQL($value);
if ($value eq "none" || $value eq " ") {
if ($value eq "none" || $value eq " ") {
$value = "";
$value = "";
}
}
my $playerName = &abbreviate($player->{name});
my $playerName = &abbreviate($player->{name});
my $playerId = $player->{playerid};
my $playerId = $player->{playerid};
&execNonQuery("
&execNonQuery("
UPDATE
UPDATE
hlstats_Players
hlstats_Players
SET
SET
$field='$value'
$field='$value'
WHERE
WHERE
playerId=$playerId
playerId=$playerId
");
");
if ($g_servers{$s_addr}->{player_events} == 1) {
if ($g_servers{$s_addr}->{player_events} == 1) {
my $p_userid = $g_servers{$s_addr}->format_userid($player->{userid});
my $p_userid = $g_servers{$s_addr}->format_userid($player->{userid});
my $p_is_bot = $player->{is_bot};
my $p_is_bot = $player->{is_bot};
$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam("SET command successful for '$playerName'.");
$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam("SET command successful for '$playerName'.");
$g_servers{$s_addr}->dorcon($cmd_str);
$g_servers{$s_addr}->dorcon($cmd_str);
}
}
return 1;
return 1;
}
}
#
#
# mixed getClanId (string name)
# mixed getClanId (string name)
#
#
# Looks up a player's clan ID from their name. Compares the player's name to tag
# Looks up a player's clan ID from their name. Compares the player's name to tag
# patterns in hlstats_ClanTags. Patterns look like: [AXXXXX] (matches 1 to 6
# patterns in hlstats_ClanTags. Patterns look like: [AXXXXX] (matches 1 to 6
# letters inside square braces, e.g. [ZOOM]Player) or =\*AAXX\*= (matches
# letters inside square braces, e.g. [ZOOM]Player) or =\*AAXX\*= (matches
# 2 to 4 letters between an equals sign and an asterisk, e.g. =*RAGE*=Player).
# 2 to 4 letters between an equals sign and an asterisk, e.g. =*RAGE*=Player).
#
#
# Special characters in the pattern:
# Special characters in the pattern:
# A matches one character (i.e. a character is required)
# A matches one character (i.e. a character is required)
# X matches zero or one characters (i.e. a character is optional)
# X matches zero or one characters (i.e. a character is optional)
# a matches literal A or a
# a matches literal A or a
# x matches literal X or x
# x matches literal X or x
#
#
# If no clan exists for the tag, it will be created. Returns the clan's ID, or
# If no clan exists for the tag, it will be created. Returns the clan's ID, or
# 0 if the player is not in a clan.
# 0 if the player is not in a clan.
#
#
sub getClanId
sub getClanId
{
{
my ($name) = @_;
my ($name) = @_;
my $clanTag = "";
my $clanTag = "";
my $clanName = "";
my $clanName = "";
my $clanId = 0;
my $clanId = 0;
my $result = &doQuery("
my $result = &doQuery("
SELECT
SELECT
pattern,
pattern,
position,
position,
LENGTH(pattern) AS pattern_length
LENGTH(pattern) AS pattern_length
FROM
FROM
hlstats_ClanTags
hlstats_ClanTags
ORDER BY
ORDER BY
pattern_length DESC,
pattern_length DESC,
id
id
");
");
while ( my($pattern, $position) = $result->fetchrow_array) {
while ( my($pattern, $position) = $result->fetchrow_array) {
my $regpattern = quotemeta($pattern);
my $regpattern = quotemeta($pattern);
$regpattern =~ s/([A-Za-z0-9]+[A-Za-z0-9_-]*)/\($1\)/; # to find clan name from tag
$regpattern =~ s/([A-Za-z0-9]+[A-Za-z0-9_-]*)/\($1\)/; # to find clan name from tag
$regpattern =~ s/A/./g;
$regpattern =~ s/A/./g;
$regpattern =~ s/X/.?/g;
$regpattern =~ s/X/.?/g;
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("regpattern=$regpattern");
&printNotice("regpattern=$regpattern");
}
}
if ((($position eq "START" || $position eq "EITHER") && $name =~ /^($regpattern).+/i) ||
if ((($position eq "START" || $position eq "EITHER") && $name =~ /^($regpattern).+/i) ||
(($position eq "END" || $position eq "EITHER") && $name =~ /.+($regpattern)$/i)) {
(($position eq "END" || $position eq "EITHER") && $name =~ /.+($regpattern)$/i)) {
if ($g_debug > 2) {
if ($g_debug > 2) {
&printNotice("pattern \"$regpattern\" matches \"$name\"! 1=\"$1\" 2=\"$2\"");
&printNotice("pattern \"$regpattern\" matches \"$name\"! 1=\"$1\" 2=\"$2\"");
}
}
$clanTag = $1;
$clanTag = $1;
$clanName = $2;
$clanName = $2;
last;
last;
}
}
}
}
unless ($clanTag) {
unless ($clanTag) {
return 0;
return 0;
}
}
my $query = "
my $query = "
SELECT
SELECT
clanId
clanId
FROM
FROM
hlstats_Clans
hlstats_Clans
WHERE
WHERE
tag='" . "eSQL($clanTag) . "' AND
tag='" . "eSQL($clanTag) . "' AND
game='$g_servers{$s_addr}->{game}'
game='$g_servers{$s_addr}->{game}'
";
";
$result = &doQuery($query);
$result = &doQuery($query);
if ($result->rows) {
if ($result->rows) {
($clanId) = $result->fetchrow_array;
($clanId) = $result->fetchrow_array;
$result->finish;
$result->finish;
return $clanId;
return $clanId;
} else {
} else {
# The clan doesn't exist yet, so we create it.
# The clan doesn't exist yet, so we create it.
$query = "
$query = "
REPLACE INTO
REPLACE INTO
hlstats_Clans
hlstats_Clans
(
(
tag,
tag,
name,
name,
game
game
)
)
VALUES
VALUES
(
(
'" . "eSQL($clanTag) . "',
'" . "eSQL($clanTag) . "',
'" . "eSQL($clanName) . "',
'" . "eSQL($clanName) . "',
'"."eSQL($g_servers{$s_addr}->{game})."'
'"."eSQL($g_servers{$s_addr}->{game})."'
)
)
";
";
&execNonQuery($query);
&execNonQuery($query);
$clanId = $db_conn->{'mysql_insertid'};
$clanId = $db_conn->{'mysql_insertid'};
&printNotice("Created clan \"$clanName\" <C:$clanId> with tag "
&printNotice("Created clan \"$clanName\" <C:$clanId> with tag "
. "\"$clanTag\" for player \"$name\"");
. "\"$clanTag\" for player \"$name\"");
return $clanId;
return $clanId;
}
}
}
}
#
#
# object getServer (string address, int port)
# object getServer (string address, int port)
#
#
# Looks up a server's ID number in the Servers table, by searching for a
# Looks up a server's ID number in the Servers table, by searching for a
# matching IP address and port. NOTE you must specify IP addresses in the
# matching IP address and port. NOTE you must specify IP addresses in the
# Servers table, NOT hostnames.
# Servers table, NOT hostnames.
#
#
# Returns a new "Server object".
# Returns a new "Server object".
#
#
sub getServer
sub getServer
{
{
my ($address, $port) = @_;
my ($address, $port) = @_;
my $query = "
my $query = "
SELECT
SELECT
a.serverId,
a.serverId,
a.game,
a.game,
a.name,
a.name,
a.rcon_password,
a.rcon_password,
a.publicaddress,
a.publicaddress,
IFNULL(b.`value`,3) AS game_engine,
IFNULL(b.`value`,3) AS game_engine,
IFNULL(c.`realgame`, 'hl2mp') AS realgame,
IFNULL(c.`realgame`, 'hl2mp') AS realgame,
IFNULL(a.max_players, 0) AS maxplayers
IFNULL(a.max_players, 0) AS maxplayers
FROM
FROM
hlstats_Servers a LEFT JOIN hlstats_Servers_Config b on a.serverId = b.serverId AND b.`parameter` = 'GameEngine' LEFT JOIN `hlstats_Games` c ON a.game = c.code
hlstats_Servers a LEFT JOIN hlstats_Servers_Config b on a.serverId = b.serverId AND b.`parameter` = 'GameEngine' LEFT JOIN `hlstats_Games` c ON a.game = c.code
WHERE
WHERE
address=? AND
address=? AND
port=? LIMIT 1
port=? LIMIT 1
";
";
my @vals = (
my @vals = (
$address,
$address,
$port
$port
);
);
my $result = &execCached("get_server_information", $query, @vals);
my $result = &execCached("get_server_information", $query, @vals);
if ($result->rows) {
if ($result->rows) {
my ($serverId, $game, $name, $rcon_pass, $publicaddress, $gameengine, $realgame, $maxplayers) = $result->fetchrow_array;
my ($serverId, $game, $name, $rcon_pass, $publicaddress, $gameengine, $realgame, $maxplayers) = $result->fetchrow_array;
$result->finish;
$result->finish;
if (!defined($g_games{$game})) {
if (!defined($g_games{$game})) {
$g_games{$game} = new HLstats_Game($game);
$g_games{$game} = new HLstats_Game($game);
}
}
# l4d code should be reused for l4d2
# l4d code should be reused for l4d2
# trying first using l4d as "realgame" code for l4d2 in db. if default server config settings won't work, will leave as own "realgame" code in db but uncomment line.
# trying first using l4d as "realgame" code for l4d2 in db. if default server config settings won't work, will leave as own "realgame" code in db but uncomment line.
#$realgame = "l4d" if $realgame eq "l4d2";
#$realgame = "l4d" if $realgame eq "l4d2";
return new HLstats_Server($serverId, $address, $port, $name, $rcon_pass, $game, $publicaddress, $gameengine, $realgame, $maxplayers);
return new HLstats_Server($serverId, $address, $port, $name, $rcon_pass, $game, $publicaddress, $gameengine, $realgame, $maxplayers);
} else {
} else {
$result->finish;
$result->finish;
return 0;
return 0;
}
}
}
}
#
#
#
#
#
#
#
#
#
#
sub queryServer
sub queryServer
{
{
my ($iaddr, $iport, @query) = @_;
my ($iaddr, $iport, @query) = @_;
my $game = "";
my $game = "";
my $timeout=2;
my $timeout=2;
my $message = IO::Socket::INET->new(Proto=>"udp",Timeout=>$timeout,PeerPort=>$iport,PeerAddr=>$iaddr) or die "Can't make UDP socket: $@";
my $message = IO::Socket::INET->new(Proto=>"udp",Timeout=>$timeout,PeerPort=>$iport,PeerAddr=>$iaddr) or die "Can't make UDP socket: $@";
$message->send("\xFF\xFF\xFF\xFFTSource Engine Query\x00");
$message->send("\xFF\xFF\xFF\xFFTSource Engine Query\x00");
my ($datagram,$flags);
my ($datagram,$flags);
my $end = time + $timeout;
my $end = time + $timeout;
my $rin = '';
my $rin = '';
vec($rin, fileno($message), 1) = 1;
vec($rin, fileno($message), 1) = 1;
my %hash = ();
my %hash = ();
while (1) {
while (1) {
my $timeleft = $end - time;
my $timeleft = $end - time;
last if ($timeleft <= 0);
last if ($timeleft <= 0);
my ($nfound, $t) = select(my $rout = $rin, undef, undef, $timeleft);
my ($nfound, $t) = select(my $rout = $rin, undef, undef, $timeleft);
last if ($nfound == 0); # either timeout or end of file
last if ($nfound == 0); # either timeout or end of file
$message->recv($datagram,1024,$flags);
$message->recv($datagram,1024,$flags);
@hash{qw/key type netver hostname mapname gamedir gamename id numplayers maxplayers numbots dedicated os passreq secure gamever edf port/} = unpack("LCCZ*Z*Z*Z*vCCCCCCCZ*Cv",$datagram);
@hash{qw/key type netver hostname mapname gamedir gamename id numplayers maxplayers numbots dedicated os passreq secure gamever edf port/} = unpack("LCCZ*Z*Z*Z*vCCCCCCCZ*Cv",$datagram);
}
}
return @hash{@query};
return @hash{@query};
}
}
sub getServerMod
sub getServerMod
{
{
my ($address, $port) = @_;
my ($address, $port) = @_;
my ($playgame);
my ($playgame);
&printEvent ("DETECT", "Querying $address".":$port for gametype");
&printEvent ("DETECT", "Querying $address".":$port for gametype");
my @query = (
my @query = (
'gamename',
'gamename',
'gamedir',
'gamedir',
'hostname',
'hostname',
'numplayers',
'numplayers',
'maxplayers',
'maxplayers',
'mapname'
'mapname'
);
);
my ($gamename, $gamedir, $hostname, $numplayers, $maxplayers, $mapname) = &queryServer($address, $port, @query);
my ($gamename, $gamedir, $hostname, $numplayers, $maxplayers, $mapname) = &queryServer($address, $port, @query);
if ($gamename =~ /^Counter-Strike$/i) {
if ($gamename =~ /^Counter-Strike$/i) {
$playgame = "cstrike";
$playgame = "cstrike";
} elsif ($gamename =~ /^Counter-Strike/i) {
} elsif ($gamename =~ /^Counter-Strike/i) {
$playgame = "css";
$playgame = "css";
} elsif ($gamename =~ /^Team Fortress C/i) {
} elsif ($gamename =~ /^Team Fortress C/i) {
$playgame = "tfc";
$playgame = "tfc";
} elsif ($gamename =~ /^Team Fortress/i) {
} elsif ($gamename =~ /^Team Fortress/i) {
$playgame = "tf";
$playgame = "tf";
} elsif ($gamename =~ /^Day of Defeat$/i) {
} elsif ($gamename =~ /^Day of Defeat$/i) {
$playgame = "dod";
$playgame = "dod";
} elsif ($gamename =~ /^Day of Defeat/i) {
} elsif ($gamename =~ /^Day of Defeat/i) {
$playgame = "dods";
$playgame = "dods";
} elsif ($gamename =~ /^Insurgency/i) {
} elsif ($gamename =~ /^Insurgency/i) {
$playgame = "insmod";
$playgame = "insmod";
} elsif ($gamename =~ /^Neotokyo/i) {
} elsif ($gamename =~ /^Neotokyo/i) {
$playgame = "nts";
$playgame = "nts";
} elsif ($gamename =~ /^Fortress Forever/i) {
} elsif ($gamename =~ /^Fortress Forever/i) {
$playgame = "ff";
$playgame = "ff";
} elsif ($gamename =~ /^Age of Chivalry/i) {
} elsif ($gamename =~ /^Age of Chivalry/i) {
$playgame = "aoc";
$playgame = "aoc";
} elsif ($gamename =~ /^Dystopia/i) {
} elsif ($gamename =~ /^Dystopia/i) {
$playgame = "dystopia";
$playgame = "dystopia";
} elsif ($gamename =~ /^Stargate/i) {
} elsif ($gamename =~ /^Stargate/i) {
$playgame = "sgtls";
$playgame = "sgtls";
} elsif ($gamename =~ /^Battle Grounds/i) {
} elsif ($gamename =~ /^Battle Grounds/i) {
$playgame = "bg2";
$playgame = "bg2";
} elsif ($gamename =~ /^Hidden/i) {
} elsif ($gamename =~ /^Hidden/i) {
$playgame = "hidden";
$playgame = "hidden";
} elsif ($gamename =~ /^L4D /i) {
} elsif ($gamename =~ /^L4D /i) {
$playgame = "l4d";
$playgame = "l4d";
} elsif ($gamename =~ /^Left 4 Dead 2/i) {
} elsif ($gamename =~ /^Left 4 Dead 2/i) {
$playgame = "l4d2";
$playgame = "l4d2";
} elsif ($gamename =~ /^ZPS /i) {
} elsif ($gamename =~ /^ZPS /i) {
$playgame = "zps";
$playgame = "zps";
} elsif ($gamename =~ /^NS /i) {
} elsif ($gamename =~ /^NS /i) {
$playgame = "ns";
$playgame = "ns";
} elsif ($gamename =~ /^pvkii/i) {
} elsif ($gamename =~ /^pvkii/i) {
$playgame = "pvkii";
$playgame = "pvkii";
} elsif ($gamename =~ /^CSPromod/i) {
} elsif ($gamename =~ /^CSPromod/i) {
$playgame = "csp";
$playgame = "csp";
} elsif ($gamename eq "Half-Life") {
} elsif ($gamename eq "Half-Life") {
$playgame = "valve";
$playgame = "valve";
} elsif ($gamename eq "Nuclear Dawn") {
} elsif ($gamename eq "Nuclear Dawn") {
$playgame = "nucleardawn";
$playgame = "nucleardawn";
# We didn't found our mod, trying secondary way. This is required for some games such as FOF and GES and is a fallback for others
# We didn't found our mod, trying secondary way. This is required for some games such as FOF and GES and is a fallback for others
} elsif ($gamedir =~ /^ges/i) {
} elsif ($gamedir =~ /^ges/i) {
$playgame = "ges";
$playgame = "ges";
} elsif ($gamedir =~ /^fistful_of_frags/i || $gamedir =~ /^fof/i) {
} elsif ($gamedir =~ /^fistful_of_frags/i || $gamedir =~ /^fof/i) {
$playgame = "fof";
$playgame = "fof";
} elsif ($gamedir =~ /^hl2mp/i) {
} elsif ($gamedir =~ /^hl2mp/i) {
$playgame = "hl2mp";
$playgame = "hl2mp";
} elsif ($gamedir =~ /^tfc/i) {
} elsif ($gamedir =~ /^tfc/i) {
$playgame = "tfc";
$playgame = "tfc";
} elsif ($gamedir =~ /^tf/i) {
} elsif ($gamedir =~ /^tf/i) {