The Death of Rats is LegacyWorlds' experimental multi detection tool.
Select page:
set_magic_quotes_runtime(false);
include('config.inc');
switch ($_GET['p']) {
case 'e': $page = 'execution'; break;
case 'sl': $page = 'singlelog'; break;
case 'sp': $page = 'signlepoints'; break;
case 'ml': $page = 'multilog'; break;
case 'mp': $page = 'multipoints'; break;
case 'al': $page = 'actions'; break;
case 'fp': $page = 'finalpoints'; break;
case 'il': $page = 'ingamelog'; break;
default: $page = "status"; break;
}
$pages = array(
'status' => array('s', 'Current status', 'showStatus'),
'actions' => array('al', 'Actions taken', 'showActionLog'),
'finalpoints' => array('fp', 'Decision points', 'showFinalPoints'),
'ingamelog' => array('il', 'In-game checks', 'showInGameChecks'),
'multipoints' => array('mp', 'Multiplayer points', 'showMultiPoints'),
'multilog' => array('ml', 'Multiplayer log', 'showMultiLog'),
'signlepoints' => array('sp', 'Single player points', 'showSinglePoints'),
'singlelog' => array('sl', 'Single player events', 'showSingleLog'),
'execution' => array('e', 'Execution log', 'showExecLog'),
);
foreach ($pages as $pName => $data) {
if ($pName == $page) {
echo "";
} else {
echo "";
}
echo $data[1];
if ($pName == $page) {
echo " ";
} else {
echo " ";
}
}
echo "
";
$func = $pages[$page][2];
$func();
function showStatus() {
?>
Current status
The Death of Rats is still in an experimental stage at this time, and no actual action is taken. What
it would do if it were fully enabled is logged on the "Actions taken" page nonetheless.
Most of the information it provides can be trusted, tho; however, if you suspect it sent a warning or "punished" a
player for no good reason, manual checks should be performed.
The following checks are performed:
- use of open proxies
- cookie deletion
- trying to log on with a banned account
- passwords shared between multiple accounts
- simple multiing, as well as pass sharing
- "vicious" multiing, implying that the cookies are cleared between each use
- in-game checks for donations, tech exchanges, gifts and sales, and planet retake after abandon
Checks for concurrent session from the same IP as well as more in-game checks (alliance, posts, messages,
TA list, battles) are still missing.
About the different pages
This tool consists in a few different pages which give different information about the Death of Rats' current status.
These pages are:
-
Actions taken: the log of all actions the Death of Rats performed. This includes sending
warnings and deciding to punish players.
-
Decision points: the current amount of points for each pair of players that has been investigated thoroughly
by the Death of Rats. Pairs with over 100 points will cause the Death of Rats to act.
-
In-game checks log: the latest 400 entries of the checks performed in-game on suspicious players as well
as the results of these checks.
-
Multiplayer points: the current amount of points for each pair of accounts that could be multiing or
abusing pass-sharing.
-
Multiplayer log: the latest 200 entries of the suspicious events detected between pairs of accounts.
-
Single player points: the current amount of points for each account that has performed suspicious actions.
While these points are normally not a problem, they influence multiplayer scores.
-
Single player log: the latest 200 suspicious events detected for single accounts.
-
Execution log: the latest 200 runs of the Death of Rats.
}
function showExecLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT * FROM main.dor_exec ORDER BY ts DESC LIMIT 200");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Previous 200 runs of the Death of Rats
This page shows the log of the previous 200 executions of the Death of Rats tick. The Changes column indicates
the amount of changes (connection records, password updates) examined; the Events column indicates the amount
of entries added to either the single player log or the multiplayer log.
Time & date |
Changes |
Events |
foreach ($entries as $entry) {
?>
=$entry['events'] ? "" : ""?>=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>=$entry['events'] ? "" : ""?> |
=$entry['events'] ? "" : ""?>=$entry['entries']?>=$entry['events'] ? "" : ""?> |
=$entry['events'] ? "" : ""?>=$entry['events']?>=$entry['events'] ? "" : ""?> |
}
?>
}
function showSingleLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a.name,l.message,l.ts FROM main.dor_single l, main.account a WHERE a.id = l.account AND a.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a.name ASC LIMIT 200");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Previous 200 single player log entries
This page shows the log of the previous 200 log entries generated for single players.
Time & date |
Account |
Message |
$messages = array(
"ASSHOLE" => "Tried to log on using a banned account",
"PROXY" => "Currently using an open proxy",
"CLCOOK-SIP" => "Cleared cookies from the same IP",
"CLCOOK-DIP" => "Cleared cookies from a different (but close) IP",
);
foreach ($entries as $entry) {
?>
=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
| =htmlentities($entry['name'])?> |
=$messages[$entry['message']]?> |
}
?>
}
function showSinglePoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a.name,l.points FROM main.dor_single_points l, main.account a WHERE a.id = l.account AND a.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Single player "badness points"
These points correspond to recent suspicious activities from active accounts.
Account |
Points |
foreach ($entries as $entry) {
?>
=htmlentities($entry['name'])?> |
=$entry['points']?> |
}
?>
}
function showInGameChecks() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a1.name as name1, a2.name as name2, l.message, l.ts, l.game FROM main.dor_ingame_check l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a1.name ASC, a2.name ASC LIMIT 400");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Latest 400 in-game checks log entries
This page shows the log of the latest 400 log entries generated by in-game checks on players. Events logged here
belong to different categories:
- Somewhat suspicious events: donations of less than €100,000; rejected tech offers
-
Suspicious events: donations of less than €1,000,000; pending tech offers; accepted techs offer with
a price greater than €1,000; planets taken by a player within 5 days of being abandonned by the other; sales
of planets or fleets.
-
Highly suspicious events: donations of less than €10,000,000; gifts; tech offers with a price lower
than €1,000.
-
Extremely suspicious events: donations of more than €10,000,000.
Time & date |
Game ID |
Account 1 |
Account 2 |
Message |
Count |
$messages = array(
"CHECK" => "Verifying accounts",
"VHSE" => "Extremely suspicious in-game events",
"HSE" => "Highly suspicious in-game events",
"SE" => "Suspicious in-game events",
"LSE" => "Somewhat suspicious in-game events"
);
foreach ($entries as $entry) {
list($message, $count) = explode('-', $entry['message']);
if ($message == 'CHECK') {
$count = "N/A";
}
?>
=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
| =$entry['game']?> |
=htmlentities($entry['name1'])?> |
=htmlentities($entry['name2'])?> |
=$messages[$message]?> |
=$count?> |
}
?>
}
function showMultiLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT (a1.id || ',' || a2.id) as id, a1.name as name1, a2.name as name2, l.message, l.ts FROM main.dor_multi l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a1.name ASC, a2.name ASC LIMIT 400");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
$displayed = array();
?>
Previous 200 multiplayer log entries
This page shows the log of the previous 200 log entries generated for pairs of players.
Time & date |
Account 1 |
Account 2 |
Message |
$messages = array(
"SIMPLE" => "Simple multiing / open pass sharing detected",
"SIMPLE-10" => "Simple multiing / open pass sharing detected (within 10 seconds!)",
"PASS" => "Accounts are using the same password",
"NOPASS" => "Accounts are no longer using the same password",
"VICIOUS-LP" => "Potential attempt to conceal pass-sharing",
"VICIOUS-MP" => "Probable attempt to conceal pass-sharing",
"VICIOUS-HP" => "Highly probable attempt to conceal pass-sharing",
);
foreach ($entries as $entry) {
$id = explode(',', $entry['id']);
sort($id);
$id = join(',', $id) . "-" . $entry['ts'] . "-" . $entry['message'];
if (in_array($id, $displayed)) {
continue;
}
$displayed[] = $id;
?>
=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
| =htmlentities($entry['name1'])?> |
=htmlentities($entry['name2'])?> |
=$messages[$entry['message']]?> |
}
?>
}
function showFinalPoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a1.name as name1, a2.name as name2, l.points FROM main.dor_final_points l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a1.name ASC, a2.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Final decision points
This page displays the current amount of points for each pair of players that has been investigated thoroughly
by the Death of Rats. Pairs will over 100 points will cause the Death of Rats to act.
Account 1 |
Account 2 |
Points |
foreach ($entries as $entry) {
?>
=htmlentities($entry['name1'])?> |
=htmlentities($entry['name2'])?> |
=$entry['points']?> |
}
?>
}
function showMultiPoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT (a1.id || ',' || a2.id) as id, a1.name as name1, a2.name as name2, l.points FROM main.dor_multi_points l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a1.name ASC, a2.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
$displayed = array();
?>
Multiplayer "badness points"
This page shows the list of "badness points" between pairs of accounts. The higher the badness points, the more likely
the accounts are multis.
Account 1 |
Account 2 |
Points |
foreach ($entries as $entry) {
$id = explode(',', $entry['id']);
sort($id);
$id = join(',', $id);
if (in_array($id, $displayed)) {
continue;
}
$displayed[] = $id;
?>
=htmlentities($entry['name1'])?> |
=htmlentities($entry['name2'])?> |
=$entry['points']?> |
}
?>
}
function showActionLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db,
"SELECT * FROM ("
. "SELECT a1.name AS name1, a2.name AS name2, l.ts AS ts, 'WARN' AS atype "
. "FROM main.dor_warning l, main.account a1, main.account a2 "
. "WHERE a1.id = l.account1 AND a2.id = l.account2 "
. "AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "UNION SELECT a1.name AS name1, a2.name AS name2, l.ts AS ts, 'PUNISH' AS atype "
. "FROM main.dor_warning l, main.account a1, main.account a2 "
. "WHERE a1.id = l.account1 AND a2.id = l.account2 "
. "AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED')"
. ") AS t ORDER BY t.ts DESC, t.name1 ASC, t.name2 ASC"
);
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
Actions performed by the Death of Rats
This page lists all the actions the Death of Rats has performed.
Time & date |
Account 1 |
Account 2 |
Message |
$messages = array(
"WARN" => "Warned player",
"PUNISH" => "Slaughtered player with a rat-sized scythe"
);
foreach ($entries as $entry) {
?>
=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
| =htmlentities($entry['name1'])?> |
=htmlentities($entry['name2'])?> |
=$messages[$entry['atype']]?> |
}
?>
}
?>