Reupload after bitbucket wipe

This commit is contained in:
Chris Lynch
2013-12-25 18:43:29 -05:00
commit 965453909e
5942 changed files with 99045 additions and 0 deletions

384
scripts/BASTARDrcon.pm Normal file
View File

@ -0,0 +1,384 @@
package BASTARDrcon;
#
# BASTARDrcon Perl Module - execute commands on a remote Half-Life 1 server using Rcon.
# A merge of the KKrcon library into HLstatsX
# Copyright (C) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# KKrcon Perl Module - execute commands on a remote Half-Life server using Rcon.
# http://kkrcon.sourceforge.net
#
# TRcon Perl Module - execute commands on a remote Half-Life2 server using remote console.
# http://www.hlstatsx.com
#
# Copyright (C) 2000, 2001 Rod May
# Enhanced in 2005 by Tobi (Tobi@gameme.de)
#
# 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.
#
use strict;
use sigtrap;
use Socket;
use Sys::Hostname;
use bytes;
##
## Main
##
#
# Constructor
#
sub new
{
my ($class_name, $server_object) = @_;
my ($self) = {};
bless($self, $class_name);
# Initialise properties
$self->{server_object} = $server_object;
$self->{rcon_password} = $server_object->{rcon} or die("BASTARDrcon: a Password is required\n");
$self->{server_host} = $server_object->{address};
$self->{server_port} = int($server_object->{port}) or die("BASTARDrcon: invalid Port \"" . $server_object->{port} . "\"\n");
$self->{socket} = undef;
$self->{error} = "";
# Set up socket parameters
$self->{_ipaddr} = gethostbyname($self->{server_host}) or die("BASTARDrcon: could not resolve Host \"" . $self->{server_host} . "\"\n");
return $self;
}
#
# Execute an Rcon command and return the response
#
sub execute
{
my ($self, $command) = @_;
my $msg;
my $ans;
# version x.1.0.6+ HL1 server
$msg = "\xFF\xFF\xFF\xFFchallenge rcon\n\0";
$ans = $self->_sendrecv($msg);
if ($ans =~ /challenge +rcon +(\d+)/)
{
$msg = "\xFF\xFF\xFF\xFFrcon $1 \"" . $self->{"rcon_password"} . "\" $command\0";
$ans = $self->_sendrecv($msg);
}
elsif (!$self->error())
{
$ans = "";
$self->{"error"} = "No challenge response";
}
if ($ans =~ /bad rcon_password/i)
{
$self->{"error"} = "Bad Password";
}
return $ans;
}
sub _sendrecv
{
my ($self, $msg) = @_;
my $host = $self->{"server_host"};
my $port = $self->{"server_port"};
my $ipaddr = $self->{"_ipaddr"};
my $proto = $self->{"_proto"};
# Open socket
socket($self->{"socket"}, PF_INET, SOCK_DGRAM, $proto) or die("BASTARDrcon(141): socket: $!\n");
my $hispaddr = sockaddr_in($port, $ipaddr);
die("BASTARDrcon: send $ipaddr:$port : $!") unless(defined(send($self->{"socket"}, $msg, 0, $hispaddr)));
my $rin = "";
vec($rin, fileno($self->{"socket"}), 1) = 1;
my $ans = "TIMEOUT";
if (select($rin, undef, undef, 0.5))
{
$ans = "";
$hispaddr = recv($self->{"socket"}, $ans, 8192, 0);
$ans =~ s/\x00+$//; # trailing crap
$ans =~ s/^\xFF\xFF\xFF\xFFl//; # HL response
$ans =~ s/^\xFF\xFF\xFF\xFFn//; # QW response
$ans =~ s/^\xFF\xFF\xFF\xFF//; # Q2/Q3 response
$ans =~ s/^\xFE\xFF\xFF\xFF.....//; # old HL bug/feature
}
# Close socket
close($self->{"socket"});
if ($ans eq "TIMEOUT")
{
$ans = "";
$self->{"error"} = "Rcon timeout";
}
return $ans;
}
#
# Send a package
#
sub send_rcon
{
my ($self, $id, $command, $string1, $string2) = @_;
my $tmp = pack("VVZ*Z*",$id,$command,$string1,$string2);
my $size = length($tmp);
if($size > 4096)
{
$self->{error} = "Command too long to send!";
return 1;
}
$tmp = pack("V", $size) .$tmp;
unless(defined(send($self->{"socket"},$tmp,0)))
{
die("BASTARDrcon: send $!");
}
return 0;
}
#
# Recieve a package
#
sub recieve_rcon
{
my $self = shift;
my ($size, $id, $command, $msg);
my $rin = "";
my $tmp = "";
vec($rin, fileno($self->{"socket"}), 1) = 1;
if(select($rin, undef, undef, 0.5))
{
while(length($size) < 4)
{
$tmp = "";
recv($self->{"socket"}, $tmp, (4-length($size)), 0);
$size .= $tmp;
}
$size = unpack("V", $size);
if($size < 10 || $size > 8192)
{
close($self->{"socket"});
$self->{error} = "illegal size $size ";
return (-1, -1, -1);
}
while(length($id)<4)
{
$tmp = "";
recv($self->{"socket"}, $tmp, (4-length($id)), 0);
$id .= $tmp;
}
$id = unpack("V", $id);
$size = $size - 4;
while(length($command)<4)
{
$tmp ="";
recv($self->{"socket"}, $tmp, (4-length($command)),0);
$command.=$tmp;
}
$command = unpack("V", $command);
$size = $size - 4;
my $msg = "";
while($size >= 1)
{
$tmp = "";
recv($self->{"socket"}, $tmp, $size, 0);
$size -= length($tmp);
$msg .= $tmp;
}
my ($string1,$string2) = unpack("Z*Z*",$msg);
$msg = $string1.$string2;
return ($id, $command, $msg);
}
else
{
return (-1, -1, -1);
}
}
#
# Get error message
#
sub error
{
my ($self) = @_;
return $self->{"error"};
}
#
# Parse "status" command output into player information
#
sub getPlayers
{
my ($self) = @_;
my $status = $self->execute("status");
my @lines = split(/[\r\n]+/, $status);
my %players;
# HL1
# name userid uniqueid frag time ping loss adr
# 1 "psychonic" 1 STEAM_0:1:4153990 0 00:33 13 0 192.168.5.115:27005
foreach my $line (@lines)
{
if ($line =~ /^\#\s*\d+\s+
"(.+)"\s+ # name
(\d+)\s+ # userid
([^\s]+)\s+\d+\s+ # uniqueid
([\d:]+)\s+ # time
(\d+)\s+ # ping
(\d+)\s+ # loss
([^:]+): # addr
(\S+) # port
$/x)
{
my $name = $1;
my $userid = $2;
my $uniqueid = $3;
my $time = $4;
my $ping = $5;
my $loss = $6;
my $state = "";
my $address = $7;
my $port = $8;
$uniqueid =~ s/^STEAM_[0-9]+?\://i;
# &::printEvent("DEBUG", "USERID: '$userid', NAME: '$name', UNIQUEID: '$uniqueid', TIME: '$time', PING: '$ping', LOSS: '$loss', ADDRESS:'$address', CLI_PORT: '$port'", 1);
if ($::g_mode eq "NameTrack") {
$players{$name} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
} elsif ($::g_mode eq "LAN") {
$players{$address} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
} else {
$players{$uniqueid} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
}
}
}
return %players;
}
sub getServerData
{
my ($self) = @_;
my $status = $self->execute("status");
my @lines = split(/[\r\n]+/, $status);
my $servhostname = "";
my $map = "";
my $max_players = 0;
foreach my $line (@lines)
{
if ($line =~ /^\s*hostname\s*:\s*([\S].*)$/x)
{
$servhostname = $1;
}
elsif ($line =~ /^\s*map\s*:\s*([\S]+).*$/x)
{
$map = $1;
}
elsif ($line =~ /^\s*players\s*:\s*\d+.+\((\d+)\smax.*$/)
{
$max_players = $1;
}
}
return ($servhostname, $map, $max_players, 0);
}
sub getVisiblePlayers
{
my ($self) = @_;
my $status = $self->execute("sv_visiblemaxplayers");
my @lines = split(/[\r\n]+/, $status);
my $max_players = -1;
foreach my $line (@lines)
{
# "sv_visiblemaxplayers" = "-1"
# - Overrides the max players reported to prospective clients
if ($line =~ /^\s*"sv_visiblemaxplayers"\s*=\s*"([-0-9]+)".*$/x)
{
$max_players = $1;
}
}
return ($max_players);
}
#
# Get information about a player by userID
#
sub getPlayer
{
my ($self, $uniqueid) = @_;
my %players = $self->getPlayers();
if (defined($players{$uniqueid}))
{
return $players{$uniqueid};
}
else
{
$self->{"error"} = "No such player # $uniqueid";
return 0;
}
}
1;
# end

View File

@ -0,0 +1,247 @@
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
package ConfigReaderSimple;
#
# Simple interface to a configuration file
#
# Originally developed by Ben Oberin.
# Modified for HLstats by Simon Garner.
# Modified for HLstatsX by Tobias Oetzel.
#
# ObLegalStuff:
# Copyright (c) 2000 Bek Oberin. All rights reserved. This program is
# free software; you can redistribute it and/or modify it under the
# same terms as Perl itself.
#
use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = "1.0";
my $DEBUG = 0;
=head1 NAME
ConfigReader::Simple - Simple configuration file parser
=head1 SYNOPSIS
use ConfigReader::Simple;
$config = ConfigReader::Simple->new("configrc", [qw(Foo Bar Baz Quux)]);
$config->parse();
$config->get("Foo");
=head1 DESCRIPTION
C<ConfigReader::Simple> reads and parses simple configuration files. It's
designed to be smaller and simpler than the C<ConfigReader> module
and is more suited to simple configuration files.
=cut
###################################################################
# Functions under here are member functions #
###################################################################
=head1 CONSTRUCTOR
=item new ( FILENAME, DIRECTIVES )
This is the constructor for a new ConfigReader::Simple object.
C<FILENAME> tells the instance where to look for the configuration
file.
C<DIRECTIVES> is an optional argument and is a reference to an array.
Each member of the array should contain one valid directive. A directive
is the name of a key that must occur in the configuration file. If it
is not found, the module will die. The directive list may contain all
the keys in the configuration file, a sub set of keys or no keys at all.
=cut
sub new {
my $prototype = shift;
my $filename = shift;
my $keyref = shift;
my $class = ref($prototype) || $prototype;
my $self = {};
$self->{"filename"} = $filename;
$self->{"validkeys"} = $keyref;
bless($self, $class);
return $self;
}
#
# destructor
#
sub DESTROY {
my $self = shift;
return 1;
}
=pod
=item parse ()
This does the actual work. No parameters needed.
=cut
sub parse {
my $self = shift;
open(CONFIG, $self->{"filename"}) ||
die "Config: Can't open config file " . $self->{"filename"} . ": $!";
my @array_buffer;
my $ext_option = 0;
my $parsed_line = 0;
while (<CONFIG>) {
chomp;
next if /^\s*$/; # blank
next if /^\s*#/; # comment
next if /^\s*.*\[[0-9]+\]\s*=\s*\(/; # old style server config start
next if /^\s*.*\s*=>\s*\.*".*\",/; # old style server config option
$parsed_line = 0;
my $input_text = $_;
if (($ext_option == 0) && ($parsed_line == 0)) {
my ($key, $value) = &parse_line($input_text);
warn "Key: '$key' Value: '$value'\n" if $DEBUG;
$self->{"config_data"}{$key} = $value;
}
}
close(CONFIG);
return 1;
}
=pod
=item get ( DIRECTIVE )
Returns the parsed value for that directive.
=cut
sub get {
my $self = shift;
my $key = shift;
unless (ref $self->{"config_data"}{$key}) {
return $self->{"config_data"}{$key};
} else {
return %{$self->{"config_data"}{$key}};
}
}
# Internal methods
sub parse_line {
my $text = shift;
my ($key, $value);
if ($text =~ /^\s*(\w+)\s+(['"]?)(.*?)\2\s*$/) {
$key = $1;
$value = $3;
} else {
die "Config: Can't parse line: $text\n";
}
return ($key, $value);
}
=pod
=head1 LIMITATIONS/BUGS
Directives are case-sensitive.
If a directive is repeated, the first instance will silently be
ignored.
Always die()s on errors instead of reporting them.
C<get()> doesn't warn if used before C<parse()>.
C<get()> doesn't warn if you try to acces the value of an
unknown directive not know (ie: one that wasn't passed via C<new()>).
All these will be addressed in future releases.
=head1 CREDITS
Kim Ryan <kimaryan@ozemail.com.au> adapted the module to make declaring
keys optional. Thanks Kim.
=head1 AUTHORS
Bek Oberin <gossamer@tertius.net.au>
=head1 COPYRIGHT
Copyright (c) 2000 Bek Oberin. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
#
# End code.
#
1;

View File

@ -0,0 +1,86 @@
#!/bin/sh
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# Configure the variables below
# Set this value to 1 if you are running Gentoo linux, or any other linux distro where the "cal" command outputs not Sunday as the first day in every row!
LINUX_OTHER="0"
# Login information for your MySQL server
DBHOST="localhost"
DBNAME=""
DBUSER=""
DBPASS=""
#
# Nothing to change below here.
#
# database is updated every first tuesday of any month, so download it with that specific date and import it
TODAY_MONTH=$( date +%m )
TODAY_YEAR=$( date +%Y )
if [ $LINUX_OTHER == "1" ]
then CAL_COMMAND="cal -s"
else CAL_COMMAND="cal"
fi
FIRST_TUESDAY_MONTH=$( $CAL_COMMAND $TODAY_MONTH $TODAY_YEAR |
awk '
NR == 1 { next }
NR == 2 { next }
NF <= 4 { next }
NF == 5 { print $1 ; exit }
NF == 6 { print $2 ; exit }
NF == 7 { print $3 ; exit }
' )
DATE=""$TODAY_YEAR""$TODAY_MONTH"0"$FIRST_TUESDAY_MONTH""
DIR="GeoLiteCity_$DATE"
FILE="GeoLiteCity_$DATE.zip"
ls *.csv &>/dev/null && rm *.csv
[ -f $FILE ] || wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/$FILE || exit 1
unzip -o $FILE || exit 1
mv $DIR/GeoLiteCity-Blocks.csv geoLiteCity_Blocks.csv
mv $DIR/GeoLiteCity-Location.csv geoLiteCity_Location.csv.temp
iconv -f ISO-8859-1 -t UTF-8 geoLiteCity_Location.csv.temp > geoLiteCity_Location.csv
mysqlimport -C -d --fields-terminated-by=, --fields-enclosed-by=\" --ignore-lines=2 --default-character-set=utf8 -L -i -h $DBHOST -u $DBUSER --password=$DBPASS $DBNAME geoLiteCity_Blocks.csv
mysqlimport -C -d --fields-terminated-by=, --fields-enclosed-by=\" --ignore-lines=2 --default-character-set=utf8 -L -i -h $DBHOST -u $DBUSER --password=$DBPASS $DBNAME geoLiteCity_Location.csv
# Cleanup
ls *.csv &>/dev/null && rm *.csv
ls *.csv.temp &>/dev/null && rm *.csv.temp
rm $FILE
rmdir $DIR

View File

@ -0,0 +1,17 @@
Included in this folder are two scripts to import data from the MaxMind (http://www.maxmind.com) from the GeoLiteCity database into your HLX db.
For Linux:
Edit the GeoLite_Import.sh file to insert your database settings in the top section and then execute.
For Windows:
Download the HLstatsX CE GeoLiteCity Importer from http://code.google.com/p/hlstatsxcommunity
--------------------------------------------------------------
Alternative method by *XYZ*SaYnt:
--------------------------------------------------------------
* For Windows or Linux.
* Requires python.
* Generates INSERTs in case LOAD DATA command is disabled
Edit the geoip.py file to insert your database settings in the top section and then execute.

View File

@ -0,0 +1,196 @@
#!/usr/bin/env python
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
# 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.
# For support and installation notes visit http://www.hlxcommunity.com
import os,sys
# version 1.0 alpha contributed to hlstatsx community by *XYZ*SaYnt
DBHOST="localhost"
DBNAME="your_hlstats_db"
DBUSER="your_sql_username"
DBPASS="your_sql_password"
def system(cmd):
"""
executes a system call and returns the text as a string. Returns only the first line of output.
"""
print("EXECUTING: %s"%cmd)
f = os.popen(cmd)
output = f.readlines()
f.close()
if len(output) > 0:
return output[0].replace("\n","")
else:
return ""
def fetch_geodata():
"""
Obtains the geoLiteCity raw data, resulting in geoLiteCity_Location.csv and geoLiteCity_Blocks.csv
"""
# database is updated on 1st every month, so download the file from the 1st of current month
DAT = system("date +%Y%m01")
FIL = "GeoLiteCity_%s"%DAT
FILE = FIL + ".zip"
system("rm *.csv > /dev/null")
if not os.path.exists(FILE):
system("wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/" + FILE)
system("unzip -o " + FILE)
system("mv %s/GeoLiteCity-Blocks.csv geoLiteCity_Blocks.csv"%FIL)
system("mv %s/GeoLiteCity-Location.csv geoLiteCity_Location.csv.temp"%FIL)
system("rmdir " + FIL)
system("iconv -f ISO-8859-1 -t UTF-8 geoLiteCity_Location.csv.temp > geoLiteCity_Location.csv")
return
def dump_sql(fname):
"""
Dump the new sql data into our database
"""
system("mysql -u %s -p%s -h %s %s < %s"%(DBUSER,DBPASS,DBHOST,DBNAME,fname))
def write_sql(fname):
"""
Write a file of sql commands so that our data can be imported into our database.
"""
try:
fout = open(fname,"w")
except:
print("ERROR: unable to open "+fname)
return 0
fout.write("""
DROP TABLE IF EXISTS `geoLiteCity_Blocks`;
DROP TABLE IF EXISTS `geolitecity_blocks`;
DROP TABLE IF EXISTS `geolitecity_location`;
DROP TABLE IF EXISTS `geoLiteCity_Location`;
CREATE TABLE `geoLiteCity_Blocks`
(`startIpNum` bigint(11) unsigned NOT NULL default '0',
`endIpNum` bigint(11) unsigned NOT NULL default '0',
`locId` bigint(11) unsigned NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `geoLiteCity_Location` (
`locId` bigint(11) unsigned NOT NULL default '0',
`country` varchar(2) NOT NULL,
`region` varchar(50) default NULL,
`city` varchar(50) default NULL,
`postalCode` varchar(10) default NULL,
`latitude` decimal(14,4) default NULL,
`longitude` decimal(14,4) default NULL,
PRIMARY KEY (`locId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
""")
# read in the raw data
f = open("geoLiteCity_Blocks.csv")
raw = f.readlines()
f.close()
del raw[0:2]
# chunk up the raw data
chunksize = 1000
gblocks = []
chunks = len(raw)/chunksize + 1
for i in xrange(0,chunks): gblocks.append(raw[i*chunksize:(i+1)*chunksize])
print("SQL: %d data items, %d chunks"%(len(raw),chunks))
del raw
for chunk in gblocks:
if chunk:
s = "insert into `geoLiteCity_Blocks`(`startIpNum`,`endIpNum`,`locId`) values"
for l in chunk:
vals = l.replace('"',"").replace('\n',"").split(',')
s += "(%s,%s,%s),"%(vals[0],vals[1],vals[2])
s = s[0:-1] # chop the last comma
fout.write(s + ";\n");
del gblocks
f = open("geoLiteCity_Location.csv")
raw = f.readlines()
f.close()
del raw[0:2]
# chunk up the raw data
gblocks = []
chunks = len(raw)/chunksize + 1
for i in xrange(0,chunks): gblocks.append(raw[i*chunksize:(i+1)*chunksize])
print("SQL: %d data items, %d chunks"%(len(raw),chunks))
del raw
for chunk in gblocks:
if chunk:
s = "insert into `geoLiteCity_Location`(`locId`,`country`,`region`,`city`,`postalCode`,`latitude`,`longitude`) values"
for l in chunk:
vals = l.replace('"',"").replace('\n',"").split(',')
for i,v in enumerate(vals): vals[i] = v.replace("'","\\'")
s += "(%s,'%s','%s','%s','%s','%s','%s'),"%(vals[0],vals[1],vals[2],vals[3],vals[4],vals[5],vals[6])
s = s[0:-1] # chop the last comma
fout.write(s + ";\n");
del gblocks
return 1
def main():
sqlname = "geodata.sql"
print("DOWNLOADING GEO DATA....")
fetch_geodata()
print("WRITING DATABASE FILE....")
if write_sql(sqlname):
print("IMPORTING DATABASE FILE....")
dump_sql(sqlname)
else:
print("Fatal error; unable to finish.")
# clean up.
system("rm "+sqlname)
print("DONE.")
main()

View File

@ -0,0 +1,54 @@
#!/bin/bash
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# *** You should not need to configure anything in this script. ***
# URL is the location to download the GeoLiteCity.dat.gz file from.
URL=http://geolite.maxmind.com/download/geoip/database/
# File is the file to download from the server above, as well as what to store it as locally.
FILE=GeoLiteCity.dat.gz
# ***** NOTHING TO CONFIGURE BELOW HERE *****
# Change to directory where installer is
cd `dirname $0`
echo Downloading a new copy of GeoLiteCity, if needed.
wget -N -q $URL$FILE
echo Uncompressing database
gzip -dc < $FILE > $(basename $FILE .gz)
chmod 777 *.dat
echo Done

View File

@ -0,0 +1,49 @@
<?php
/*
HLstatsX Community Edition - Real-time player and clan rankings and statistics
Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
http://www.hlxcommunity.com
HLstatsX Community Edition is a continuation of
ELstatsNEO - Real-time player and clan rankings and statistics
Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
http://ovrsized.neo-soft.org/
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
http://www.hlstatsx.com/
Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
HLstatsX is an enhanced version of HLstats made by Simon Garner
HLstats - Real-time player and clan rankings and statistics for Half-Life
http://sourceforge.net/projects/hlstats/
Copyright (C) 2001 Simon Garner
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.
For support and installation notes visit http://www.hlxcommunity.com
*/
$ip = "62.77.230.10";
$ip = explode(".",$ip);
$number = ($ip[0]*16777216) + ($ip[1]*65536) + ($ip[2]*256) + $ip[3];
echo $number;
// example SQL to determine location
// SELECT geoLiteCity_Location.* FROM geoLiteCity_Blocks INNER JOIN geoLiteCity_Location ON (geoLiteCity_Blocks.locId=geoLiteCity_Location.locId) WHERE startIpNum<=$number AND endIpNum>=$number;
?>

31
scripts/HLStatsFTP/README Normal file
View File

@ -0,0 +1,31 @@
hlstats-ftp.pl README
Utility written by Woody.
This utility can be used to grab log files from a remote game server through FTP and then use the HLStatsX Daemon to enter
the data into the database. You must have perl installed to use this utility.
The script "remembers" the modification time (mtime) of the last log file that has been processed, and when run again,
only processes files with a later mtime.
*** NOTE ***
To use this utility you must copy it into the same folder your hlstats.pl (the daemon) is in.
You probably want to configure this as a cronjob as well.
Usage:
hlstats-ftp.pl --help
hlstats-ftp.pl --version
hlstats-ftp.pl --gs-ip=GSIP --gs-port=GSPORT [--ftp-ip=FTPIP] --ftp-usr=FTPUSR --ftp-pwd=FTPPWD --ftp-dir=FTPDIR [--quiet]
Options:
--help display this help and exit
--version output version information and exit
--gs-ip=IP game server IP address
--gs-port=PORT game server port
--ftp-ip=IP ftp log server IP address, if different from
game server IP address (--gs-ip)
--ftp-usr=USERNAME ftp log server user name
--ftp-pwd=PASSWORD ftp log server password
--ftp-dir=DIRECTORY ftp log server directory
--quiet quiet operation, i.e. no output

View File

@ -0,0 +1,235 @@
#!/usr/bin/perl
################################################################################################################
# hlstats-ftp.pl
################################################################################################################
# Feed HLstatsX with log data via FTP
# (w) 2009 by Woody (http://woodystree.net)
################################################################################################################
use strict;
use Getopt::Long;
use Net::FTP;
use constant VERSION => "0.42";
use constant USAGE => <<EOT
Feed HLstatsX with log data via FTP.
Usage:
hlstats-ftp.pl --help
hlstats-ftp.pl --version
hlstats-ftp.pl --gs-ip=<IP> --gs-port=<PORT> [--ftp-ip=<IP>] --ftp-usr=<USR> --ftp-pwd=<PWD> --ftp-dir=<DIR> [--quiet]
Options:
--help display this help and exit
--version output version information and exit
--gs-ip=IP game server IP address
--gs-port=PORT game server port
--ftp-ip=IP ftp log server IP address, if different from
game server IP address (--gs-ip)
--ftp-usr=USR ftp log server user name
--ftp-pwd=PWD ftp log server password
--ftp-dir=DIR ftp log server directory
--quiet quiet operation, i.e. no output
(w)2009 by Woody (http://woodystree.net)
EOT
;
################################################################################################################
# define output subroutine
################################################################################################################
sub output {
if (!(our $opt_quiet)) {
my $text = shift;
print $text;
}
}
################################################################################################################
# get & parse command line options
################################################################################################################
my $opt_help; my $opt_version; my $gs_ip; my $gs_port; my $ftp_ip; my $ftp_usr; my $ftp_pwd; my $ftp_dir; our $opt_quiet;
GetOptions(
"help" => \$opt_help,
"version" => \$opt_version,
"gs-ip=s" => \$gs_ip,
"gs-port=i" => \$gs_port,
"ftp-ip=s" => \$ftp_ip,
"ftp-usr=s" => \$ftp_usr,
"ftp-pwd=s" => \$ftp_pwd,
"ftp-dir=s" => \$ftp_dir,
"quiet" => \$opt_quiet
) or die(USAGE);
if ($opt_help) {
print USAGE;
exit(0);
}
if ($opt_version) {
print "\nhlstats-ftp.pl - Version " . VERSION . "\n";
print "Feed HLstatsX with log data via FTP.\n";
print "(w)2009 by Woody (http://woodystree.net)\n\n";
exit(0);
}
if (!(defined $gs_ip) && !(defined $gs_port) && !(defined $ftp_usr) && !(defined $ftp_pwd) && !(defined $ftp_dir)) {
die(USAGE);
}
if (!(defined $ftp_ip)) {
$ftp_ip = $gs_ip;
}
################################################################################################################
# OK, lets go...
################################################################################################################
output("\nStarting hlstats-ftp.pl for IP $gs_ip, Port $gs_port...\n\n");
################################################################################################################
# create tmp directory
################################################################################################################
output(" - creating tmp directory... ");
my $tmp_dir = "hlstats-ftp-$gs_ip-$gs_port.tmp";
if (-e $tmp_dir) {
if (!(-w $tmp_dir)) {
die "Writing to tmp directory is not possible.";
}
} else {
mkdir($tmp_dir, 0775) || die "Make tmp directory \"$tmp_dir\" failed: $!";
}
output("OK.\n");
################################################################################################################
# get last mtime info, if any
################################################################################################################
output(" - getting last mtime info... ");
my $last_mtime_filename = "hlstats-ftp-$gs_ip-$gs_port.last";
my $last_mtime = 0;
if (-e $last_mtime_filename) {
open(LASTMTIME, "<$last_mtime_filename") || die "Open file \"$last_mtime_filename\" failed: $!";
$last_mtime = <LASTMTIME>;
close(LASTMTIME);
output("OK: last mtime $last_mtime.\n");
} else {
output("none: using default 0.\n");
}
################################################################################################################
# establish ftp connection
################################################################################################################
output(" - establishing FTP connection... ");
my $ftp = Net::FTP->new($ftp_ip) || die "FTP connect to \"$ftp_ip\" failed: $!";
$ftp->login($ftp_usr,$ftp_pwd) || die "FTP login for user \"$ftp_usr\" failed: $!";
$ftp->binary() || die "FTP binary mode failed: $!";
$ftp->cwd($ftp_dir) || die "FTP chdir to \"$ftp_dir\" failed: $!";
output("OK.\n");
################################################################################################################
# get complete list of log files
################################################################################################################
output(" - getting complete list of log files... ");
my @files = $ftp->ls("-t *.log"); # get list of log files sorted by mtime
$#files = $#files - 1; # skip last file, i.e. the latest file, which is possibly still in use by the game server
output("OK.\n");
################################################################################################################
# transfer log files to tmp directory, if todo
################################################################################################################
output(" + transfering log files, if todo:\n");
my @todo_files = ();
my @todo_mtimes = ();
foreach my $file (@files) {
output(" - \"$file\" ");
my $mtime = $ftp->mdtm($file) || die "FTP mtdm failed: $!";
output("(mtime $mtime): ");
if ($mtime > $last_mtime) {
output("transferring... ");
$ftp->get($file, "$tmp_dir/$file") || die "FTP get with \"$file\" failed: $!";
push(@todo_files, $file);
push(@todo_mtimes, $mtime);
output("OK.\n");
} else {
output("skipping.\n");
}
}
################################################################################################################
# close ftp connection
################################################################################################################
output(" - closing FTP connection... ");
$ftp->close() || die "FTP close failed: $!";
output("OK.\n");
################################################################################################################
# process log files in tmp directory
################################################################################################################
output(" + parsing log files:\n");
for (my $i = 0; $i <= $#todo_files; $i++) {
my $progress = "(" . ($i+1) . "/" . ($#todo_files+1) . ")";
output(" - \"" . $todo_files[$i] . "\" " . $progress . ": parsing... ");
system("./hlstats.pl --stdin --server-ip $gs_ip --server-port $gs_port < $tmp_dir/" . $todo_files[$i] . " > /dev/null");
output("updating last mtime...");
open(LASTMTIME, ">$last_mtime_filename") || die "Open file \"$last_mtime_filename\" failed: $!";
print LASTMTIME $todo_mtimes[$i];
close(LASTMTIME);
output("OK.\n");
}
################################################################################################################
# delete tmp log files and directory
################################################################################################################
output(" - delete tmp log files and directory... ");
foreach my $file (<$tmp_dir/*>) {
unlink($file) || die "Delete tmp log files failed: $!";
}
rmdir($tmp_dir) || die "Delete tmp directory failed: $!";
output("OK.\n");
################################################################################################################
# the end
################################################################################################################
output("\nSo Long, and Thanks for all the Fish.\n\n");

455
scripts/HLstats.plib Normal file
View File

@ -0,0 +1,455 @@
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# HLstatsX CE release version number
$g_version = "<Unable to Detect>";
my %db_stmt_cache = ();
%g_eventTables = (
"TeamBonuses",
["playerId", "actionId", "bonus"],
"ChangeRole",
["playerId", "role"],
"ChangeName",
["playerId", "oldName", "newName"],
"ChangeTeam",
["playerId", "team"],
"Connects",
["playerId", "ipAddress", "hostname", "hostgroup"],
"Disconnects",
["playerId"],
"Entries",
["playerId"],
"Frags",
["killerId", "victimId", "weapon", "headshot", "killerRole", "victimRole", "pos_x","pos_y","pos_z", "pos_victim_x","pos_victim_y","pos_victim_z"],
"PlayerActions",
["playerId", "actionId", "bonus", "pos_x","pos_y","pos_z"],
"PlayerPlayerActions",
["playerId", "victimId", "actionId", "bonus", "pos_x","pos_y","pos_z", "pos_victim_x","pos_victim_y","pos_victim_z"],
"Suicides",
["playerId", "weapon", "pos_x","pos_y","pos_z"],
"Teamkills",
["killerId", "victimId", "weapon", "pos_x","pos_y","pos_z", "pos_victim_x","pos_victim_y","pos_victim_z"],
"Rcon",
["type", "remoteIp", "password", "command"],
"Admin",
["type", "message", "playerName"],
"Statsme",
["playerId", "weapon", "shots", "hits", "headshots", "damage", "kills", "deaths"],
"Statsme2",
["playerId", "weapon", "head", "chest", "stomach", "leftarm", "rightarm", "leftleg", "rightleg"],
"StatsmeLatency",
["playerId", "ping"],
"StatsmeTime",
["playerId", "time"],
"Latency",
["playerId", "ping"],
"Chat",
["playerId", "message_mode", "message"]
);
##
## Common Functions
##
sub number_format {
local $_ = shift;
1 while s/^(-?\d+)(\d{3})/$1,$2/;
return $_;
}
sub date_format {
my $timestamp = shift;
return sprintf('%dd %02d:%02d:%02dh',
$timestamp / 86400,
$timestamp / 3600 % 24,
$timestamp / 60 % 60,
$timestamp % 60
);
}
#
# void error (string errormsg)
#
# Dies, and optionally mails error messages to $g_mailto.
#
sub error
{
my $errormsg = $_[0];
if ($g_mailto && $g_mailpath)
{
system("echo \"$errormsg\" | $g_mailpath -s \"HLstatsX:CE crashed `date`\" $g_mailto");
}
die("$errormsg\n");
}
#
# string quoteSQL (string varQuote)
#
# Escapes all quote characters in a variable, making it suitable for use in an
# SQL query. Returns the escaped version.
#
sub quoteSQL
{
my $varQuote = $_[0];
$varQuote =~ s/\\/\\\\/g; # replace \ with \\
$varQuote =~ s/'/\\'/g; # replace ' with \'
return $varQuote;
}
#
# void doConnect
#
# Connects to the HLstatsX database
#
sub doConnect
{
$db_conn = DBI->connect(
"DBI:mysql:$db_name:$db_host",
$db_user, $db_pass, { mysql_enable_utf8 => 1 }
);
while(!$db_conn) {
&printEvent("MYSQL", "\nCan't connect to MySQL database '$db_name' on '$db_host'\n" .
"Server error: $DBI::errstr\n");
sleep(5);
$db_conn = DBI->connect(
"DBI:mysql:$db_name:$db_host",
$db_user, $db_pass, { mysql_enable_utf8 => 1 }
);
}
$db_conn->do("SET NAMES 'utf8'");
&printEvent("MYSQL", "Connecting to MySQL database '$db_name' on '$db_host' as user '$db_user' ... connected ok", 1);
%db_stmt_cache = ();
}
#
# result doQuery (string query)
#
# Executes the SQL query 'query' and returns the result identifier.
#
sub doQuery
{
my ($query, $callref) = @_;
if(!$db_conn->ping()) {
&printEvent("HLSTATSX", "Lost database connection. Trying to reconnect...", 1);
&doConnect();
}
my $result = $db_conn->prepare($query) or die("Unable to prepare query:\n$query\n$DBI::errstr\n$callref");
$result->execute or die("Unable to execute query:\n$query\n$DBI::errstr\n$callref");
return $result;
}
sub execNonQuery
{
my ($query) = @_;
if(!$db_conn->ping()) {
&printEvent("HLSTATSX", "Lost database connection. Trying to reconnect...", 1);
&doConnect();
}
#&printEvent("DEBUG","execNonQuery:\n".$query);
$db_conn->do($query);
}
sub execCached {
my ($query_id,$query, @bind_args) = @_;
if(!$db_conn->ping()) {
&printEvent("HLSTATSX", "Lost database connection. Trying to reconnect...", 1);
&doConnect();
}
if(!$db_stmt_cache{$query_id}) {
$db_stmt_cache{$query_id} = $db_conn->prepare($query) or die("Unable to prepare query ($query_id):\n$query\n$DBI::errstr");
#&printEvent("HLSTATSX", "Prepared a statement ($query_id) for the first time.", 1);
}
$db_stmt_cache{$query_id}->execute(@bind_args) or die ("Unable to execute query ($query_id):\n$query\n$DBI::errstr");
return $db_stmt_cache{$query_id};
}
#
# string resolveIp (string ip, boolean quiet)
#
# Do a DNS reverse-lookup on an IP address and return the hostname, or empty
# string on error.
#
sub resolveIp
{
my ($ip, $quiet) = @_;
my ($host) = "";
unless ($g_dns_resolveip)
{
return "";
}
eval
{
$SIG{ALRM} = sub { die "DNS Timeout\n" };
alarm $g_dns_timeout; # timeout after $g_dns_timeout sec
$host = gethostbyaddr(inet_aton($ip), AF_INET);
alarm 0;
};
if ($@)
{
my $error = $@;
chomp($error);
printEvent("DNS", "Resolving hostname (timeout $g_dns_timeout sec) for IP \"$ip\" - $error ", 1);
$host = ""; # some error occurred
}
elsif (!defined($host))
{
printEvent("DNS", "Resolving hostname (timeout $g_dns_timeout sec) for IP \"$ip\" - No Host ", 1);
$host = ""; # ip did not resolve to any host
} else {
$host = lc($host); # lowercase
printEvent("DNS", "Resolving hostname (timeout $g_dns_timeout sec) for IP \"$ip\" - $host ", 1);
}
chomp($host);
return $host;
}
#
# object queryHostGroups ()
#
# Returns result identifier.
#
sub queryHostGroups
{
return &doQuery("
SELECT
pattern,
name,
LENGTH(pattern) AS patternlength
FROM
hlstats_HostGroups
ORDER BY
patternlength DESC,
pattern ASC
");
}
#
# string getHostGroup (string hostname[, object result])
#
# Return host group name if any match, or last 2 or 3 parts of hostname.
#
sub getHostGroup
{
my ($hostname, $result) = @_;
my $hostgroup = "";
# User can define special named hostgroups in hlstats_HostGroups, i.e.
# '.adsl.someisp.net' => 'SomeISP ADSL'
$result = &queryHostGroups() unless ($result);
$result->execute();
while (my($pattern, $name) = $result->fetchrow_array())
{
$pattern = quotemeta($pattern);
$pattern =~ s/\\\*/[^.]*/g; # allow basic shell-style globbing in pattern
if ($hostname =~ /$pattern$/)
{
$hostgroup = $name;
last;
}
}
$result->finish;
if (!$hostgroup)
{
#
# Group by last 2 or 3 parts of hostname, i.e. 'max1.xyz.someisp.net' as
# 'someisp.net', and 'max1.xyz.someisp.net.nz' as 'someisp.net.nz'.
# Unfortunately some countries do not have categorical SLDs, so this
# becomes more complicated. The dom_nosld array below contains a list of
# known country codes that do not use categorical second level domains.
# If a country uses SLDs and is not listed below, then it will be
# incorrectly grouped, i.e. 'max1.xyz.someisp.yz' will become
# 'xyz.someisp.yz', instead of just 'someisp.yz'.
#
# Please mail sgarner@hlstats.org with any additions.
#
my @dom_nosld = (
"ca", # Canada
"ch", # Switzerland
"be", # Belgium
"de", # Germany
"ee", # Estonia
"es", # Spain
"fi", # Finland
"fr", # France
"ie", # Ireland
"nl", # Netherlands
"no", # Norway
"ru", # Russia
"se", # Sweden
);
my $dom_nosld = join("|", @dom_nosld);
if ($hostname =~ /([\w-]+\.(?:$dom_nosld|\w\w\w))$/)
{
$hostgroup = $1;
}
elsif ($hostname =~ /([\w-]+\.[\w-]+\.\w\w)$/)
{
$hostgroup = $1;
}
else
{
$hostgroup = $hostname;
}
}
return $hostgroup;
}
#
# void doConf (object conf, hash directives)
#
# Walk through configuration directives, setting values of global variables.
#
sub doConf
{
my ($conf, %directives) = @_;
while (($directive, $variable) = each(%directives))
{
if ($directive eq "Servers") {
%$variable = $conf->get($directive);
} else {
$$variable = $conf->get($directive);
}
}
}
#
# void setOptionsConf (hash optionsconf)
#
# Walk through configuration directives, setting values of global variables.
#
sub setOptionsConf
{
my (%optionsconf) = @_;
while (($thekey, $theval) = each(%optionsconf))
{
if($theval)
{
$$thekey = $theval;
}
}
}
#
# string abbreviate (string thestring[, int maxlength)
#
# Returns thestring abbreviated to maxlength-3 characters plus "...", unless
# thestring is shorter than maxlength.
#
sub abbreviate
{
my ($thestring, $maxlength) = @_;
$maxlength = 12 unless ($maxlength);
if (length($thestring) > $maxlength)
{
$thestring = substr($thestring, 0, $maxlength - 3);
return "$thestring...";
}
else
{
return $thestring;
}
}
#
# void printEvent (int code, string description)
#
# Logs event information to stdout.
#
sub printEvent
{
my ($code, $description, $update_timestamp, $force_output) = @_;
if ( (($g_debug > 0) && ($g_stdin == 0))|| (($g_stdin == 1) && ($force_output == 1)) ) {
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time());
my $timestamp = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
if ($update_timestamp == 0) {
$timestamp = $ev_timestamp;
}
if (is_number($code)) {
printf("%s: %21s - E%03d: %s\n", $timestamp, $s_addr, $code, $description);
} else {
printf("%s: %21s - %s: %s\n", $timestamp, $s_addr, $code, $description);
}
}
}
1;

File diff suppressed because it is too large Load Diff

104
scripts/HLstats_Game.pm Normal file
View File

@ -0,0 +1,104 @@
package HLstats_Game;
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
#
# Constructor
#
sub new
{
my $class_name = shift;
my $game = shift;
my $self = {};
bless($self, $class_name);
# Initialise Properties
$self->{game} = $game;
$self->{weapons} = ();
$self->{actions} = ();
# Set Property Values
die("HLstats_Game->new(): must specify game's game code\n") if ($game eq "");
#&::printEvent("DEBUG","game is $game");
my $weaponlist = &::doQuery("SELECT code, name, modifier FROM hlstats_Weapons WHERE game='".&::quoteSQL($game)."'");
while ( my($code,$name,$modifier) = $weaponlist->fetchrow_array) {
$self->{weapons}{$code}{name} = $name;
$self->{weapons}{$code}{modifier} = $modifier;
#&::printEvent("DEBUG","Weapon: name is \"$name\"; modifier is $modifier");
}
my $actionlist = &::doQuery("SELECT id, code, reward_player, reward_team, team, description, for_PlayerActions, for_PlayerPlayerActions, for_TeamActions, for_WorldActions FROM hlstats_Actions WHERE game='".&::quoteSQL($game)."'");
while ( my($id, $code, $reward_player,$reward_team,$team, $descr, $paction, $ppaction, $taction, $waction) = $actionlist->fetchrow_array) {
$self->{actions}{$code}{id} = $id;
$self->{actions}{$code}{descr} = $descr;
$self->{actions}{$code}{reward_player} = $reward_player;
$self->{actions}{$code}{reward_team} = $reward_team;
$self->{actions}{$code}{team} = $team;
$self->{actions}{$code}{paction} = $paction;
$self->{actions}{$code}{ppaction} = $ppaction;
$self->{actions}{$code}{taction} = $taction;
$self->{actions}{$code}{waction} = $waction;
}
$actionlist->finish;
&::printNotice("Created new game object " . $game);
return $self;
}
sub getTotalPlayers
{
my ($self) = @_;
my $query = "
SELECT
COUNT(*)
FROM
hlstats_Players
WHERE
game=?
AND hideranking = 0
AND kills >= 1
";
my $resultTotalPlayers = &::execCached("get_game_total_players", $query, &::quoteSQL($self->{game}));
my ($totalplayers) = $resultTotalPlayers->fetchrow_array;
$resultTotalPlayers->finish;
return $totalplayers;
}
1;

View File

@ -0,0 +1,56 @@
use constant {
UNKNOWN => -1,
CSS => 0,
HL2MP => 1,
TF => 2,
DODS => 3,
INSMOD => 4,
FF => 5,
HIDDEN => 6,
ZPS => 7,
AOC => 8,
CSTRIKE => 9,
TFC => 10,
DOD => 11,
NS => 12,
L4D => 13,
FOF => 14,
GES => 15,
BG2 => 16,
SGTLS => 17,
DYSTOPIA => 18,
NTS => 19,
PVKII => 20,
CSP => 21,
VALVE => 22,
NUCLEARDAWN => 23,
DDD => 24,
};
%gamecode_to_game = (
'css' => CSS(),
'hl2mp' => HL2MP(),
'tf' => TF(),
'dods' => DODS(),
'insmod' => INSMOD(),
'ff' => FF(),
'hidden' => HIDDEN(),
'zps' => ZPS(),
'aoc' => AOC(),
'cstrike' => CSTRIKE(),
'tfc' => TFC(),
'dod' => DOD(),
'ns' => NS(),
'l4d' => L4D(),
'fof' => FOF(),
'ges' => GES(),
'bg2' => BG2(),
'sgtls' => SGTLS(),
'dystopia' => DYSTOPIA(),
'nts' => NTS(),
'pvkii' => PVKII(),
'csp' => CSP(),
'valve' => VALVE(),
'nucleardawn' => NUCLEARDAWN(),
'dinodday' => DDD()
);

1124
scripts/HLstats_Player.pm Normal file

File diff suppressed because it is too large Load Diff

1414
scripts/HLstats_Server.pm Normal file

File diff suppressed because it is too large Load Diff

55
scripts/ImportBans/README Normal file
View File

@ -0,0 +1,55 @@
HLStatsX:CE Import Ban Options
----------------------
Description:
HLStatsX:CE has two different scripts to use to import bans from your banning system:
1) ImportBans
ImportBans.pl is a perl script and is the original importing script.
It only imports bans and does not unban a player if they're unbanned from your ban system.
This script supports SourceBans, AMXBans, BeetleMod, and GlobalBan.
You must have perl installed to use this script.
2) hlstatsxbans
Hlstatsxbans is written by Peace-Maker and is written in PHP.
This script will ban AND UNBAN players as they are banned from your banning system.
Forum URL: http://forums.interwavestudios.com/topic/167-import-mysql-bans-to-hlxce-bancheater-page/
This script suports SourceBans, AMXBans, BeetleMod, and GlobalBan.
You must have PHP installed to use this script.
Configuration:
Select which ban system you want to use, either ImportBans or HLStatsXBans. You must then edit the corresponding file.
*run_importbans
** Open run_importbans in a text editor
** Configure "BANSYSTEM" for which script you would like to use.
*ImportBans
** Open ImportBans.pl in a text editor.
** Fill in the HLX DB INFO section (should be same as that found in hlstats.conf in the Perl directory)
** Fill in at least one of the other databases (Sourcebans, AMXBans, BeetlesMod) that you want to import from.
NOTE: You can use any of these databases simultaneously -- fill in the ones you want
to pull from and those databases will be queried.
*HLStatsXBans
** Open HLStatsXBans.cfg in a text editor.
** Fill in the database info for HLX.
** Fill in at least one of the other databases that you want to import from.
Running:
You should run the script manually one time to make sure everything is working.
To run ImportBans, run:
./importbans.pl
To run HLStatsXBans, run:
php hlstatsxbans.php
If everything works, you can either schedule the exact same command you just executed to run at a configured interval or time,
or use the run_importbans wrapper to get logging (great for console use).
To use run_importbans, make sure you have edited the file for which script you want to use, and then simply execute:
./run_importbans.
Note: you will not get any output from this script. Everything is written into your logs/ directory.

View File

@ -0,0 +1,105 @@
<?php
/***************
** Deactivate HLstatsX ranking for banned players
** and reactivate them if unbanned
** Supports SourceBans, AMXBans, Beetlesmod, Globalban, MySQL Banning*
** by Jannik 'Peace-Maker' Hartung
** http://www.sourcebans.net/, http://www.wcfan.de/
** 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.
**
**
** Version 1.3: Added MySQL Banning support
** Version 1.2: Added more error handling
** Version 1.1: Fixed banned players not marked as banned, if a previous ban was unbanned
** Version 1.0: Initial Release
** YOU MUST ADJUST THIS FILE TO MEET YOUR NEEDS!
** Please fill in AT LEAST one bans database AND
** the HLStatsX Database section! Don't forget the names
** of the HLStatsX Databases near the end of this file!
**************/
//** SOURCEBANS MYSQL INFO ----------------------------
// http://www.sourcebans.net/
define('SB_HOST', 'localhost'); // MySQL host
define('SB_PORT', 3306); // MySQL port (Default 3306)
define('SB_USER', ''); // MySQL user
define('SB_PASS', ''); // MySQL password
define('SB_NAME', ''); // MySQL database name
define('SB_PREFIX', 'sb'); // MySQL table prefix
//** END SOURCEBANS MYSQL INFO ------------------------
//** AMXBANS MYSQL INFO -------------------------------
// http://www.amxbans.net/
define('AMX_HOST', 'localhost'); // MySQL host
define('AMX_PORT', 3306); // MySQL port (Default 3306)
define('AMX_USER', ''); // MySQL user
define('AMX_PASS', ''); // MySQL password
define('AMX_NAME', ''); // MySQL database name
define('AMX_PREFIX', 'amx'); // MySQL table prefix
//** END AMXBANS MYSQL INFO ---------------------------
//** BEETLESMOD MYSQL INFO ----------------------------
// http://www.beetlesmod.com/
define('BM_HOST', 'localhost'); // MySQL host
define('BM_PORT', 3306); // MySQL port (Default 3306)
define('BM_USER', ''); // MySQL user
define('BM_PASS', ''); // MySQL password
define('BM_NAME', ''); // MySQL database name
define('BM_PREFIX', 'bm'); // MySQL table prefix
//** END BEETLESMOD MYSQL INFO ------------------------
//** GLOBALBAN MYSQL INFO -----------------------------
// http://addons.eventscripts.com/addons/view/GlobalBan
// http://forums.eventscripts.com/viewtopic.php?t=14384
define('GB_HOST', 'localhost'); // MySQL host
define('GB_PORT', 3306); // MySQL port (Default 3306)
define('GB_USER', ''); // MySQL user
define('GB_PASS', ''); // MySQL password
define('GB_NAME', 'global_ban'); // MySQL database name
define('GB_PREFIX', 'gban'); // MySQL table prefix
//** END GLOBALBAN MYSQL INFO -------------------------
//** MySQL Banning - MYSQL INFO -----------------------
// http://forums.alliedmods.net/showthread.php?t=65822
define('MB_HOST', 'localhost'); // MySQL host
define('MB_PORT', 3306); // MySQL port (Default 3306)
define('MB_USER', ''); // MySQL user
define('MB_PASS', ''); // MySQL password
define('MB_NAME', ''); // MySQL database name
define('MB_PREFIX', 'mysql'); // MySQL table prefix
//** END MySQL Banning - MYSQL INFO -------------------
//** HLSTATSX MYSQL INFO ------------------------------
// http://www.hlxcommunity.com/
define('HLX_HOST', 'localhost'); // MySQL host
define('HLX_PORT', 3306); // MySQL port (Default 3306)
define('HLX_USER', ''); // MySQL user
define('HLX_PASS', ''); // MySQL password
define('HLX_PREFIX', 'hlstats'); // MySQL table prefix
/*************************************************
/* We're using different databases for each of our server to isolate each ranking
/* Type the HLstatsX database name here like
/* $hlxdbs[] = "databasename";
/* It's fine to just type one database.
**************************************************/
$hlxdbs = array();
$hlxdbs[] = "hlstatsx";
//** END HLSTATSX MYSQL INFO --------------------------
?>

View File

@ -0,0 +1,362 @@
<?php
/***************
** Deactivate HLstatsX ranking for banned players
** and reactivate them if unbanned
** Supports SourceBans, AMXBans, Beetlesmod, Globalban, MySQL Banning*
** by Jannik 'Peace-Maker' Hartung
** http://www.sourcebans.net/, http://www.wcfan.de/
** 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.
**
**
** Version 1.3: Added MySQL Banning support
** Version 1.2: Added more error handling
** Version 1.1: Fixed banned players not marked as banned, if a previous ban was unbanned
** Version 1.0: Initial Release
***************/
/*****************************
/***MAKE YOUR CONFIGURATION***
/********SETTINGS IN**********
/******hlstatsxban.cfg********
/***** DON'T EDIT BELOW ******
/*****************************/
require("hlstatsxban.cfg");
if (!extension_loaded('mysqli')) {
die("This script requires the MySQLi extension to be enabled. Consult your administrator, or edit your php.ini file, to enable this extension.");
}
$usesb = (SB_HOST == ""||SB_PORT == ""||SB_USER == ""||SB_PASS == ""||SB_NAME == ""||SB_PREFIX == ""?false:true);
$useamx = (AMX_HOST == ""||AMX_PORT == ""||AMX_USER == ""||AMX_PASS == ""||AMX_NAME == ""||AMX_PREFIX == ""?false:true);
$usebm = (BM_HOST == ""||BM_PORT == ""||BM_USER == ""||BM_PASS == ""||BM_NAME == ""||BM_PREFIX == ""?false:true);
$usegb = (GB_HOST == ""||GB_PORT == ""||GB_USER == ""||GB_PASS == ""||GB_NAME == ""||GB_PREFIX == ""?false:true);
$usemb = (MB_HOST == ""||MB_PORT == ""||MB_USER == ""||MB_PASS == ""||MB_NAME == ""||MB_PREFIX == ""?false:true);
$hlxready = (HLX_HOST == ""||HLX_PORT == ""||HLX_USER == ""||HLX_PASS == ""||empty($hlxdbs)||HLX_PREFIX == ""?false:true);
if (!$hlxready || (!$usesb && !$useamx && !$usebm && !$usegb && !$usemb))
die('[-] Please type your database information for HLstatsX and at least for one other ban database.');
$bannedplayers = array();
$unbannedplayers = array();
//------------------------------
// SourceBans Part
//------------------------------
if ($usesb)
{
// Connect to the SourceBans database.
$con = new mysqli(SB_HOST, SB_USER, SB_PASS, SB_NAME, SB_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to SourceBans Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to SourceBans database. Retrieving bans now.\n");
// Get permanent banned players
$bcnt = 0;
if ($bans = $con->query("SELECT `authid` FROM `".SB_PREFIX."_bans` WHERE `RemoveType` IS NULL AND `length` = 0")) {
while ($banned = $bans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($banned["authid"], $bannedplayers)) {
$bannedplayers[] = $banned["authid"];
++$bcnt;
}
}
}
else {
die('[-] Error retrieving banned players: ' . $con->error);
}
// Read unbanned players
$ubcnt = 0;
if ($unbans = $con->query("SELECT `authid` FROM `".SB_PREFIX."_bans` WHERE `RemoveType` IS NOT NULL AND `RemovedOn` IS NOT NULL")) {
while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($unbanned["authid"], $bannedplayers) && !in_array($unbanned["authid"], $unbannedplayers)) {
$unbannedplayers[] = $unbanned["authid"];
++$ubcnt;
}
}
}
else {
die('[-] Error retrieving unbanned players: ' . $con->error);
}
$con->close();
print("[+] Retrieved ".$bcnt." banned and ".$ubcnt." unbanned players from SourceBans.\n");
}
//------------------------------
// AMXBans Part
//------------------------------
if ($useamx)
{
// Connect to the AMXBans database.
$con = new mysqli(AMX_HOST, AMX_USER, AMX_PASS, AMX_NAME, AMX_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to AMXBans Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to AMXBans database. Retrieving bans now.\n");
// Get permanent banned players
$bcnt = 0;
if ($bans = $con->query("SELECT `player_id` FROM `".AMX_PREFIX."_bans` WHERE `ban_length` = 0")) {
while ($banned = $bans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($banned["player_id"], $bannedplayers))
{
$bannedplayers[] = $banned["player_id"];
++$bcnt;
}
}
} else {
die('[-] Error retrieving banned players: ' . $con->error);
}
// Read unbanned players
$ubcnt = 0;
// Handles (apparently) pre-6.0 version DB or lower
if ($unbans = $con->query("SELECT `player_id` FROM `".AMX_PREFIX."_banhistory` WHERE `ban_length` = 0")) {
while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($unbanned["player_id"], $bannedplayers) && !in_array($unbanned["player_id"], $unbannedplayers))
{
$unbannedplayers[] = $unbanned["player_id"];
++$ubcnt;
}
}
}
// Handles (apparently) 6.0 version DB or higher
else if ($unbans = $con->query("SELECT `player_id` FROM `".AMX_PREFIX."_bans` WHERE `expired` = 1")) {
while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($unbanned["player_id"], $bannedplayers) && !in_array($unbanned["player_id"], $unbannedplayers))
{
$unbannedplayers[] = $unbanned["player_id"];
++$ubcnt;
}
}
} else {
die('[-] Error retrieving unbanned players: ' . $con->error);
}
$con->close();
print("[+] Retrieved ".$bcnt." banned and ".$ubcnt." unbanned players from AMXBans.\n");
}
//------------------------------
// Beetlesmod Part
//------------------------------
if ($usebm)
{
// Connect to the Beetlesmod database.
$con = new mysqli(BM_HOST, BM_USER, BM_PASS, BM_NAME, BM_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to Beetlesmod Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to Beetlesmod database. Retrieving bans now.\n");
// Get permanent banned players
$bcnt = 0;
if ($bans = $con->query("SELECT `steamid` FROM `".BM_PREFIX."_bans` WHERE `Until` IS NULL")) {
while ($banned = $bans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($banned["steamid"], $bannedplayers))
{
$bannedplayers[] = $banned["steamid"];
++$bcnt;
}
}
} else {
die('[-] Error retrieving banned players: ' . $con->error);
}
// Read unbanned players
$ubcnt = 0;
if ($unbans = $con->query("SELECT `steamid` FROM `".BM_PREFIX."_bans` WHERE `Until` IS NULL AND `Remove` = 0")) {
while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($unbanned["steamid"], $bannedplayers) && !in_array($unbanned["steamid"], $unbannedplayers))
{
$unbannedplayers[] = $unbanned["steamid"];
++$ubcnt;
}
}
} else {
die('[-] Error retrieving unbanned players: ' . $con->error);
}
$con->close();
print("[+] Retrieved ".$bcnt." banned and ".$ubcnt." unbanned players from Beetlesmod.\n");
}
//------------------------------
// Globalban Part
//------------------------------
if ($usegb)
{
// Connect to the Globalban database.
$con = new mysqli(GB_HOST, GB_USER, GB_PASS, GB_NAME, GB_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to Globalban Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to Globalban database. Retrieving bans now.\n");
// Get permanent banned players
$bcnt = 0;
if ($bans = $con->query("SELECT `steam_id` FROM `".GB_PREFIX."_ban` WHERE `active` = 1 AND `pending` = 0 AND `length` = 0")) {
while ($banned = $bans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($banned["steam_id"], $bannedplayers))
{
$bannedplayers[] = $banned["steam_id"];
++$bcnt;
}
}
} else {
die('[-] Error retrieving banned players: ' . $con->error);
}
// Read unbanned players
$ubcnt = 0;
if ($unbans = $con->query("SELECT `steam_id` FROM `".GB_PREFIX."_ban` WHERE `active` = 0 AND `pending` = 0 AND `length` = 0")) {
while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($unbanned["steam_id"], $bannedplayers) && !in_array($unbanned["steam_id"], $unbannedplayers))
{
$unbannedplayers[] = $unbanned["steam_id"];
++$ubcnt;
}
}
} else {
die('[-] Error retrieving unbanned players: ' . $con->error);
}
$con->close();
print("[+] Retrieved ".$bcnt." banned and ".$ubcnt." unbanned players from Globalban.\n");
}
//------------------------------
// MySQL Banning Part
//------------------------------
if ($usemb)
{
// Connect to the MySQL Banning database.
$con = new mysqli(MB_HOST, MB_USER, MB_PASS, MB_NAME, MB_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to MySQL Banning Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to MySQL Banning database. Retrieving bans now.\n");
// Get permanent banned players
$bcnt = 0;
if ($bans = $con->query("SELECT `steam_id` FROM `".MB_PREFIX."_bans` WHERE `ban_length` = 0")) {
while ($banned = $bans->fetch_array(MYSQL_ASSOC)) {
if(!in_array($banned["steam_id"], $bannedplayers))
{
$bannedplayers[] = $banned["steam_id"];
++$bcnt;
}
}
} else {
die('[-] Error retrieving banned players: ' . $con->error);
}
/****** SM MySQL Banning doesn't provide a ban history AFAIK ******/
// Read unbanned players
// $ubcnt = 0;
// if ($unbans = $con->query("SELECT `steam_id` FROM `".MB_PREFIX."_bans` WHERE `ban_length` = 0")) {
// while ($unbanned = $unbans->fetch_array(MYSQL_ASSOC)) {
// if(!in_array($unbanned["steam_id"], $bannedplayers) && !in_array($unbanned["steam_id"], $unbannedplayers))
// {
// $unbannedplayers[] = $unbanned["steam_id"];
// ++$ubcnt;
// }
// }
// } else {
// die('[-] Error retrieving unbanned players: ' . $con->error);
//}
$con->close();
//print("[+] Retrieved ".$bcnt." banned and ".$ubcnt." unbanned players from MySQL Banning.\n");
print("[+] Retrieved ".$bcnt." banned players from MySQL Banning.\n");
}
//------------------------------
// HLstatsX Part
//------------------------------
if(empty($bannedplayers) && empty($unbannedplayers))
die('[-] Nothing to change. Exiting.');
$bannedsteamids="''";
$unbannedsteamids="''";
if(!empty($bannedplayers))
{
$bannedsteamids = "'";
foreach ($bannedplayers as $steamid)
{
$steamid = preg_replace('/^STEAM_[0-9]+?\:/i','',$steamid);
$bannedsteamids .= $steamid."','";
}
$bannedsteamids .= preg_replace('/\,\'$/','',$steamid);
$bannedsteamids .= "'";
}
if(!empty($unbannedplayers))
{
$unbannedsteamids = "'";
foreach ($unbannedplayers as $steamid)
{
$steamid = preg_replace('/^STEAM_[0-9]+?\:/i','',$steamid);
$unbannedsteamids .= $steamid."','";
}
$unbannedsteamids .= preg_replace('/\,\'$/','',$steamid);
$unbannedsteamids .= "'";
}
// Connection to DB
$hlxcon = new mysqli(HLX_HOST, HLX_USER, HLX_PASS, '', HLX_PORT);
if (mysqli_connect_error()) die('[-] Can\'t connect to HLstatsX Database (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
print("[+] Successfully connected to HLstatsX database server. Updating players...\n");
// Loop through all hlstatsx databases
foreach ($hlxdbs as $hlxdb)
{
$unbancnt = $bancnt = 0;
$hlxcon->select_db($hlxdb);
// Hide all banned players
if ($hlxban = $hlxcon->query("UPDATE `".HLX_PREFIX."_Players` SET `hideranking` = 2 WHERE `hideranking` < 2 AND `playerId` IN (SELECT `playerId` FROM `".HLX_PREFIX."_PlayerUniqueIds` WHERE `uniqueId` IN (".$bannedsteamids."));")) {
$bancnt = ($hlxcon->affected_rows?$hlxcon->affected_rows:0);
}
else {
die('[-] Error hiding banned players: ' . $hlxcon->error);
}
// Show all unbanned players
if ($hlxunban = $hlxcon->query("UPDATE `".HLX_PREFIX."_Players` SET `hideranking` = 0 WHERE `hideranking` = 2 AND `playerId` IN (SELECT `playerId` FROM `".HLX_PREFIX."_PlayerUniqueIds` WHERE `uniqueId` IN (".$unbannedsteamids."));")) {
$unbancnt = ($hlxcon->affected_rows?$hlxcon->affected_rows:0);
if ($bancnt>0||$unbancnt>0) {
print("[+] ".$hlxdb.": ".$bancnt." players were marked as banned, ".$unbancnt." players were reenabled again.\n");
}
else {
print("[-] ".$hlxdb.": No player changed.\n");
}
}
else {
die('[-] Error showing unbanned players: ' . $hlxcon->error);
}
}
$hlxcon->close();
?>

View File

@ -0,0 +1,194 @@
#!/usr/bin/perl
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
####
# Script to mark banned users in HLstatsX Community Edition from a Sourcebans, AMXBans, Beetlesmod, or ES GlobalBan database (or multiple at once!)
# Last Revised: 2009-07-22 13:35 GMT
# BeetlesMod and GlobalBan support added by Bo Tribun (R3M)
#######################################################################################
# You must fill info out for the HLX DB and at least one of the Bans databases
#######################################################################################
# Sourcebans DB Info
$sb_dbhost = "localhost";
$sb_dbport = 3306;
$sb_dbuser = "";
$sb_dbpass = "";
$sb_dbname = "";
$sb_prefix = "sb_"; # be sure to include the underscore (_)
# AMXBans DB Info
$amxb_dbhost = "localhost";
$amxb_dbport = 3306;
$amxb_dbuser = "";
$amxb_dbpass = "";
$amxb_dbname = "";
# BeetlesMod DB Info
$bm_dbhost = "localhost";
$bm_dbport = 3306;
$bm_dbuser = "";
$bm_dbpass = "";
$bm_dbname = "";
# ES GlobalBan DB Info
$gb_dbhost = "localhost";
$gb_dbport = 3306;
$gb_dbuser = "";
$gb_dbpass = "";
$gb_dbname = "";
# HLX DB Info
$hlx_dbhost = "localhost";
$hlx_dbport = 3306;
$hlx_dbuser = "";
$hlx_dbpass = "";
$hlx_dbname = "";
##
##
################################################################################
## No need to edit below this line
##
use DBI;
$havesbinfo = ($sb_dbhost eq "" || $sb_dbuser eq "" || $sb_dbpass eq "" || $sb_dbname eq "")?0:1;
$haveamxbinfo = ($amxb_dbhost eq "" || $amxb_dbuser eq "" || $amxb_dbpass eq "" || $amxb_dbname eq "")?0:1;
$havebminfo = ($bm_dbhost eq "" || $bm_dbuser eq "" || $bm_dbpass eq "" || $bm_dbname eq "")?0:1;
$havegbinfo = ($gb_dbhost eq "" || $gb_dbuser eq "" || $gb_dbpass eq "" || $gb_dbname eq "")?0:1;
$havehlxinfo = ($hlx_dbhost eq "" || $hlx_dbuser eq "" || $hlx_dbpass eq "" || $hlx_dbname eq "")?0:1;
die("DB login info incomplete. Exiting\n") if ($havehlxinfo == 0 || ($havesbinfo == 0 && $haveamxbinfo == 0 && $havebminfo == 0 && $havegbinfo == 0));
@steamids = ();
if ($havesbinfo) {
print "Connecting to Sourcebans database...\n";
my $sb_dbconn = DBI->connect(
"DBI:mysql:database=$sb_dbname;host=$sb_dbhost;port=$sb_dbport",
$sb_dbuser, $sb_dbpass) or die ("\nCan't connect to Sourcebans database '$sb_dbname' on '$sb_dbhost'\n" .
"Server error: $DBI::errstr\n");
print "Successfully connected to Sourcebans database. Retrieving banned Steam IDs now...\n";
my $result = &doQuery($sb_dbconn, "SELECT `authid` FROM ".$sb_prefix."bans WHERE `length` = 0 AND `RemovedBy` IS NULL");
while ( my($steamid) = $result->fetchrow_array) {
push(@steamids, $steamid);
}
my $rows = $result->rows;
if ($rows) {
print $rows." banned users retrieved from Sourcebans.\n";
}
$sb_dbconn->disconnect;
}
if ($haveamxbinfo) {
print "Connecting to AMXBans database...\n";
my $amxb_dbconn = DBI->connect(
"DBI:mysql:database=$amxb_dbname;host=$amxb_dbhost;port=$amxb_dbport",
$amxb_dbuser, $amxb_dbpass) or die ("\nCan't connect to AMXBans database '$amxb_dbname' on '$amxb_dbhost'\n" .
"Server error: $DBI::errstr\n");
print "Successfully connected to AMXBans database. Retrieving banned Steam IDs now...\n";
my $result = &doQuery($amxb_dbconn, "SELECT `player_id` FROM amx_bans WHERE `ban_length` = 0");
while ( my($steamid) = $result->fetchrow_array) {
push(@steamids, $steamid);
}
my $rows = $result->rows;
if ($rows) {
print $rows." banned users retrieved from AMXBans.\n";
}
$amxb_dbconn->disconnect;
}
if ($havebminfo) {
print "Connecting to BeetlesMod database...\n";
my $bm_dbconn = DBI->connect(
"DBI:mysql:database=$bm_dbname;host=$bm_dbhost;port=$bm_dbport",
$bm_dbuser, $bm_dbpass) or die ("\nCan't connect to BeetlesMod database '$bm_dbname' on '$bm_dbhost'\n" .
"Server error: $DBI::errstr\n");
print "Successfully connected to BeetlesMod database. Retrieving banned Steam IDs now...\n";
my $result = &doQuery($bm_dbconn, "SELECT `steamid` FROM `bm_bans` WHERE `Until` IS NULL");
while ( my($steamid) = $result->fetchrow_array) {
push(@steamids, $steamid);
}
my $rows = $result->rows;
if ($rows) {
print $rows." banned users retrieved from BeetlesMod.\n";
}
$bm_dbconn->disconnect;
}
if ($havegbinfo) {
print "Connecting to ES GlobalBan database...\n";
my $gb_dbconn = DBI->connect(
"DBI:mysql:database=$gb_dbname;host=$gb_dbhost;port=$gb_dbport",
$gb_dbuser, $gb_dbpass) or die ("\nCan't connect to ES GlobalBan database '$gb_dbname' on '$gb_dbhost'\n" .
"Server error: $DBI::errstr\n");
print "Successfully connected to ES GlobalBan database. Retrieving banned Steam IDs now...\n";
my $result = &doQuery($gb_dbconn, "SELECT `steam_id` FROM `gban_ban` WHERE `active` = 1 AND `pending` = 0 AND `length` = 0");
while ( my($steamid) = $result->fetchrow_array) {
push(@steamids, $steamid);
}
my $rows = $result->rows;
if ($rows) {
print $rows." banned users retrieved from ES GlobalBan.\n";
}
$gb_dbconn->disconnect;
}
if (@steamids) {
$steamidstring = "'";
foreach $steamid (@steamids)
{
$steamid =~ s/^STEAM_[0-9]+?\://i;
$steamidstring .= $steamid."','";
}
$steamidstring =~ s/\,\'$//;
print "Connecting to HLX:CE database...\n";
$hlx_dbconn = DBI->connect(
"DBI:mysql:database=$hlx_dbname;host=$hlx_dbhost;port=$hlx_dbport",
$hlx_dbuser, $hlx_dbpass) or die ("\nCan't connect to HLX:CE database '$hlx_dbname' on '$hlx_dbhost'\n" .
"Server error: $DBI::errstr\n");
print "Updating HLX:CE banned players...\n";
$result = &doQuery($hlx_dbconn, "UPDATE `hlstats_Players` SET `hideranking` = 2 WHERE `playerId` IN (SELECT `playerId` FROM hlstats_PlayerUniqueIds WHERE `uniqueId` IN ($steamidstring)) AND `hideranking` < 2");
print $result->rows." users newly marked as banned.\n";
$hlx_dbconn->disconnect;
} else {
die("No banned users found in database(s). Exiting\n");
}
sub doQuery
{
my ($dbconn, $query, $callref) = @_;
my $result = $dbconn->prepare($query) or die("Unable to prepare query:\n$query\n$DBI::errstr\n$callref");
$result->execute or die("Unable to execute query:\n$query\n$DBI::errstr\n$callref");
return $result;
}

View File

@ -0,0 +1,79 @@
#!/bin/bash
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# HLStatsX:CE now has two import ban utilities:
# 1) ImportBans.pl is the original importing script written in perl.
#
# 2) hlstatsxbans.php is written by Peace-Maker and is written in PHP.
#
# More information on these scripts can be found in README.
# Please select your banning system below using the number that corresponds to the ban system above.
BANSYSTEM=1
### Nothing needs to be modified below here ###
# verify that you have a logs directory
if [ ! -d logs ];then
mkdir logs
fi
if [ ! -w logs ];then
echo "you need write access to the logs folder"
exit 1
fi
# print info to the log file and run importbans.pl
echo Importing Bans -- `date +%c` >> logs/log`date +_%Y%m%d`
case $BANSYSTEM in
1)
echo Using importbans.pl >> logs/log`date +_%Y%m%d` 2>&1
./importbans.pl >> logs/log`date +_%Y%m%d` 2>&1
;;
2)
echo Using hlstatsxbans.php >> logs/log`date +_%Y%m%d` 2>&1
/usr/bin/php `pwd`/hlstatsxban.php >> logs/log`date +_%Y%m%d` 2>&1
;;
*)
echo Warning: BANSYSTEM is not correctly configured. Please check your configuration.
;;
esac
echo >> logs/log`date +_%Y%m%d`
exit 0

