Add MultiAccount Detection, Add Push Protection Detection, Add register Default Gold

Add MultiAccount Detection, Add Push Protection Detection, Add register Default Gold
This commit is contained in:
novgorodschi catalin
2026-07-15 14:23:05 +03:00
parent 1925f45001
commit b87cf27396
23 changed files with 1798 additions and 8 deletions
+4 -4
View File
@@ -105,10 +105,6 @@ $editIcon = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke=
<tr><td>New Alliance & Embassy Mechanics <em class="tooltip">?<span class="classic">https://github.com/Shadowss/TravianZ/wiki/New-Alliance-&-Embassy-Mechanics</span></em></td><td><?php echo NEW_FUNCTIONS_EMBASSY_MECHANICS ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New forum post message <em class="tooltip">?<span class="classic">Enable (Disable) forum subscription messages</span></em></td><td><?php echo NEW_FUNCTIONS_FORUM_POST_MESSAGE ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>Tribes images in profile <em class="tooltip">?<span class="classic">Enable (Disable) displaying images of tribes</span></em></td><td><?php echo NEW_FUNCTIONS_TRIBE_IMAGES ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Huns <em class="tooltip">?<span class="classic">Enable (Disable) the Huns tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_HUNS') && NEW_FUNCTION_TRIBE_HUNS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Egyptians <em class="tooltip">?<span class="classic">Enable (Disable) the Egyptians tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_EGIPTEANS') && NEW_FUNCTION_TRIBE_EGIPTEANS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Spartans <em class="tooltip">?<span class="classic">Enable (Disable) the Spartans tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_SPARTANS') && NEW_FUNCTION_TRIBE_SPARTANS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Vikings <em class="tooltip">?<span class="classic">Enable (Disable) the Vikings tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_VIKINGS') && NEW_FUNCTION_TRIBE_VIKINGS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>MHs images in profile <em class="tooltip">?<span class="classic">Enable (Disable) displaying images of Multihunters</span></em></td><td><?php echo NEW_FUNCTIONS_MHS_IMAGES ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>Display artifact in profile <em class="tooltip">?<span class="classic">Enable (Disable) the display of the artifact</span></em></td><td><?php echo NEW_FUNCTIONS_DISPLAY_ARTIFACT ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>Display WoW in profile <em class="tooltip">?<span class="classic">Enable (Disable) the display of the wonder</span></em></td><td><?php echo NEW_FUNCTIONS_DISPLAY_WONDER ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
@@ -123,6 +119,10 @@ $editIcon = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke=
<tr><td>Server Milestones<em class="tooltip">?<span class="classic">Server Milestones</span></em></td><td><?php echo NEW_FUNCTIONS_MILESTONES ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>Server Medal Reset Timer<em class="tooltip">?<span class="classic">Server Medal Reset Timer</span></em></td><td><?php echo NEW_FUNCTIONS_MEDAL_RESET ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>T4 Hero (items, adventures, auction)<em class="tooltip">?<span class="classic">T4 Hero (items, adventures, auction)</span></em></td><td><?php echo NEW_FUNCTIONS_HERO_T4 ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Huns <em class="tooltip">?<span class="classic">Enable (Disable) the Huns tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_HUNS') && NEW_FUNCTION_TRIBE_HUNS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Egyptians <em class="tooltip">?<span class="classic">Enable (Disable) the Egyptians tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_EGIPTEANS') && NEW_FUNCTION_TRIBE_EGIPTEANS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Spartans <em class="tooltip">?<span class="classic">Enable (Disable) the Spartans tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_SPARTANS') && NEW_FUNCTION_TRIBE_SPARTANS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td>New Tribe: Vikings <em class="tooltip">?<span class="classic">Enable (Disable) the Vikings tribe</span></em></td><td><?php echo (defined('NEW_FUNCTION_TRIBE_VIKINGS') && NEW_FUNCTION_TRIBE_VIKINGS) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
</table>
</div>
+17
View File
@@ -287,6 +287,23 @@ if($_SESSION['access'] < 9) die(ACCESS_DENIED_ADMIN);
<option value="False" <?php if(!defined('NEW_FUNCTION_TRIBE_VIKINGS') || NEW_FUNCTION_TRIBE_VIKINGS == false) echo "selected";?>>False</option>
</select>
</td>
</tr>
<tr>
<td class="b">Registration Bonus Gold <em class="tooltip">?<span class="classic">Enable (Disable) a one-time gold bonus granted to every newly registered player at account creation (system accounts id&le;3 are skipped). The amount is set in the field below.</span></em>
<?php if (!defined('NEW_FUNCTION_REGISTRATION_GOLD')): ?><br><span style="color:#c0392b;font-size:11px;font-weight:normal;text-transform:none;">Not present in config.php yet &mdash; saving this form once will add it (defaults to False until then).</span><?php endif; ?>
</td>
<td>
<select name="new_function_registration_gold">
<option value="True" <?php if(defined('NEW_FUNCTION_REGISTRATION_GOLD') && NEW_FUNCTION_REGISTRATION_GOLD == true) echo "selected";?>>True</option>
<option value="False" <?php if(!defined('NEW_FUNCTION_REGISTRATION_GOLD') || NEW_FUNCTION_REGISTRATION_GOLD == false) echo "selected";?>>False</option>
</select>
</td>
</tr>
<tr>
<td class="b">Registration Bonus Gold &ndash; amount <em class="tooltip">?<span class="classic">How much gold each new player receives when the toggle above is True. Default: 200.</span></em></td>
<td>
<input type="number" min="0" step="1" name="new_function_registration_gold_value" value="<?php echo (defined('NEW_FUNCTION_REGISTRATION_GOLD_VALUE') ? (int) NEW_FUNCTION_REGISTRATION_GOLD_VALUE : 200); ?>">
</td>
</tr>
</tbody>
</table>
+168
View File
@@ -0,0 +1,168 @@
<?php
#################################################################################
## Filename : Admin/Templates/multiacc.tpl ##
## Type : Admin page - Multi-Account Detection ##
## Project : TravianZ ##
## License : TravianZ Project ##
#################################################################################
// Access: admins (9) and multihunters (8) only.
if (!isset($_SESSION['access']) || $_SESSION['access'] < MULTIHUNTER) {
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
return;
}
// Filters (GET). All optional.
$days = isset($_GET['days']) && ctype_digit((string)$_GET['days']) ? max(1, min(365, (int)$_GET['days'])) : MultiAccount::WINDOW_DAYS;
$minScore = isset($_GET['min']) && ctype_digit((string)$_GET['min']) ? max(0, min(100, (int)$_GET['min'])) : MultiAccount::MIN_REPORT_SCORE;
$focusUid = isset($_GET['focus']) && ctype_digit((string)$_GET['focus']) ? (int)$_GET['focus'] : 0;
$data = MultiAccount::riskPairs(['days' => $days, 'min_score' => $minScore, 'focus_uid' => $focusUid]);
$pairs = $data['pairs'];
?>
<style>
.mad-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
.mad-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
.mad-wrap h2 span{color:#f59e0b;}
.mad-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:820px;line-height:1.5;}
.mad-filter{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:12px 14px;display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end;margin-bottom:16px;}
.mad-filter label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:#94a3b8;margin-bottom:4px;}
.mad-filter input{background:#0b1220;border:1px solid #334155;border-radius:6px;color:#e2e8f0;padding:6px 8px;width:110px;}
.mad-filter button{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:8px 16px;cursor:pointer;}
.mad-filter a.reset{color:#94a3b8;font-size:11px;text-decoration:none;padding:8px 4px;}
.mad-meta{color:#64748b;font-size:11px;margin-bottom:10px;}
.mad-warn{background:#422006;border:1px solid #92400e;color:#fbbf24;border-radius:6px;padding:8px 12px;font-size:11px;margin-bottom:12px;}
.mad-table{width:100%;border-collapse:collapse;background:#0b1220;border:1px solid #1f2937;border-radius:8px;overflow:hidden;}
.mad-table th{background:#111827;text-align:left;padding:9px 10px;font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:#94a3b8;border-bottom:1px solid #1f2937;}
.mad-table td{padding:9px 10px;border-bottom:1px solid #14203a;vertical-align:top;}
.mad-table tr:hover td{background:#0f1a30;}
.mad-acc a{color:#e2e8f0;text-decoration:none;font-weight:bold;}
.mad-acc a:hover{color:#f59e0b;}
.mad-acc .uid{color:#475569;font-weight:normal;font-size:10px;}
.mad-acc .sub{display:block;margin-top:2px;}
.mad-acc .sub a{font-size:10px;color:#64748b;font-weight:normal;margin-right:8px;}
.mad-score{font-weight:bold;font-size:14px;}
.badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:.5px;}
.b-high{background:#7f1d1d;color:#fecaca;}
.b-med{background:#78350f;color:#fde68a;}
.b-low{background:#1e3a5f;color:#bfdbfe;}
.chips span{display:inline-block;background:#1e293b;color:#cbd5e1;border-radius:4px;padding:2px 7px;margin:2px 3px 0 0;font-size:10px;}
.mad-empty{padding:26px;text-align:center;color:#64748b;}
.mad-bar{height:6px;background:#1e293b;border-radius:3px;margin-top:4px;overflow:hidden;}
.mad-bar i{display:block;height:100%;}
</style>
<div class="mad-wrap">
<h2>Multi-Account <span>Detection</span></h2>
<p class="mad-intro">
Heuristic correlation of account pairs by shared IP, subnet, device/browser
fingerprint (User-Agent), overlapping login times, and resource-transfer flow.
This is a <b>risk score, not proof</b> &mdash; use it to prioritise which
pairs a human should investigate. Nothing is banned automatically.
</p>
<form method="get" action="admin.php" class="mad-filter">
<input type="hidden" name="p" value="multiacc">
<div>
<label>Window (days)</label>
<input type="number" name="days" min="1" max="365" value="<?php echo (int)$days; ?>">
</div>
<div>
<label>Min score</label>
<input type="number" name="min" min="0" max="100" value="<?php echo (int)$minScore; ?>">
</div>
<div>
<label>Focus on UID (optional)</label>
<input type="number" name="focus" min="0" value="<?php echo $focusUid ?: ''; ?>">
</div>
<button type="submit">Analyse</button>
<?php if ($focusUid || $days != MultiAccount::WINDOW_DAYS || $minScore != MultiAccount::MIN_REPORT_SCORE): ?>
<a class="reset" href="admin.php?p=multiacc">reset</a>
<?php endif; ?>
</form>
<?php if ($data['truncated']): ?>
<div class="mad-warn">
Row cap reached while scanning login history (window is large / very busy server).
Results still valid but may be incomplete &mdash; narrow the window for full coverage.
</div>
<?php endif; ?>
<div class="mad-meta">
Window: last <?php echo (int)$data['window_days']; ?> days &nbsp;|&nbsp;
scanned <?php echo (int)$data['scanned']['login_log']; ?> login-log +
<?php echo (int)$data['scanned']['mad_session']; ?> fingerprint rows &nbsp;|&nbsp;
<?php echo count($pairs); ?> suspicious pair<?php echo count($pairs) == 1 ? '' : 's'; ?>
<?php if ($focusUid): ?>&nbsp;|&nbsp;focused on UID <?php echo (int)$focusUid; ?><?php endif; ?>
</div>
<?php if (empty($pairs)): ?>
<div class="mad-table"><div class="mad-empty">
No account pairs at or above the current score threshold.<br>
<?php if ((int)$data['scanned']['mad_session'] === 0): ?>
Tip: the User-Agent signal starts filling in only after players log in
once with this feature deployed. IP &amp; login-time signals work on
existing history immediately.
<?php else: ?>
Try lowering the minimum score or widening the window.
<?php endif; ?>
</div></div>
<?php else: ?>
<table class="mad-table">
<thead>
<tr>
<th style="width:80px;">Risk</th>
<th>Account A</th>
<th>Account B</th>
<th style="width:44%;">Why</th>
</tr>
</thead>
<tbody>
<?php foreach ($pairs as $p):
$cls = $p['label'] === 'High' ? 'b-high' : ($p['label'] === 'Medium' ? 'b-med' : 'b-low');
$barColor = $p['label'] === 'High' ? '#ef4444' : ($p['label'] === 'Medium' ? '#f59e0b' : '#3b82f6');
?>
<tr>
<td>
<div class="mad-score" style="color:<?php echo $barColor; ?>;"><?php echo (int)$p['score']; ?></div>
<span class="badge <?php echo $cls; ?>"><?php echo e($p['label']); ?></span>
<div class="mad-bar"><i style="width:<?php echo (int)$p['score']; ?>%;background:<?php echo $barColor; ?>;"></i></div>
</td>
<td class="mad-acc">
<a href="admin.php?p=player&uid=<?php echo (int)$p['uid_a']; ?>"><?php echo e($p['name_a']); ?></a>
<span class="uid">#<?php echo (int)$p['uid_a']; ?></span>
<span class="sub">
<a href="admin.php?p=userlogin&uid=<?php echo (int)$p['uid_a']; ?>">login log</a>
<a href="admin.php?p=multiacc&focus=<?php echo (int)$p['uid_a']; ?>">focus</a>
</span>
</td>
<td class="mad-acc">
<a href="admin.php?p=player&uid=<?php echo (int)$p['uid_b']; ?>"><?php echo e($p['name_b']); ?></a>
<span class="uid">#<?php echo (int)$p['uid_b']; ?></span>
<span class="sub">
<a href="admin.php?p=userlogin&uid=<?php echo (int)$p['uid_b']; ?>">login log</a>
<a href="admin.php?p=multiacc&focus=<?php echo (int)$p['uid_b']; ?>">focus</a>
</span>
</td>
<td class="chips">
<?php foreach ($p['reasons'] as $r): ?>
<span><?php echo e($r); ?></span>
<?php endforeach; ?>
<?php if (!empty($p['shared_ip_list'])): ?>
<div style="margin-top:5px;color:#475569;font-size:10px;">
IPs: <?php echo e(implode(', ', $p['shared_ip_list'])); ?>
</div>
<?php endif; ?>
<?php if ($p['trade_gross'] > 0): ?>
<div style="margin-top:3px;color:#475569;font-size:10px;">
transfer volume: <?php echo number_format((int)$p['trade_gross']); ?> res
<?php echo $p['trade_dir'] ? '(one-directional)' : '(two-way)'; ?>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
+170
View File
@@ -0,0 +1,170 @@
<?php
#################################################################################
## Filename : Admin/Templates/pushprot.tpl ##
## Type : Admin page - Push Protection dashboard ##
## Project : TravianZ ##
## License : TravianZ Project ##
#################################################################################
if (!isset($_SESSION['access']) || $_SESSION['access'] < MULTIHUNTER) {
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
return;
}
$days = isset($_GET['days']) && ctype_digit((string)$_GET['days']) ? max(1, min(30, (int)$_GET['days'])) : PushProtection::WINDOW_DAYS;
$hours = isset($_GET['hours']) && ctype_digit((string)$_GET['hours']) ? max(1, min(168, (int)$_GET['hours'])): PushProtection::HOURS_ALLOWED;
$only = isset($_GET['only']) && in_array($_GET['only'], ['all','over','flagged'], true) ? $_GET['only'] : 'all';
$data = PushProtection::dashboard(['days' => $days, 'hours' => $hours, 'only' => $only]);
$rows = $data['rows'];
function pp_num($n) { return number_format((int)$n); }
?>
<style>
.pp-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
.pp-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
.pp-wrap h2 span{color:#f59e0b;}
.pp-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:860px;line-height:1.5;}
.pp-filter{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:12px 14px;display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end;margin-bottom:14px;}
.pp-filter label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:#94a3b8;margin-bottom:4px;}
.pp-filter input,.pp-filter select{background:#0b1220;border:1px solid #334155;border-radius:6px;color:#e2e8f0;padding:6px 8px;}
.pp-filter input{width:90px;}
.pp-filter button{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:8px 16px;cursor:pointer;}
.pp-meta{color:#64748b;font-size:11px;margin-bottom:10px;}
.pp-table{width:100%;border-collapse:collapse;background:#0b1220;border:1px solid #1f2937;border-radius:8px;overflow:hidden;}
.pp-table th{background:#111827;text-align:left;padding:9px 10px;font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:#94a3b8;border-bottom:1px solid #1f2937;}
.pp-table td{padding:9px 10px;border-bottom:1px solid #14203a;vertical-align:top;}
.pp-table tr:hover td{background:#0f1a30;}
.pp-acc a{color:#e2e8f0;text-decoration:none;font-weight:bold;}
.pp-acc a:hover{color:#f59e0b;}
.pp-acc .uid{color:#475569;font-weight:normal;font-size:10px;display:block;}
.badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:.4px;}
.s-over{background:#7f1d1d;color:#fecaca;}
.s-near{background:#78350f;color:#fde68a;}
.s-ok{background:#14532d;color:#bbf7d0;}
.s-exempt{background:#1e3a5f;color:#bfdbfe;}
.flag{display:inline-block;background:#334155;color:#e2e8f0;border-radius:4px;padding:1px 6px;font-size:9px;margin:2px 3px 0 0;text-transform:uppercase;letter-spacing:.4px;}
.flag.ww{background:#5b21b6;color:#ede9fe;}
.flag.arte{background:#0e7490;color:#cffafe;}
.pp-bar{height:6px;background:#1e293b;border-radius:3px;margin-top:4px;overflow:hidden;width:120px;}
.pp-bar i{display:block;height:100%;}
.pp-ov{display:flex;gap:5px;align-items:center;flex-wrap:wrap;}
.pp-ov select,.pp-ov input{background:#0b1220;border:1px solid #334155;border-radius:5px;color:#e2e8f0;padding:4px 6px;font-size:11px;}
.pp-ov input.lim{width:90px;}
.pp-ov input.note{width:120px;}
.pp-ov button{background:#334155;color:#fff;border:0;border-radius:5px;padding:5px 10px;font-size:11px;cursor:pointer;}
.pp-ov button:hover{background:#f59e0b;color:#111827;}
.pp-cur{font-size:10px;color:#94a3b8;display:block;margin-bottom:3px;}
.pp-empty{padding:26px;text-align:center;color:#64748b;}
.num{font-variant-numeric:tabular-nums;}
</style>
<div class="pp-wrap">
<h2>Push Protection <span>Dashboard</span></h2>
<p class="pp-intro">
Per-player <b>7-day resource balance</b> (received from other players) versus an
automatic limit derived from the player's hourly production
(<span class="num"><?php echo (int)$data['hours_allowed']; ?>h</span> of production per window).
WW villages and artefact villages are flagged as supply exceptions. Set a manual
override to exempt a player (WW / trusted) or give a custom cap. Nothing is blocked
automatically &mdash; this is visibility &amp; control for a human moderator.
</p>
<form method="get" action="admin.php" class="pp-filter">
<input type="hidden" name="p" value="pushprot">
<div>
<label>Window (days)</label>
<input type="number" name="days" min="1" max="30" value="<?php echo (int)$days; ?>">
</div>
<div>
<label>Hours of prod. allowed</label>
<input type="number" name="hours" min="1" max="168" value="<?php echo (int)$hours; ?>">
</div>
<div>
<label>Show</label>
<select name="only">
<option value="all" <?php echo $only==='all'?'selected':''; ?>>All with activity</option>
<option value="over" <?php echo $only==='over'?'selected':''; ?>>Over limit only</option>
<option value="flagged" <?php echo $only==='flagged'?'selected':''; ?>>WW / artefact / overridden</option>
</select>
</div>
<button type="submit">Refresh</button>
</form>
<div class="pp-meta">
Window: last <?php echo (int)$data['window_days']; ?> days &nbsp;|&nbsp;
limit = <?php echo (int)$data['hours_allowed']; ?>h &times; hourly production &nbsp;|&nbsp;
<?php echo count($rows); ?> player<?php echo count($rows)==1?'':'s'; ?> shown
</div>
<?php if (empty($rows)): ?>
<div class="pp-table"><div class="pp-empty">
No inter-player transfers recorded in this window yet.<br>
The 7-day balance fills in as merchant deliveries between different players
are processed after this feature is deployed.
</div></div>
<?php else: ?>
<table class="pp-table">
<thead>
<tr>
<th>Player</th>
<th>Villages / Pop</th>
<th>Prod/h</th>
<th>Received (7d)</th>
<th>Limit</th>
<th>Usage</th>
<th style="width:26%;">Override</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $r):
$sCls = $r['status']==='Over' ? 's-over' : ($r['status']==='Near' ? 's-near' : ($r['status']==='Exempt' ? 's-exempt' : 's-ok'));
$barCol = $r['status']==='Over' ? '#ef4444' : ($r['status']==='Near' ? '#f59e0b' : ($r['status']==='Exempt' ? '#3b82f6' : '#22c55e'));
$barW = $r['eff_limit']==-1 ? 100 : min(100, (int)$r['pct']);
?>
<tr>
<td class="pp-acc">
<a href="admin.php?p=player&uid=<?php echo (int)$r['uid']; ?>"><?php echo e($r['name']); ?></a>
<span class="uid">#<?php echo (int)$r['uid']; ?></span>
<?php foreach ($r['flags'] as $fl): ?>
<span class="flag <?php echo stripos($fl,'WW')!==false?'ww':'arte'; ?>"><?php echo e($fl); ?></span>
<?php endforeach; ?>
</td>
<td class="num"><?php echo (int)$r['villages']; ?> / <?php echo pp_num($r['pop']); ?></td>
<td class="num"><?php echo pp_num($r['prod_h']); ?></td>
<td class="num">
<?php echo pp_num($r['received']); ?>
<span style="color:#64748b;font-size:10px;">from <?php echo (int)$r['senders']; ?></span>
</td>
<td class="num">
<?php echo $r['eff_limit']==-1 ? '<span style="color:#93c5fd;">unlimited</span>' : pp_num($r['eff_limit']); ?>
<?php if ($r['ov_label']): ?><span style="color:#64748b;font-size:10px;display:block;"><?php echo e($r['ov_label']); ?></span><?php endif; ?>
</td>
<td>
<span class="badge <?php echo $sCls; ?>"><?php echo e($r['status']); ?></span>
<?php if ($r['eff_limit']!=-1): ?>
<div style="font-size:10px;color:#94a3b8;margin-top:3px;"><?php echo (int)$r['pct']; ?>%</div>
<?php endif; ?>
<div class="pp-bar"><i style="width:<?php echo (int)$barW; ?>%;background:<?php echo $barCol; ?>;"></i></div>
</td>
<td>
<?php if ($r['ov_note']): ?><span class="pp-cur">note: <?php echo e($r['ov_note']); ?></span><?php endif; ?>
<form method="post" action="../GameEngine/Admin/Mods/pushOverride.php" class="pp-ov">
<?php echo csrf_field(); ?>
<input type="hidden" name="uid" value="<?php echo (int)$r['uid']; ?>">
<select name="mode">
<option value="0" <?php echo $r['ov_mode']==0?'selected':''; ?>>Auto</option>
<option value="1" <?php echo $r['ov_mode']==1?'selected':''; ?>>Exempt<?php echo $r['is_ww']?' (WW)':''; ?></option>
<option value="3" <?php echo $r['ov_mode']==3?'selected':''; ?>>Custom cap</option>
</select>
<input class="lim num" type="number" min="0" name="custom_limit" placeholder="cap" value="<?php echo $r['ov_mode']==3 && $r['eff_limit']>0 ? (int)$r['eff_limit'] : ''; ?>">
<input class="note" type="text" name="note" maxlength="255" placeholder="note" value="<?php echo e($r['ov_note']); ?>">
<button type="submit">Save</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
+16
View File
@@ -42,6 +42,8 @@ include_once("../GameEngine/Lang/" . LANG . ".php");
include_once("../GameEngine/Admin/database.php");
include_once("../GameEngine/Data/buidata.php");
include_once("../GameEngine/Artifacts.php");
include_once("../GameEngine/MultiAccount.php");
include_once("../GameEngine/PushProtection.php");
// ─── SECURITY HELPERS ────────────────────────────────────────────────────────
@@ -95,6 +97,8 @@ function admin_validated_page(string $raw): string
'village', 'editResources', 'addTroops', 'addABTroops', 'editVillage',
'villagelog', 'techlog', 'msg',
'alliance', 'editAli', 'delAli','editNewFunctions',
'multiacc',
'pushprot',
];
return in_array($raw, $whitelist, true) ? $raw : '';
@@ -169,6 +173,14 @@ if ($page !== '') {
$subpage = 'Search IGMs/Reports';
break;
case 'multiacc':
$subpage = 'Multi-Account Detection';
break;
case 'pushprot':
$subpage = 'Push Protection';
break;
case 'massmessage':
$subpage = 'Mass Message';
break;
@@ -847,6 +859,8 @@ body.app #menu li.sub ul li a:hover{color:#d97706!important}
<li class="sub"><a href="#">Admin</a>
<ul>
<li><a href="?p=admin_log"><font color="Red"><b>Admin Log</b></font></a></li>
<li><a href="?p=multiacc"><font color="Red"><b>Multi-Account Detection</b></font></a></li>
<li><a href="?p=pushprot"><font color="Red"><b>Push Protection</b></font></a></li>
<li><a href="?p=debug_log">Debug Error Log</a></li>
<li><a href="?p=config">Server Settings</a></li>
<li><a href="?p=maintenance">Server Maintenance</a></li>
@@ -866,6 +880,8 @@ body.app #menu li.sub ul li a:hover{color:#d97706!important}
<li><a href="?p=search">Search</a></li>
<li><a href="?p=message">Msg/Rep</a></li>
<li><a href="?p=ban">Ban</a></li>
<li><a href="?p=multiacc">Multi-Account Detection</a></li>
<li><a href="?p=pushprot">Push Protection</a></li>
<li><a href="?action=logout">Logout</a></li>
</ul>