500
scripts/TRcon.pm Normal file
View File

@ -0,0 +1,500 @@
package TRcon;
#
# TRcon Perl Module - execute commands on a remote Half-Life2 server using remote console.
#
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
use strict;
no strict 'vars';
use Sys::Hostname;
use IO::Socket;
use IO::Select;
use bytes;
use Scalar::Util;
do "$::opt_libdir/HLstats_GameConstants.plib";
my $VERSION = "1.00";
my $TIMEOUT = 1.0;
my $SERVERDATA_EXECCOMMAND = 2;
my $SERVERDATA_AUTH = 3;
my $SERVERDATA_RESPONSE_VALUE = 0;
my $SERVERDATA_AUTH_RESPONSE = 2;
my $REFRESH_SOCKET_COUNTER_LIMIT = 100;
my $AUTH_PACKET_ID = 1;
my $SPLIT_END_PACKET_ID = 2;
#
# Constructor
#
sub new
{
my ($class_name, $server_object) = @_;
my ($self) = {};
bless($self, $class_name);
$self->{"rcon_socket"} = 0;
$self->{"server_object"} = $server_object;
Scalar::Util::weaken($self->{"server_object"});
$self->{"auth"} = 0;
$self->{"refresh_socket_counter"} = 0;
$self->{"packet_id"} = 10;
return $self;
}
sub execute
{
my ($self, $command, $splitted_answer) = @_;
if ($::g_stdin == 0) {
my $answer = $self->sendrecv($command, $splitted_answer);
if ($answer =~ /bad rcon_password/i) {
&::printEvent("TRCON", "Bad Password");
}
return $answer;
}
}
sub get_auth_code
{
my ($self, $id) = @_;
my $auth = 0;
if ($id == $AUTH_PACKET_ID) {
&::printEvent("TRCON", "Rcon password accepted");
$auth = 1;
$self->{"auth"} = 1;
} elsif( $id == -1) {
&::printEvent("TRCON", "Rcon password refused");
$self->{"auth"} = 0;
$auth = 0;
} else {
&::printEvent("TRCON", "Bad password response id=$id");
$self->{"auth"} = 0;
$auth = 0;
}
return $auth;
}
sub sendrecv
{
my ($self, $msg, $splitted_answer) = @_;
my $rs_counter = $self->{"refresh_socket_counter"};
if ($rs_counter % $REFRESH_SOCKET_COUNTER_LIMIT == 0) {
if ($self->{"rcon_socket"} > 0) {
shutdown($self->{"rcon_socket"}, 2);
$self->{"rcon_socket"} = 0;
}
my $server_object = $self->{"server_object"};
$self->{"rcon_socket"} = IO::Socket::INET->new(
Proto=>"tcp",
PeerAddr=>$server_object->{address},
PeerPort=>$server_object->{port},
);
if (!$self->{"rcon_socket"}) {
&::printEvent("TRCON", "Cannot setup TCP socket on ".$server_object->{address}.":".$server_object->{port}.": $!");
}
$self->{"refresh_socket_counter"} = 0;
$self->{"auth"} = 0;
}
my $r_socket = $self->{"rcon_socket"};
my $server = $self->{"server_object"};
my $auth = $self->{"auth"};
my $response = "";
my $packet_id = $self->{"packet_id"};
if (($r_socket) && ($r_socket->connected() )) {
if ($auth == 0) {
&::printEvent("TRCON", "Trying to get rcon access (auth)");
if ($self->send_rcon($AUTH_PACKET_ID, $SERVERDATA_AUTH, $server->{rcon}, "")) {
&::printEvent("TRCON", "Couldn't send password");
return;
}
my ($id, $command, $response) = $self->recieve_rcon($AUTH_PACKET_ID);
if($command == $SERVERDATA_AUTH_RESPONSE) {
$auth = $self->get_auth_code($id);
} elsif (($command == $SERVERDATA_RESPONSE_VALUE) && ($id == $AUTH_PACKET_ID)) {
#Source servers sends one junk packet during the authentication step, before it responds
# with the correct authentication response.
&::printEvent("TRCON", "Junk packet from Source Engine");
my ($id, $command, $response) = $self->recieve_rcon($AUTH_PACKET_ID);
$auth = $self->get_auth_code($id);
}
}
if ($auth == 1) {
$self->{"refresh_socket_counter"}++;
$self->send_rcon($packet_id, $SERVERDATA_EXECCOMMAND, $msg);
if ($splitted_answer > 0) {
$self->send_rcon($SPLIT_END_PACKET_ID, $SERVERDATA_EXECCOMMAND, "");
}
my ($id, $command, $response) = $self->recieve_rcon($packet_id, $splitted_answer);
$self->{"packet_id"}++;
if ($self->{"packet_id"} > 32767) {
$self->{"packet_id"} = 10;
}
return $response;
}
} else {
$self->{"refresh_socket_counter"} = 0;
}
return;
}
#
# Send a package
#
sub send_rcon
{
my ($self, $id, $command, $string1, $string2) = @_;
my $data = pack("VVZ*Z*", $id, $command, $string1, $string2);
my $size = length($data);
if($size > 4096) {
&::printEvent("TRCON", "Command to long to send!");
return 1;
}
$data = pack("V", $size).$data;
my $r_socket = $self->{"rcon_socket"};
if ($r_socket && $r_socket->connected() && $r_socket->peeraddr()) {
$r_socket->send($data, 0);
return 0;
} else {
$self->{"refresh_socket_counter"} = 0;
}
return 1;
}
#
# Recieve a package
#
sub recieve_rcon
{
my ($self, $packet_id, $splitted_answer) = @_;
my ($size, $id, $command, $msg);
my $tmp = "";
my $r_socket = $self->{"rcon_socket"};
my $server = $self->{"server_object"};
my $auth = $self->{"auth"};
my $packet_id = $self->{"packet_id"};
if (($r_socket) && ($r_socket->connected() )) {
if(IO::Select->new($r_socket)->can_read($TIMEOUT)) { # $TIMEOUT seconds timeout
$r_socket->recv($tmp, 1500);
$size = unpack("V", substr($tmp, 0, 4));
if ($size == 0) {
$self->{"refresh_socket_counter"} = 0;
return (-1, -1, -1);
}
$id = unpack("V", substr($tmp, 4, 4));
$command = unpack("V", substr($tmp, 8, 4));
if ($id == $packet_id) {
$tmp = substr($tmp, 12, length($tmp)-12);
if ($splitted_answer > 0) {
my $last_packet_id = $id;
while ($last_packet_id != $SPLIT_END_PACKET_ID) {
if(IO::Select->new($r_socket)->can_read($TIMEOUT)) {
$r_socket->recv($split_data, 1500);
my $split_size = unpack("V", substr($split_data, 0, 4));
my $split_id = unpack("V", substr($split_data, 4, 4));
my $split_command = unpack("V", substr($split_data, 8, 4));
if ($split_id == $last_packet_id) {
$split_data = substr($split_data, 12, length($split_data)-12);
}
if (!defined($split_id)){
$last_packet_id = $SPLIT_END_PACKET_ID;
} else {
$last_packet_id = $split_id;
}
$tmp .= $split_data;
} else {
&::printNotice("TRCON", "Multiple packet error");
$last_packet_id = $SPLIT_END_PACKET_ID;
}
}
}
if (length($tmp) > 0) {
$tmp .= "\x00";
my ($string1, $string2) = unpack("Z*Z*", $tmp);
$msg = $string1.$string2;
} else {
$msg = "";
}
}
return ($id, $command, $msg);
} else {
$self->{"refresh_socket_counter"} = 0;
return (-1, -1, -1);
}
} else {
$self->{"refresh_socket_counter"} = 0;
return (-1, -1, -1);
}
}
#
# Get error message
#
sub error
{
my ($self) = @_;
return $self->{"rcon_error"};
}
#
# Parse "status" command output into player information
#
sub getPlayers
{
my ($self) = @_;
my $status = $self->execute("status", 1);
if (!$status)
{
return ("", -1, "", 0);
}
my @lines = split(/[\r\n]+/, $status);
my %players;
# HL2 standard
# userid name uniqueid connected ping loss state adr
# 187 ".:[SoV]:.Evil Shadow" STEAM_0:1:6200412 13:48 97 0 active 213.10.196.229:24085
# L4D
# userid name uniqueid connected ping loss state rate adr
# 2 1 "psychonic" STEAM_1:1:4153990 00:45 68 1 active 20000 192.168.5.115:27006
foreach my $line (@lines)
{
if ($line =~ /^\#\s*
(\d+)\s+ # userid
(?:\d+\s+|) # extra number in L4D, not sure what this is??
"(.+)"\s+ # name
(.+)\s+ # uniqueid
([\d:]+)\s+ # time
(\d+)\s+ # ping
(\d+)\s+ # loss
([A-Za-z]+)\s+ # state
(?:\d+\s+|) # rate (L4D only)
([^:]+): # addr
(\S+) # port
$/x)
{
my $userid = $1;
my $name = $2;
my $uniqueid = $3;
my $time = $4;
my $ping = $5;
my $loss = $6;
my $state = $7;
my $address = $8;
my $port = $9;
$uniqueid =~ s/^STEAM_[0-9]+?\://i;
# &::printEvent("DEBUG", "USERID: '$userid', NAME: '$name', UNIQUEID: '$uniqueid', TIME: '$time', PING: '$ping', LOSS: '$loss', STATE: '$state', ADDRESS:'$address', CLI_PORT: '$port'", 1);
if ($::g_mode eq "NameTrack") {
$players{$name} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
} elsif ($::g_mode eq "LAN") {
$players{$address} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
} else {
$players{$uniqueid} = {
"Name" => $name,
"UserID" => $userid,
"UniqueID" => $uniqueid,
"Time" => $time,
"Ping" => $ping,
"Loss" => $loss,
"State" => $state,
"Address" => $address,
"ClientPort" => $port
};
}
}
}
return %players;
}
sub getServerData
{
my ($self) = @_;
my $status = $self->execute("status", 1);
my $server_object = $self->{server_object};
my $game = $server_object->{play_game};
my @lines = split(/[\r\n]+/, $status);
my $servhostname = "";
my $map = "";
my $max_players = 0;
my $difficulty = 0;
foreach my $line (@lines)
{
if ($line =~ /^\s*hostname\s*:\s*([\S].*)$/)
{
$servhostname = $1;
}
elsif ($line =~ /^\s*map\s*:\s*([\S]+).*$/)
{
$map = $1;
}
elsif ($line =~ /^\s*players\s*:\s*\d+.+\((\d+)\smax.*$/)
{
$max_players = $1;
}
}
if ($game == L4D()) {
$difficulty = $self->getDifficulty();
}
return ($servhostname, $map, $max_players, $difficulty);
}
sub getVisiblePlayers
{
my ($self) = @_;
my $status = $self->execute("sv_visiblemaxplayers");
my @lines = split(/[\r\n]+/, $status);
my $max_players = -1;
foreach my $line (@lines)
{
# "sv_visiblemaxplayers" = "-1"
# - Overrides the max players reported to prospective clients
if ($line =~ /^\s*"sv_visiblemaxplayers"\s*=\s*"([-0-9]+)".*$/x)
{
$max_players = $1;
}
}
return ($max_players);
}
my %l4d_difficulties = (
'Easy' => 1,
'Normal' => 2,
'Hard' => 3,
'Impossible' => 4
);
sub getDifficulty
{
#z_difficulty
#"z_difficulty" = "Normal"
# game replicated
# - Difficulty of the current game (Easy, Normal, Hard, Impossible)
my ($self) = @_;
my $zdifficulty = $self->execute("z_difficulty");
my @lines = split(/[\r\n]+/, $zdifficulty);
foreach my $line (@lines)
{
if ($line =~ /^\s*"z_difficulty"\s*=\s*"([A-Za-z]+)".*$/x)
{
if (exists($l4d_difficulties{$1}))
{
return $l4d_difficulties{$1};
}
}
}
return 0;
}
#
# Get information about a player by userID
#
sub getPlayer
{
my ($self, $uniqueid) = @_;
my %players = $self->getPlayers();
if (defined($players{$uniqueid}))
{
return $players{$uniqueid};
}
else
{
$self->{"error"} = "No such player # $uniqueid";
return 0;
}
}
1;
# end

1282
scripts/hlstats-awards.pl Normal file

File diff suppressed because it is too large Load Diff

374
scripts/hlstats-resolve.pl Normal file
View File

@ -0,0 +1,374 @@
#!/usr/bin/perl
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
##
## Settings
##
# $opt_configfile - Absolute path and filename of configuration file.
$opt_configfile = "./hlstats.conf";
# $opt_libdir - Directory to look in for local required files
# (our *.plib, *.pm files).
$opt_libdir = "./";
##
##
################################################################################
## No need to edit below this line
##
use Getopt::Long;
use IO::Socket;
use DBI;
require "$opt_libdir/ConfigReaderSimple.pm";
do "$opt_libdir/HLstats.plib";
$|=1;
Getopt::Long::Configure ("bundling");
##
## Functions
##
sub is_number ($) { ( $_[0] ^ $_[0] ) eq '0' }
#
# void printEvent (int code, string description)
#
# Logs event information to stdout.
#
sub printEvent
{
my ($code, $description, $update_timestamp) = @_;
if ($g_debug > 0)
{
if ($update_timestamp > 0)
{
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time());
my $timestamp = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
} else {
my $timestamp = $ev_timestamp;
}
print localtime(time) . "" unless ($timestamp);
if (is_number($code))
{
printf("%s: %21s - E%03d: %s\n", $timestamp, $s_addr, $code, $description);
} else {
printf("%s: %21s - %s: %s\n", $timestamp, $s_addr, $code, $description);
}
}
}
##
## MAIN
##
# Options
$opt_help = 0;
$opt_version = 0;
$opt_regroup = 0;
$db_host = "localhost";
$db_user = "";
$db_pass = "";
$db_name = "hlstats";
$g_dns_timeout = 5;
$g_debug = 0;
# Usage message
$usage = <<EOT
Usage: hlstats-resolve.pl [OPTION]...
Resolve player IP addresses to hostnames.
-h, --help display this help and exit
-v, --version output version information and exit
-d, --debug enable debugging output (-dd for more)
-n, --nodebug disables above; reduces debug level
--db-host=HOST database ip:port
--db-name=DATABASE database name
--db-password=PASSWORD database password (WARNING: specifying the
password on the command line is insecure.
Use the configuration file instead.)
--db-username=USERNAME database username
--dns-timeout=SEC timeout DNS queries after SEC seconds [$g_dns_timeout]
-r, --regroup only re-group hostnames--don't resolve any IPs
Long options can be abbreviated, where such abbreviation is not ambiguous.
Most options can be specified in the configuration file:
$opt_configfile
Note: Options set on the command line take precedence over options set in the
configuration file.
HLstats: http://www.hlstats.org
EOT
;
# Read Config File
if ($opt_configfile && -r $opt_configfile)
{
$conf = ConfigReaderSimple->new($opt_configfile);
$conf->parse();
%directives = (
"DBHost", "db_host",
"DBUsername", "db_user",
"DBPassword", "db_pass",
"DBName", "db_name",
"DNSTimeout", "g_dns_timeout",
"DebugLevel", "g_debug"
);
&doConf($conf, %directives);
}
else
{
print "-- Warning: unable to open configuration file '$opt_configfile'\n";
}
# Read Command Line Arguments
GetOptions(
"help|h" => \$opt_help,
"version|v" => \$opt_version,
"debug|d+" => \$g_debug,
"nodebug|n+" => \$g_nodebug,
"db-host=s" => \$db_host,
"db-name=s" => \$db_name,
"db-password=s" => \$db_pass,
"db-username=s" => \$db_user,
"dns-timeout=i" => \$g_dns_timeout,
"regroup|r" => \$opt_regroup
) or die($usage);
if ($opt_help)
{
print $usage;
exit(0);
}
if ($opt_version)
{
print "hlstats-resolve.pl (HLstats) $g_version\n"
. "Real-time player and clan rankings and statistics for Half-Life\n\n"
. "Copyright (C) 2001 Simon Garner\n"
. "This is free software; see the source for copying conditions. There is NO\n"
. "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
exit(0);
}
$g_debug -= $g_nodebug;
$g_debug = 0 if ($g_debug < 0);
if ($g_debug >= 2)
{
$opt_quiet = 0;
}
else
{
$opt_quiet = 1; # quiet name resolution
}
$g_dns_resolveip = 1;
# Startup
print "++ HLstats Resolve $g_version starting...\n\n";
# Connect to the database
print "-- Connecting to MySQL database '$db_name' on '$db_host' as user '$db_user' ... ";
$db_conn = DBI->connect(
"DBI:mysql:$db_name:$db_host",
$db_user, $db_pass
) or die ("Can't connect to MySQL database '$db_name' on '$db_host'\n" .
"$DBI::errstr\n");
print "connected OK\n";
# Print configuration
print "-- DNS timeout is $g_dns_timeout seconds. Debug level is $g_debug.\n";
# Main data routine
if ($opt_regroup)
{
my $result = &doQuery("
SELECT
id,
hostname
FROM
hlstats_Events_Connects
WHERE
hostname != ''
");
my $total = $result->rows;
if ($total > 0) {
print "\n++ Re-grouping hosts (total $total hostnames) ... ";
my $resultHG = &queryHostGroups();
if ($g_debug > 0)
{
print "\n\n";
}
else
{
print " ";
}
my $p = 1;
while( my($id, $hostname) = $result->fetchrow_array )
{
my $percent = ($p / $total) * 100;
my $hostgroup = &getHostGroup($hostname, $resultHG);
&execNonQuery("
UPDATE
hlstats_Events_Connects
SET
hostgroup='" . &quoteSQL($hostgroup) . "'
WHERE
id=$id
");
if ($g_debug > 0)
{
printf("-> (%3d%%) %50s = %s\n", $percent, $hostname, $hostgroup);
}
else
{
printf("\b\b\b\b%3d%%", $percent);
}
$p++;
}
print "\n" unless ($g_debug > 0);
} else {
print "\n++ No Connects found!\n";
}
}
else
{
my $result = &doQuery("
SELECT
DISTINCT ipAddress,
hostname
FROM
hlstats_Events_Connects
");
my $total = $result->rows;
if ($total > 0) {
print "\n++ Resolving IPs and re-grouping hosts (total $total connects) ... ";
my $resultHG = &queryHostGroups();
if ($g_debug > 0)
{
print "\n\n";
}
else
{
print " ";
}
my $p = 1;
while( my($ipAddress, $hostname) = $result->fetchrow_array )
{
my $percent = ($p / $total) * 100;
if ($hostname eq "")
{
$hostname = &resolveIp($ipAddress, $opt_quiet);
}
my $hostgroup = &getHostGroup($hostname, $resultHG);
&execNonQuery("
UPDATE
hlstats_Events_Connects
SET
hostname='$hostname',
hostgroup='" . &quoteSQL($hostgroup) . "'
WHERE
ipAddress='$ipAddress'
");
if ($g_debug > 0)
{
printf("-> (%3d%%) %15s = %50s = %s\n", $percent, $ipAddress, $hostname, $hostgroup);
}
else
{
printf("\b\b\b\b%3d%%", $percent);
}
$p++;
}
print "\n" unless ($g_debug > 0);
} else {
print "\n++ No Connects found!\n";
}
}
print "\n++ Operation complete.\n";
exit(0);

83
scripts/hlstats.conf Normal file
View File

@ -0,0 +1,83 @@
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
##
## Database Settings
##
# DBHost - Database server "address" or "address:port". Address can be an IP or
# a hostname. The default MySQL port is 3306 (tcp).
DBHost ""
# DBUsername - User to connect to the database as.
DBUsername ""
# DBPassword - Password for the database user.
DBPassword ""
# DBName - Name of the database to use.
DBName ""
##
## UDP Socket Settings (should match "logaddress ip port" on the game servers)
##
# BindIP - IP address to bind to (leave empty to use all interfaces).
BindIP ""
# Port - Port to listen on for log data from the game servers. this is also valid for proxy-daemon.pl
Port 27500
##
## Cpanel hack
##
## Set this to 1 if you use cpanel and need to use a user-installed Perl module
CpanelHack 0
##
## Event Queue
##
## Number of each type of events to queue before inserting events of that type
## (larger installs may try raising this for better performance
EventQueueSize 10
# DebugLevel - Set this to 1 to have debugging information printed on stdout.
# Set higher for even more debugging information. Set to 0 for
# quiet operation. It is recommended that you set this to 1 when
# first configuring HLstats, to help diagnose any problems.
DebugLevel 1

3626
scripts/hlstats.pl Normal file

File diff suppressed because it is too large Load Diff

456
scripts/proxy-daemon.pl Normal file
View File

@ -0,0 +1,456 @@
#!/usr/bin/perl
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
use strict;
use DBI;
use IO::Socket;
use IO::Select;
use Getopt::Long;
use Time::Local;
no strict 'vars';
##
## Settings
##
# $opt_configfile - Absolute path and filename of configuration file.
$opt_configfile = "./hlstats.conf";
# $opt_libdir - Directory to look in for local required files
# (our *.plib, *.pm files).
$opt_libdir = "./";
$heartbeat = 30;
##
##
################################################################################
## No need to edit below this line
##
require "$opt_libdir/ConfigReaderSimple.pm";
do "$opt_libdir/HLstats.plib";
$|=1;
Getopt::Long::Configure ("bundling");
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";
# Variables
my %srv_list = ();
my ($datagram,$flags);
my $oldtime = (time + $heartbeat);
$usage = <<EOT
Usage: hlstats.pl [OPTION]...
Collect statistics from one or more Half-Life2 servers for distribution
to sub-daemons (hlstats.pl).
-h, --help display this help and exit
-d, --debug enable debugging output (-dd for more)
-c, --configfile Specific configfile to use, settings in this file can't
be overided with commandline settings.
HLstatsX: Community Edition http://www.hlxcommunity.com
EOT
;
# Read Config File
if ($opt_configfile && -r $opt_configfile) {
$conf = ConfigReaderSimple->new($opt_configfile);
$conf->parse();
%directives = (
"DBHost", "db_host",
"DBUsername", "db_user",
"DBPassword", "db_pass",
"DBName", "db_name",
"BindIP", "s_ip",
"Port", "proxy_port",
"DebugLevel", "g_debug",
);
&doConf($conf, %directives);
} else {
&printEvent("CONFIG", "-- Warning: unable to open configuration file '$opt_configfile'", 1);
}
# Read Command Line Arguments
GetOptions(
"help|h" => \$opt_help,
"configfile|c=s" => \$configfile,
"debug|d+" => \$g_debug
) or die($usage);
if ($opt_help) {
print $usage;
exit(0);
}
if ($configfile && -r $configfile) {
$conf = '';
$conf = ConfigReaderSimple->new($configfile);
$conf->parse();
&doConf($conf, %directives);
}
#
# assignDaemon(string ipaddr, string ipport, hash daemon, hash srv_list)
#
# Round-Robin kind of way of spreading the load to different daemons.
#
sub assignDaemon
{
my ($ipaddr, $ipport, $daemon, $srv_list) = @_;
my $next = "";
if (defined($$srv_list{'rr-next'})) {
$next = $$srv_list{'rr-next'};
} else {
$next = 0;
}
my $max = keys %$daemon;
if (!defined($$srv_list{$ipaddr}{$ipport})) {
if ($next eq $max) {
$next = 1;
} else {
$next++;
}
$$srv_list{'rr-next'} = $next;
$$srv_list{$ipaddr}{$ipport}{'dest_ip'} = $$daemon{$next}{'ip'};
$$srv_list{$ipaddr}{$ipport}{'dest_port'} = $$daemon{$next}{'port'};
}
return;
}
#
# checkHeartbeat (hash daemon, string proxy_key)
#
# Prints and update the state of the perl daemons, if they are up or not.
#
sub checkHeartbeat
{
my ($daemon, $proxy_key) = @_;
my $state = '';
foreach my $key (keys(%$daemon)) {
my $value = $$daemon{$key};
my $socket = IO::Socket::INET->new( Proto=>"udp",
PeerHost=>$$daemon{$key}{'ip'},
PeerPort=>$$daemon{$key}{'port'}
);
$packet = "C;HEARTBEAT;";
$socket->send("PROXY Key=$proxy_key PROXY $packet");
if(IO::Select->new($socket)->can_read(4)) { # 4 second timeout
$socket->recv($msg,1024);
if ($msg =~ /Heartbeat OK/) {
$state = "up";
} else {
$state = "down";
}
}
if ($$daemon{$key}{'curstate'} eq "") {
$$daemon{$key}{'curstate'} = "n/a";
}
$$daemon{$key}{'oldstate'} = $$daemon{$key}{'curstate'};
$$daemon{$key}{'curstate'} = $state;
&printEvent("HEARTBEAT", "Sending HB to $$daemon{$key}{'ip'}:$$daemon{$key}{'port'}... state: $$daemon{$key}{'curstate'} (old: $$daemon{$key}{'oldstate'})", 1);
$state = '';
}
return;
}
#
# string retunrServerList(hash srv_list)
#
# Return a list of servers to requestor (udp package C;SERVERLIST).
#
sub returnServerList
{
my ($srv_list) = @_;
#$srv_list{$ipaddr}{$ipport}{'dest_ip'}
for my $ip (keys(%srv_list)) {
for my $port (keys(%{$srv_list{$ip}})) {
$msg = $msg . "$ip:$port -> $srv_list{$ip}{$port}{'dest_ip'}:$srv_list{$ip}{$port}{'dest_port'}\n";
}
}
return $msg;
}
#
# string theTime(int sec, int min, int hour, int mday, int year, int wday, int yday, int isdst)
#
# Makes a pretty timestampformat to output
#
sub theTime
{
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year = $year + 1900;
$mon = $mon + 1;
if ($mon <= 9) { $mon = "0$mon"; }
if ($mday <= 9) { $mday = "0$mday"; }
if ($hour <= 9) { $hour = "0$hour"; }
if ($min <= 9) { $min = "0$min"; }
if ($sec <= 9) { $sec = "0$sec"; }
my $time = "[$year-$mon-$mday $hour:$min:$sec] ";
return $time;
}
#
# string reloadDaemon(hash daemon, string proxy_key)
#
# Sends reload package to all daemons specified in hlstats.Options.Proxy_Daemons
#
sub reloadDaemon
{
my ($daemon, $proxy_key) = @_;
my $fake_ip = "127.0.0.1";
my $fake_port = "30000";
my $msg = '';
$packet = "C;RELOAD;";
foreach my $key (keys(%$daemon)) {
if ($$daemon{$key}{'curstate'} eq "up") {
&printEvent("CONTROL", "Sending RELOAD packet to $$daemon{$key}{'ip'}:$$daemon{$key}{'port'}", 1);
$msg = $msg . &theTime() . "Sending RELOAD packet to $daemon{$key}{'ip'}:$daemon{$key}{'port'}\n";
# Sedning actual message to the daemon.
my $cmd = IO::Socket::INET->new( Proto=>"udp",
PeerHost=>$$daemon{$key}{'ip'},
PeerPort=>$$daemon{$key}{'port'}
);
$cmd->send("PROXY Key=$proxy_key PROXY $packet");
}
}
return $msg;
}
#
# string getProxyKey ()
#
# Get the value for Proxy_Key
#
sub getProxyKey
{
my $query = "SELECT `value` FROM hlstats_Options WHERE `keyname` = 'Proxy_Key'";
my $result = &doQuery($query);
my ($proxy_key) = $result->fetchrow_array;
$result->finish;
return $proxy_key;
}
sub is_number ($) { ( $_[0] ^ $_[0] ) eq '0' }
############## Main program ##############
$g_stdin = 0;
# Connect yo mysql DB to get required settings
&doConnect();
my $proxy_key = &getProxyKey();
# Get the daemons you will use
$query = "SELECT `value` FROM hlstats_Options WHERE `keyname` = 'Proxy_Daemons'";
$result = &doQuery($query);
my ($daemonlist) = $result->fetchrow_array;
$result->finish;
my @proxy_daemons = split(/,/, $daemonlist);
my $total_daemons = scalar(@proxy_daemons);
my %daemon = ();
my $i = 1;
while ($i <= $total_daemons) {
($daemon{$i}{'ip'}, $daemon{$i}{'port'}) = split(/:/, $proxy_daemons[$i-1]);
$daemon{$i}{'oldstate'} = "";
$daemon{$i}{'curstate'} = "";
$i++;
}
# Setting up the proxy port to listen on.
my $server = IO::Socket::INET->new( LocalPort=>$proxy_port,
Proto=>"udp"
) or die "Can't create UDP server: $@";
# It went ok, lets start recive messages...
&printEvent("DAEMON", "HlstatsX Proxy Daemon up and running on port: $proxy_port, key: $proxy_key", 1);
# Do initial heartbeat check.
&checkHeartbeat(\%daemon, $proxy_key);
# Reload all child daemons config
&reloadDaemon(\%daemon, $proxy_key);
while ($server->recv($datagram,1024,$flags)) {
my $control = 0;
# Checks the subdaemons every 30 sec if they are alive.
# the interval can be changed by modify $heartbeat value in beginning of script.
if (time > $oldtime) {
&checkHeartbeat(\%daemon, $proxy_key);
$oldtime = (time + $heartbeat);
}
my $ipaddr = $server->peerhost;
my $ipport = $server->peerport;
if ($ipaddr eq "127.0.0.1" && $datagram =~/C;HEARTBEAT;/) {
$control = 1;
$msg = '';
$msg = "Heartbeat OK";
&printEvent("CONTROL", "Sending Heartbeat to $ipaddr:$ipport", 1);
} elsif ($ipaddr eq "127.0.0.1" && $datagram =~/C;SERVERLIST;/) {
$control = 1;
$msg = '';
$msg = returnServerList($srv_list);
$msg = "ServerList\n$msg";
&printEvent("CONTROL", "Sending Serverlist to $ipaddr:$ipport", 1);
} elsif ($ipaddr eq "127.0.0.1" && $datagram =~/C;RELOAD;/) {
$control = 1;
$msg = '';
$msg = &reloadDaemon($daemon);
}
if ($ipaddr eq "127.0.0.1" && $control == 1) {
# Sending actual message to the daemon.
my $dest = sockaddr_in($ipport, inet_aton($ipaddr));
my $bytes = send($server, $msg, 0, $dest);
next;
}
if ($datagram =~ /PROXY Key=(.+) (.*)PROXY (.+)/) {
if ($proxy_key eq $1) {
if ($3 =~ /C;HEARTBEAT;/) {
$msg = '';
$msg = "Heartbeat OK";
&printEvent("CONTROL", "Sending Heartbeat to $ipaddr:$ipport", 1);
} elsif ($3 =~ /C;SERVERLIST;/) {
$msg = '';
$msg = returnServerList($srv_list);
$msg = "ServerList\n$msg";
&printEvent("CONTROL", "Sending Serverlist to $ipaddr:$ipport", 1);
&printEvent("CONTROL", $msg, 1);
} elsif ($3 =~ /C;RELOAD;/) {
$msg = '';
$msg = &reloadDaemon($daemon);
}
} else {
$msg = "FAILED PROXY REQUEST ($ipaddr:$ipport)\n";
&printEvent("E403", "Sending FAILED PROXY REQUEST to $ipaddr:$ipport", 1);
}
# Sedning actual message to the daemon.
my $dest = sockaddr_in($ipport, inet_aton($ipaddr));
my $bytes = send($server, $msg, 0, $dest);
next;
}
if (defined($srv_list{$ipaddr}{$ipport})) {
# Check the oldstate, curstate of your logging daemon
foreach my $key (keys %daemon) {
if ($srv_list{$ipaddr}{$ipport}{'dest_ip'} eq $daemon{$key}{'ip'} && $srv_list{$ipaddr}{$ipport}{'dest_port'} eq $daemon{$key}{'port'}) {;
if ($daemon{$key}{'curstate'} eq "up" && $daemon{$key}{'oldstate'} eq "down") {
# Recovering, should do a reload of some kind here.
%srv_list = ();
} elsif ($daemon{$key}{'curstate'} eq "down" && $daemon{$key}{'oldstate'} eq "up") {
# Daemon died, assing a new daemon to server
delete $srv_list{$ipaddr}{$ipport};
($daemon, $srv_list) = &assignDaemon($ipaddr, $ipport, $daemon, $srv_list);
&printEvent("BALANCE", "down - up: Re-Assing daemon $srv_list{$ipaddr}{$ipport}{'dest_ip'}:$srv_list{$ipaddr}{$ipport}{'dest_port'} to $ipaddr:$ipport", 1);
} elsif ($daemon{$key}{'curstate'} eq "down" && $daemon{$key}{'oldstate'} eq "down") {
# DOWN, should already reassinged the daemon.
delete $srv_list{$ipaddr}{$ipport};
($daemon, $srv_list) = &assignDaemon($ipaddr, $ipport, $daemon, $srv_list);
&printEvent("BALANCE", "down-down: Re-Assing daemon $srv_list{$ipaddr}{$ipport}{'dest_ip'}:$srv_list{$ipaddr}{$ipport}{'dest_port'} to $ipaddr:$ipport", 1);
} elsif ($daemon{$key}{'curstate'} eq "down" && $daemon{$key}{'oldstate'} eq "n/a") {
# Daemon down when we started proxy, assing another daemon.
delete $srv_list{$ipaddr}{$ipport};
($daemon, $srv_list) = &assignDaemon($ipaddr, $ipport, $daemon, $srv_list);
&printEvent("BALANCE", "down - na: Assing daemon $srv_list{$ipaddr}{$ipport}{'dest_ip'}:$srv_list{$ipaddr}{$ipport}{'dest_port'} to $ipaddr:$ipport from down/na", 1);
}
}
}
} else {
# Assign a logging daemon for your server:port
delete $srv_list{$ipaddr}{$ipport};
&assignDaemon($ipaddr, $ipport, \%daemon, \%srv_list);
&printEvent("BALANCE", "Assing daemon $srv_list{$ipaddr}{$ipport}{'dest_ip'}:$srv_list{$ipaddr}{$ipport}{'dest_port'} to $ipaddr:$ipport", 1);
}
if ($datagram =~ /.*rcon from.*: command "status".*/ || $datagram =~ /.*rcon from.*: command "stats".*/ || $datagram =~ /.*rcon from.*: command "".*/) {
# skip messages that looks like this, to ease the load on the sub daemons alittle
&printEvent("NOTICE", "Skipping message...", 1) if ($g_debug > 1);
} else {
if (defined($srv_list{$ipaddr}{$ipport}{'dest_ip'}) && defined($srv_list{$ipaddr}{$ipport}{'dest_port'})) {
$datagram =~ s/^.*RL /RL /g;
&printEvent("NOTICE", "Sending $datagram to daemon $srv_list{$ipaddr}{$ipport}{'dest_ip'}:$srv_list{$ipaddr}{$ipport}{'dest_port'}", 1) if ($g_debug > 1);
# Sedning actual message to the daemon.
my $forward = IO::Socket::INET->new( Proto=>"udp",
PeerHost=>$srv_list{$ipaddr}{$ipport}{'dest_ip'},
PeerPort=>$srv_list{$ipaddr}{$ipport}{'dest_port'}
);
$forward->send("PROXY Key=$proxy_key $ipaddr:".$ipport."PROXY $datagram");
}
}
}

791
scripts/run_hlstats Normal file
View File

@ -0,0 +1,791 @@
#!/bin/bash
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxce.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
#------------------------------------------------------------------------------
# Usage
# Information on how to use this script can be found on our wiki:
# http://wiki.hlxce.com
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Script Configuration
# These parameters allow you to adjust various functions of the daemon.
# In general, they should not need to be modified.
# Please visit our wiki for more information: http://wiki.hlxce.com
#------------------------------------------------------------------------------
# SCRIPTPATH:
# File system path to daemon and supporting files
# NOTE: This is only needed if the other scripts files will be in another directory.
# In general, NO TOUCHY! :)
SCRIPTPATH=.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# CONFFILE:
# Specifies the configuration file (relative to SCRIPTPATH) to use for the daemon
CONFFILE=hlstats.conf
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DAEMON:
# Specifies the daemon Perl script to be used
DAEMON=hlstats.pl
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# LOGDIR:
# Specifies the location to store logs
LOGDIR=${SCRIPTPATH}/logs
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# LOGDATE:
# Specifies the date format to use in log file names
LOGDATE_FORMAT=%Y-%m-%d_%H-%M-%S
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# PIDDIR:
# Specifies location to store daemon PID files
PIDDIR=${SCRIPTPATH}
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Nothing to modify below here
WEBSITE=http://www.hlxce.com
WIKI=http://wiki.hlxce.com
# Start output
echo
echo "HLstatsX:CE daemon control"
echo "${WEBSITE}"
echo "---------------------------"
# Change to directory of script
cd `dirname ${0}`
# Perform some initial checks before we encounter later errors
# Check if we can write to the SCRIPTPATH
if [ ! -w ${SCRIPTPATH} ]; then
echo "CRITICAL ERROR: Could not write to SCRIPTPATH: ${SCRIPTPATH}"
echo "Verify you have write access to this directory."
echo "Visit our wiki for more information: ${WIKI}."
exit 1
fi
# Check if the daemon perl script exists
if [ ! -f ${SCRIPTPATH}/${DAEMON} ]; then
echo "CRITICAL ERROR: Cannot access the daemon: ${DAEMON}"
echo "Verify that the daemon, and corresponding files, exist in ${SCRIPTPATH}"
echo "Visit our wiki for more information: ${WIKI}."
exit 1
fi
# Verify shebang line in daemon
SHEBANG=`head -n1 ${SCRIPTPATH}/${DAEMON}`
if [[ ${SHEBANG} =~ ^#! ]]; then
SHEBANG_BINARY=`echo "${SHEBANG}" | sed 's/^#!//'`
if [ ! -f ${SHEBANG_BINARY} ]; then
echo "CRITICAL ERROR: The path to Perl is incorrect in ${DAEMON}."
echo "Current Perl path in shebang: ${SHEBANG_BINARY}"
echo "Visit our wiki for more information: ${WIKI}."
echo
echo "Potential paths for Perl: "
echo `which perl`
exit 1
fi
else
echo "CRITICAL ERROR: The shebang line is incorrectly configured. Please verify that your shebang line is correct in ${DAEMON}."
echo "Current shebang line: ${SHEBANG}"
echo "Visit our wiki for more information: ${WIKI}."
exit 1
fi
# Create logdir if needed
if [ ! -d ${LOGDIR} ]; then
mkdir ${LOGDIR}
fi
# Make sure we can write to logdir
if [ ! -w ${LOGDIR} ]; then
echo "CRITICAL ERROR: Could not write to the log folder: ${LOGDIR}"
echo "Verify that you have write access to the log folder."
echo "Visit our wiki for more information: ${WIKI}."
exit 1
fi
# Daemon control functions
function start_daemon {
# This function handles the creation of a new daemon process.
# This function requires one parameter: PORT
# Returns:
# 0 - Daemon started
# 1 - Daemon failed to start
# 2 - Daemon already running
if [ ! $1 ]; then
echo "CRITICAL ERROR: No port was received on function start_daemon"
exit 1
else
local PORT=$1
fi
local LOG=${LOGDIR}/hlstats_${PORT}_`date +${LOGDATE_FORMAT}`
local PID=`get_pid ${PORT}`
# Check if a PID exists for this port number
if [ "${PID}" != "" ]; then
# PID exists -- check if the daemon is running.
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
# Daemon running -- nothing to do.
return 2
else
# Daemon not running -- remove pid.
remove_pidfile ${PORT}
fi
fi
# Start the daemon on requested port
echo -ne "Attempting to start HLstatsX:CE daemon on port ${PORT}..."
${SCRIPTPATH}/${DAEMON} --configfile=${CONFFILE} --port=${PORT} &> ${LOG} &
# Store PID in memory until we verify Daemon has launched
PID=$!
# Perform one quick check to see if PID is running
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
create_pidfile ${PORT} ${PID}
echo ""
return 0
else
# PID not detected in time, keep checking for 10 more seconds.
local i=1
while [ $i -le 10 ]
do
echo -ne " ${i}"
sleep 1
# Perform a kill check against saved PID
kill -0 ${PID} &> /dev/null
# Check results of pid test
if [ $? -eq 1 ]; then
# Process does not exist
let i++
if [ $i -eq 10 ]; then
# Daemon did not respond to start request within 10 seconds.
return 1
fi
else
# Daemon started successfully -- commit PID to file
create_pidfile ${PORT} ${PID}
echo ""
return 0
fi
done
fi
}
function stop_daemon {
# This function handles shutting a daemon down.
# This function requires one parameter: PORT.
# Returns:
# 0 - Daemon gracefully stopped
# 1 - Daemon forcefully stopped
# 2 - Daemon could not be stopped
# 3 - No daemon to stop or PID missing
if [ ! $1 ]; then
echo "CRITICAL ERROR: No port was received on function stop_daemon"
exit 1
else
local PORT=$1
fi
local PID=`get_pid ${PORT}`
if [ ${PID} -eq 0 ]; then
return 3
fi
# Attempt to stop the daemon
echo -n "Attempting graceful shutdown of HLstatsX:CE daemon on port ${PORT} "
kill -INT ${PID} &> /dev/null
if [ $? -ne 0 ]; then
# Daemon is not running, purge the PID.
remove_pidfile ${PORT}
echo ""
return 3
else
# Found running PID -- perform a quick check before entering loop
kill -0 ${PID} &> /dev/null
if [ $? -eq 1 ]; then
# Daemon stopped, remove PID
remove_pidfile ${PORT}
echo ""
return 0
else
local i=1
while [ $i -le 10 ]
do
echo -n " ${i}"
sleep 1
# Perform a kill check against saved PID
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
# Daemon still operating
let i++
else
# Daemon stopped, remove PID
remove_pidfile ${PORT}
echo ""
return 0
fi
done
fi
# Daemon did not respond to shutdown, attempt a forced kill
echo ""
echo "WARNING: Daemon did not respond to a graceful shut down. Forcing a shut down on port ${PORT} "
local i=1
while [ $i -le 5 ]
do
kill -KILL ${PID} &> /dev/null
echo -n " ${i}"
sleep 1
# Check if PID is still present
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
# Daemon still operating
let i++
else
# Daemon stopped successfully.
remove_pidfile ${PORT}
echo ""
return 1
fi
done
return 2
fi
}
function reload_daemon {
# This function handles reloading a daemon down.
# This function requires one parameter: PORT.
# Returns:
# 0 - Reload sent successfully
# 1 - Daemon not running or pid file missing
# Sanity check on incoming required parameter
if [ ! $1 ]; then
echo "CRITICAL ERROR: No port was received on function reload_daemon"
exit 1
else
local PORT=$1
fi
local PID=`get_pid ${PORT}`
# Check to verify the daemon is operational
if [ ${PID} -ne 0 ]; then
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
kill -HUP ${PID} &> /dev/null
return 0
else
return 1
fi
else
return 1
fi
}
function check_port {
# This function verifies user input on the port number
# One argument is required
# Returns:
# 0 - Valid input
# 1 - Invalid Input (non-digit or not in UDP port range)
if [ $1 ]; then
# Perform regex test on input
echo ${1} | grep -q '^[0-9]\{1,5\}$'
# Check if within range and if grep test was successful.
if [ $? -eq 0 ] && [ $1 -le 65535 ] && [ $1 -ge 1 ]; then
return 0
else
return 1
fi
fi
}
function get_status {
# This function performs a lookup for the PID on specified port and checks status
# Parameters:
# 1 - port
# Returns:
# 0 - PID is running
# 1 - PID is not running
# 2 - Invalid PID
if [ $1 ]; then
local PID=`get_pid ${1}`
if [ "${PID}" != "" ]; then
kill -0 ${PID} &> /dev/null
if [ $? -eq 0 ]; then
return 0
else
return 1
fi
else
return 2
fi
fi
}
function create_pidfile {
# This function will handle the creation of a PID file for a corresponding port
# Parameters required:
# 1 - port number
# 2 - PID
# Returns:
# 0 - PID saved
# 1 - Unable to save PID
if [[ $1 && $2 ]]; then
PIDFILE=${PIDDIR}/hlstats_${1}.pid
echo ${2} > ${PIDFILE}
if [ "`cat ${PIDFILE}`" -eq "${2}" ]; then
return 0
else
return 1
fi
fi
}
function remove_pidfile {
# This function will handle the deletion of a PID file for a corresponding port
# Parameters required:
# 1 - port number
# Returns:
# 0 - PID removed
# 1 - PID does not exist
if [ $1 ]; then
PIDFILE=${PIDDIR}/hlstats_${1}.pid
rm -f ${PIDFILE} &> /dev/null
if [ $? -eq 0 ]; then
return 0
else
return 1
fi
fi
}
function get_pid {
# This function will echo out the found pid and return 0, or return 1 if it finds nothing
# Parameters required:
# 1 - port number
# Output
# Requested PID on return 0
# Returns:
# 0 - PID number for corresponding process
# 1 - No PID file for specified port
if [ $1 ]; then
PIDFILE=${PIDDIR}/hlstats_${1}.pid
PID=`cat ${PIDFILE} 2> /dev/null`
if [ $? -eq 0 ]; then
echo ${PID}
return 0
else
return 1
fi
fi
}
# Cleanup old legacy run_hlstats stuff
# Check if hlstats.pid exists (original pid from legacy run_hlstats)
if [ -f ${PIDDIR}/hlstats.pid ]; then
echo "WARNING: A old PID file has been detected. To prevent further troubles this daemon will be shut down."
kill -KILL `cat ${PIDDIR}/hlstats.pid` &> /dev/null
sleep 1
# Check if PID is dead
i=1
while [ $i -le 5 ]
do
kill -0 `cat ${PIDDIR}/hlstats.pid` &> /dev/null
if [ $? -eq 0 ]; then
# Daemon still operating
let i++
sleep 1
else
# Daemon stopped successfully.
rm -f ${PIDDIR}/hlstats.pid
echo ""
echo "HLstatsX:CE daemon has been forcefully stopped."
echo "Please re-run this script to control your daemon."
exit
fi
done
fi
# Daemon control case switcher
case "$1" in
start)
# Usage: run_hlstats start <# of daemons> <first port number> <port increment number>
# All arguments are optional
# Defaults: # of Daemons = 1; First port number = 27500; Port increment number = 1
NUMDAEMONS=1
STARTPORT=27500
INCREMENT=1
# Get user-specified number of daemons
if [ $2 ]; then
NUMDAEMONS=$2
fi
if [ $3 ]; then
check_port $3
if [ $? -eq 0 ]; then
STARTPORT=$3
else
echo "CRITICAL ERROR: An invalid port number was specified."
exit 1
fi
fi
if [ $4 ]; then
INCREMENT=$4
fi
# Saving this for a future release -- right now this would prevent people from running run_hlstats every few minutes to make sure their daemon is operational.
#else
# # Lookup the highest currently used port number
# LASTPORT=`ls ${PIDDIR} | egrep 'hlstats_[0-9]{1,5}.pid' | egrep -o '[0-9]{1,5}' | tail -1`
# if [ "${LASTPORT}" != "" ]; then
# # We have currently running daemons, to take the current highest port number and increment it
# let STARTPORT=LASTPORT+INCREMENT
# fi
#
#fi
i=0
CURRENTPORT=${STARTPORT}
while [ ${i} -lt ${NUMDAEMONS} ]
do
start_daemon ${CURRENTPORT}
case $? in
0)
echo "Daemon successfully started on port ${CURRENTPORT}"
let CURRENTPORT=CURRENTPORT+INCREMENT
let i++
;;
1)
echo "CRITICAL ERROR: Unable to start daemon on port ${CURRENTPORT}"
exit 1
;;
2)
echo "Daemon is already running on port ${CURRENTPORT}"
let CURRENTPORT=CURRENTPORT+INCREMENT
let i++
;;
esac
done
;;
stop)
# Usage: run_hlstats stop <port>
# All arguments are optional
# Defaults: port = ALL
if [ $2 ]; then
check_port $2
if [ $? -eq 0 ]; then
PORT=$2
else
echo "CRITICAL ERROR: An invalid port number was specified."
exit 1
fi
else
PORT=0
fi
# Stop a single daemon
if [ ${PORT} -ne 0 ]; then
stop_daemon ${PORT}
case $? in
0)
echo "Daemon gracefully stopped on port ${PORT}"
exit 0
;;
1)
echo "Daemon forcefully stopped on port ${PORT}"
exit 0
;;
2)
echo "WARNING: Daemon could not be stopped on port ${PORT}"
exit 1
;;
3)
echo "No daemon running on port ${PORT} or PID file is missing."
exit 1
;;
esac
fi
# Stop all daemons
PORTS=`ls ${PIDDIR} | egrep 'hlstats_[0-9]{1,5}.pid' | egrep -o '[0-9]{1,5}'`
if [ $? -eq 0 ]; then
for port in ${PORTS} ; do
stop_daemon ${port}
case $? in
0)
echo "Daemon gracefully stopped on port ${port}"
;;
1)
echo "Daemon forcefully stopped on port ${port}"
;;
2)
echo "WARNING: Daemon could not be stopped on port ${port}"
;;
3)
echo "No daemon running on port ${port} or PID file is missing."
;;
esac
done
else
echo "No daemons found running, or PID files are missing."
exit 1
fi
;;
restart)
# Usage: run_hlstats restart <port>
# All arguments are optional
# Defaults: port = ALL
if [ $2 ]; then
check_port $2
if [ $? -eq 0 ]; then
PORT=$2
else
echo "CRITICAL ERROR: An invalid port number was specified."
exit 1
fi
else
PORT=0
fi
# Handle individual restart request
if [ ${PORT} -ne 0 ]; then
stop_daemon ${PORT}
case $? in
0 | 1 | 3)
start_daemon ${PORT}
if [ $? -eq 0 ]; then
echo "Daemon successfully restarted on port ${PORT}"
exit 0
else
echo "CRITICAL ERROR: Failed to restart daemon on port ${PORT}"
exit 1
fi
;;
2)
echo "WARNING: Daemon could not be stopped on port ${port}"
exit 1
;;
esac
fi
# Restart all PIDs
PORTS=`ls ${PIDDIR} | egrep 'hlstats_[0-9]{1,5}.pid' | egrep -o '[0-9]{1,5}'`
if [ $? -eq 0 ]; then
for port in ${PORTS} ; do
stop_daemon ${port}
case $? in
0 | 1 | 3)
start_daemon ${port}
if [ $? -eq 0 ]; then
echo "Daemon successfully restarted on port ${port}"
else
echo "WARNING: Failed to restart daemon on port ${port}"
fi
;;
2)
echo "WARNING: Daemon could not be stopped on port ${port}"
exit 1
;;
esac
done
else
echo "WARNING: No HLstatsX:CE daemons currently running."
exit 1
fi
;;
reload)
# Usage: run_hlstats reload <port>
# All arguments are optional
# Defaults: port = ALL
if [ $2 ]; then
check_port $2
if [ $? -eq 0 ]; then
PORT=$2
else
echo "CRITICAL ERROR: An invalid port number was specified."
exit 1
fi
else
PORT=0
fi
# Handle individual reload request
if [ ${PORT} -ne 0 ]; then
reload_daemon ${PORT}
if [ $? -eq 0 ]; then
echo "Successfully reloaded daemon running on port ${PORT}"
exit 0
else
echo "WARNING: Unable to reload daemon on port ${PORT} (daemon might not be running)"
exit 1
fi
fi
# Reload all PIDs
PORTS=`ls ${PIDDIR} | egrep 'hlstats_[0-9]{1,5}.pid' | egrep -o '[0-9]{1,5}'`
if [ "${PORTS}" != "" ]; then
for port in ${PORTS} ; do
reload_daemon ${port}
if [ $? -eq 0 ]; then
echo "Successfully reloaded daemon running on port ${port}"
else
echo "WARNING: Unable to reload daemon on port ${port} (daemon might not be running)"
fi
done
else
echo "WARNING: No HLstatsX:CE daemons currently running."
exit 1
fi
;;
status)
# Usage: run_hlstats status <port>
# All arguments are optional
# Defaults: port = ALL
if [ $2 ]; then
check_port $2
if [ $? -eq 0 ]; then
PORT=$2
else
echo "CRITICAL ERROR: An invalid port number was specified."
exit 1
fi
else
PORT=0
fi
# Handle individual status request
if [ ${PORT} -ne 0 ]; then
get_status ${PORT}
case $? in
0)
echo "Daemon on port ${PORT} is currently running."
exit 0
;;
1)
echo "A stale process was found for daemon on port ${PORT}."
exit 0
;;
2)
echo "There is no daemon running on port ${PORT}."
exit 0
;;
esac
fi
# Reload all PIDs
PORTS=`ls ${PIDDIR} | egrep 'hlstats_[0-9]{1,5}.pid' | egrep -o '[0-9]{1,5}'`
if [ "${PORTS}" != "" ]; then
for port in ${PORTS} ; do
get_status ${port}
case $? in
0)
echo "Daemon on port ${port} is currently running."
;;
1)
echo "A stale process was found for daemon on port ${port}. It has been removed."
;;
2)
echo "There is no daemon running on port ${port}."
;;
esac
done
else
echo "WARNING: No HLstatsX:CE daemons currently running."
exit 1
fi
;;
*)
echo "Usage"
echo "All optional arguments are in <>. The default is in ()."
echo ""
echo -e "\trun_hlstats start <number of daemons (1)> <starting port number (27500)> <port increment (1)>"
echo -e "\trun_hlstats stop <port # of daemon to stop (ALL)>"
echo -e "\trun_hlstats status <port # of daemon to check status of (ALL)>"
echo -e "\trun_hlstats restart <port # of daemon to restart (ALL)>"
echo -e "\trun_hlstats reload <port # of daemon to reload (ALL)>"
;;
esac
exit

50
scripts/run_hlstats_multi Normal file
View File

@ -0,0 +1,50 @@
#!/bin/bash
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# If you wish to run this script as a daemon script (in /etc/init.d, etc.)
# you must configure the "confdir" variable below.
# The other variables are optional and really should not be modified.
echo "
WARNING: run_hlstats_multi is deprecated as of 1.6.11.
If you need to start multiple daemons you should now use run_hlstats with the correct parameters.
For information run_hlstats, run:
./run_hlstats help
or visit http://wiki.hlxce.com/wiki/Controlling_the_HLXCE_daemon"
exit 0

151
scripts/run_proxy Normal file
View File

@ -0,0 +1,151 @@
#!/bin/bash
# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
#
# 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
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001 Simon Garner
#
# 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.
#
# For support and installation notes visit http://www.hlxcommunity.com
# If you wish to run this script as a daemon script (in /etc/init.d, etc.)
# you must configure the "confdir" variable below.
# The other variables are optional and really should not be modified.
# Set the path to the scripts folder (you should not need to modify this.)
confdir=.
# Set the configuration file for the daemon (you should not need to modify this.)
conffile=hlstats.conf
# Set the filename of the daemon to use (you should not need to modify this.)
daemonfile=proxy-daemon.pl
# Set where you want to log to. This is a directory inside of the confdir setting.
# (You should not need to modify this.)
logdir=logs
# Set the format of the log file
logfile=proxy`date +_%Y%m%d_%H-%M-%S`
# Set where to store PID files
piddir=${confdir}
# verify that we can see the daemon file
if [ ! -f ${confdir}/${daemonfile} ]; then
echo "Can't see the daemon. (${daemonfile})"
exit 1
fi
# verify that you have write access to the directories
if [ ! -w ${confdir} ]; then
echo "you need write access to ${confdir}"
exit 1
fi
# verify that you have a logs directory
if [ ! -d ${confdir}/${logdir} ];then
mkdir ${confdir}/${logdir}
fi
if [ ! -w ${confdir}/${logdir} ];then
echo "you need write access to ${confdir}/${logdir}"
exit 1
fi
# Grab out original directory so we can return after
origdir=`pwd`
# Move into configured directory
cd ${confdir}
case "$1" in
start)
# verify that we have a .conf file
if [ ! -f ${conffile} ]; then
echo "You're missing your configuration file. (${conffile})"
exit 1
fi
echo "Starting HLstatsX:CE...";
if [ -f ${piddir}/proxy-daemon.pid ]; then
kill -0 `cat ${piddir}/proxy-daemon.pid` >/dev/null 2>&1
if [ "$?" == "0" ]; then
echo "HLstatsX:CE already running!"
else
rm -rf ${piddir}/proxy-daemon.pid
./${daemonfile} --configfile=${conffile} > ${logdir}/${logfile} 2>&1 &
echo $! >${piddir}/proxy-daemon.pid
echo "PID file created"
echo "Started successfully"
fi
else
./${daemonfile} --configfile=${conffile} > ${logdir}/${logfile} 2>&1 &
echo $! >${piddir}/proxy-daemon.pid
echo "PID file created"
echo "Started successfully"
fi
;;
stop)
echo "Stopping HLstatsX:CE..."
kill -9 `cat ${piddir}/proxy-daemon.pid` >/dev/null 2>&1
if [ "$?" == "0" ]; then
rm -rf ${piddir}/proxy-daemon.pid
echo "Stopped successfully"
else
echo "No HLstatsX:CE running!"
fi
;;
restart)
echo "Restarting HLstatsX:CE..."
kill -9 `cat ${piddir}/proxy-daemon.pid` >/dev/null 2>&1
if [ "$?" == "0" ]; then
rm -rf ${piddir}/proxy-daemon.pid
./${daemonfile} --configfile=${conffile} > ${logdir}/${logfile} 2>&1 &
echo $! >${piddir}/proxy-daemon.pid
echo "PID file created"
echo "Restarted successfully"
else
echo "HLstatsX:CE"
if [ -f ${piddir}/proxy-daemon.pid ]; then
rm -rf ${piddir}/proxy-daemon.pid
fi
./${daemonfile} --configfile=${conffile} > ${logdir}/${logfile} 2>&1 &
echo $! >${piddir}/proxy-daemon.pid
echo "PID file created"
echo "Started successfully"
fi
;;
*)
echo "Usage: ./run_hlstats [ start | stop | restart ]"
;;
esac
# Return to original directory
cd ${origdir}
exit 0