mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-07-24 05:26:19 +00:00
Some full fixes before final v11 release
Some full fixes before final v11 release
This commit is contained in:
@@ -49,6 +49,7 @@ include_once("Database.php");
|
||||
include_once("Data/buidata.php");
|
||||
include_once("Data/unitdata.php");
|
||||
include_once("Data/hero_full.php");
|
||||
include_once("Data/cp.php");
|
||||
include_once("Units.php");
|
||||
include_once("Battle.php");
|
||||
include_once("Technology.php");
|
||||
|
||||
@@ -329,6 +329,10 @@ trait AutomationAccountMaintenance {
|
||||
$database->cacheResourceLevels(array_keys($vilIDs));
|
||||
|
||||
foreach($villages as $village){
|
||||
// HOTFIX warning "$attri undefined": $attri se seteaza doar daca satul are
|
||||
// un camp tip 18 (Stonemason); fara initializare, valoarea "scapa" din satul
|
||||
// anterior (rezultatul final era acelasi, fiind un max, dar cu warning in log)
|
||||
$attri = 0;
|
||||
$field = $database->getResourceLevel($village['wref'], false);
|
||||
for($i = 19; $i <= 40; $i++){
|
||||
if($field['f'.$i.'t'] == 18){
|
||||
|
||||
@@ -495,9 +495,14 @@ trait AutomationBattleResolution {
|
||||
$expArray = $database->getVillageFields($from['wref'], 'exp1, exp2, exp3');
|
||||
$villexp = ($expArray['exp1'] == 0) ? 0 : (($expArray['exp2'] == 0) ? 1 : (($expArray['exp3'] == 0) ? 2 : 3));
|
||||
|
||||
// HOTFIX "$cp0 undefined" (acelasi tipar ca FIX U1 din Units.php): tabelele $cp0..$cpN
|
||||
// vin din Data/cp.php, incarcat pana acum doar de Session.php - deci pe traseul de CRON
|
||||
// (fara Session) verificarea de CP la cucerire era OCOLITA silentios. Data/cp.php e
|
||||
// acum inclus si in Automation.php; gardul ?? PHP_INT_MAX ramane fail-closed daca
|
||||
// tabelul lipseste totusi (fara date de CP nu se poate cuceri), identic cu Settlers().
|
||||
$mode = CP;
|
||||
$cp_mode = $GLOBALS['cp' . $mode];
|
||||
$need_cps = $cp_mode[count($varray1) + 1];
|
||||
$cp_mode = $GLOBALS['cp' . $mode] ?? [];
|
||||
$need_cps = $cp_mode[count($varray1) + 1] ?? PHP_INT_MAX;
|
||||
$user_cps = $database->getUserArray($from['owner'], 1)['cp'];
|
||||
|
||||
if ($user_cps < $need_cps) {
|
||||
|
||||
@@ -323,50 +323,81 @@ trait AutomationVillageUpkeep {
|
||||
private function updateStore() {
|
||||
global $database, $bid10, $bid38, $bid11, $bid39;
|
||||
|
||||
$result = mysqli_query($database->dblink, 'SELECT * FROM `' . TB_PREFIX . 'fdata`');
|
||||
// HOTFIX deadlock (log 20-23 iul): rutina scria toata vdata intr-o SINGURA
|
||||
// tranzactie lunga, tinand lock-uri pe multe randuri => coliziuni fatale cu
|
||||
// scrierile jucatorilor. Doua schimbari: (1) commit in transe de 200 de randuri
|
||||
// (ferestre de lock scurte), (2) reincercare de maximum 3 ori la deadlock / lock
|
||||
// timeout. Rutina e idempotenta (recalculeaza maxstore/maxcrop de la zero), deci
|
||||
// o rulare partiala e inofensiva - urmatorul tick o completeaza.
|
||||
for ($attempt = 1; $attempt <= 3; $attempt++) {
|
||||
try {
|
||||
$result = mysqli_query($database->dblink, 'SELECT * FROM `' . TB_PREFIX . 'fdata`');
|
||||
|
||||
mysqli_begin_transaction($database->dblink);
|
||||
while ($row = mysqli_fetch_assoc($result))
|
||||
{
|
||||
$ress = $crop = 0;
|
||||
for ($i = 19; $i < 40; ++$i)
|
||||
{
|
||||
//Warehouse
|
||||
if ($row['f' . $i . 't'] == 10)
|
||||
$pending = 0;
|
||||
mysqli_begin_transaction($database->dblink);
|
||||
while ($row = mysqli_fetch_assoc($result))
|
||||
{
|
||||
$ress += ((isset($bid10[$row['f' . $i]]) && isset($bid10[$row['f' . $i]]['attri'])) ? $bid10[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
$ress = $crop = 0;
|
||||
for ($i = 19; $i < 40; ++$i)
|
||||
{
|
||||
//Warehouse
|
||||
if ($row['f' . $i . 't'] == 10)
|
||||
{
|
||||
$ress += ((isset($bid10[$row['f' . $i]]) && isset($bid10[$row['f' . $i]]['attri'])) ? $bid10[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Great warehouse
|
||||
if ($row['f' . $i . 't'] == 38)
|
||||
{
|
||||
$ress += ((isset($bid38[$row['f' . $i]]) && isset($bid38[$row['f' . $i]]['attri'])) ? $bid38[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
//Great warehouse
|
||||
if ($row['f' . $i . 't'] == 38)
|
||||
{
|
||||
$ress += ((isset($bid38[$row['f' . $i]]) && isset($bid38[$row['f' . $i]]['attri'])) ? $bid38[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Granary
|
||||
if ($row['f' . $i . 't'] == 11)
|
||||
{
|
||||
$crop += ((isset($bid11[$row['f' . $i]]) && isset($bid11[$row['f' . $i]]['attri'])) ? $bid11[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
//Granary
|
||||
if ($row['f' . $i . 't'] == 11)
|
||||
{
|
||||
$crop += ((isset($bid11[$row['f' . $i]]) && isset($bid11[$row['f' . $i]]['attri'])) ? $bid11[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Great granary
|
||||
if ($row['f' . $i . 't'] == 39)
|
||||
{
|
||||
$crop += ((isset($bid39[$row['f' . $i]]) && isset($bid39[$row['f' . $i]]['attri'])) ? $bid39[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
//Great granary
|
||||
if ($row['f' . $i . 't'] == 39)
|
||||
{
|
||||
$crop += ((isset($bid39[$row['f' . $i]]) && isset($bid39[$row['f' . $i]]['attri'])) ? $bid39[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// no need for update, since we didn't find any warehouses or granaries
|
||||
// and maximums would have been set to correct values inside prune* functions already
|
||||
if ($ress == 0 && $crop == 0) continue;
|
||||
|
||||
// maxstore nor maxcrop can go below the minimum threshold
|
||||
if ($ress < STORAGE_BASE) $ress = STORAGE_BASE;
|
||||
if ($crop < STORAGE_BASE) $crop = STORAGE_BASE;
|
||||
|
||||
mysqli_query($database->dblink,'UPDATE `' . TB_PREFIX . 'vdata` SET `maxstore` = ' . (int) $ress . ', `maxcrop` = ' . (int) $crop . ' WHERE `wref` = ' . (int) $row['vref']);
|
||||
|
||||
// commit in transe: tranzactii scurte = ferestre de lock mici
|
||||
if (++$pending >= 200) {
|
||||
mysqli_commit($database->dblink);
|
||||
mysqli_begin_transaction($database->dblink);
|
||||
$pending = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no need for update, since we didn't find any warehouses or granaries
|
||||
// and maximums would have been set to correct values inside prune* functions already
|
||||
if ($ress == 0 && $crop == 0) continue;
|
||||
|
||||
// maxstore nor maxcrop can go below the minimum threshold
|
||||
if ($ress < STORAGE_BASE) $ress = STORAGE_BASE;
|
||||
if ($crop < STORAGE_BASE) $crop = STORAGE_BASE;
|
||||
|
||||
mysqli_query($database->dblink,'UPDATE `' . TB_PREFIX . 'vdata` SET `maxstore` = ' . (int) $ress . ', `maxcrop` = ' . (int) $crop . ' WHERE `wref` = ' . (int) $row['vref']);
|
||||
}
|
||||
mysqli_commit($database->dblink);
|
||||
return;
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
if (!in_array((int) $e->getCode(), [1213, 1205], true)) {
|
||||
throw $e; // orice alta eroare ramane fatala, ca inainte
|
||||
}
|
||||
try { mysqli_rollback($database->dblink); } catch (mysqli_sql_exception $ignored) {}
|
||||
if ($attempt === 3) {
|
||||
// dupa 3 incercari renuntam la ACEST tick fara sa-l omoram;
|
||||
// urmatorul tick reia calculul de la zero
|
||||
error_log('Automation::updateStore: deadlock persistent dupa 3 incercari, amanat pentru tick-ul urmator');
|
||||
return;
|
||||
}
|
||||
usleep(150000 * $attempt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function regenerateOasisTroops() {
|
||||
|
||||
@@ -341,7 +341,14 @@ trait DatabaseBuildingQueries {
|
||||
*/
|
||||
|
||||
function modifyBData($wid, $field, $levels, $tribe){
|
||||
list($wid, $field, $levels, $tribe) = $this->escape_input((int) $wid, (int) $field, (int) $levels, (int) $tribe);
|
||||
// HOTFIX "array offset on int": $levels e un ARRAY [nivelNou, nivelVechi] (singurul
|
||||
// apel: AutomationBattleResolution, dupa lovitura de catapulte). Cast-ul (int) de aici
|
||||
// il transforma in 1, deci $levels[0] era null, "null == 0" era mereu TRUE si ramura
|
||||
// else (ajustarea nivelului comenzilor din coada) era COD MORT - comenzile de
|
||||
// constructie erau sterse mereu, chiar daca cladirea nu ajungea la nivelul 0.
|
||||
// Pastram cast-ul pe celelalte argumente; elementele lui $levels devin int (SQL-safe).
|
||||
list($wid, $field, $tribe) = $this->escape_input((int) $wid, (int) $field, (int) $tribe);
|
||||
$levels = array_map('intval', is_array($levels) ? $levels : [$levels, 0]);
|
||||
|
||||
if($levels[0] == 0){
|
||||
$q = "SELECT id FROM " .TB_PREFIX. "bdata WHERE wid = $wid AND field = $field";
|
||||
|
||||
@@ -271,7 +271,24 @@ trait DatabaseConnectionCore {
|
||||
function query($query) {
|
||||
// REFACTORIZAT: contorizare centralizată
|
||||
$this->countQueryType($query);
|
||||
return mysqli_query($this->dblink,$query);
|
||||
|
||||
// HOTFIX deadlock (log 20-23 iul): pe PHP 8.1+ mysqli arunca mysqli_sql_exception,
|
||||
// deci un deadlock InnoDB (1213) / lock wait timeout (1205) omora tot tick-ul de
|
||||
// automation. Reincercam de maximum 3 ori cu pauza crescatoare; orice alta eroare
|
||||
// se arunca mai departe neschimbata. Sigur fata de tranzactii: singurele tranzactii
|
||||
// explicite din cod (updateStore, populateWorldData) folosesc mysqli_query direct,
|
||||
// nu metoda aceasta - verificat pe tot repo-ul.
|
||||
$attempt = 0;
|
||||
while (true) {
|
||||
try {
|
||||
return mysqli_query($this->dblink, $query);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
if (!in_array((int) $e->getCode(), [1213, 1205], true) || ++$attempt >= 3) {
|
||||
throw $e;
|
||||
}
|
||||
usleep(150000 * $attempt); // 150ms, apoi 300ms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function RemoveXSS($val) {
|
||||
|
||||
@@ -1846,18 +1846,26 @@ trait DatabaseVillageQueries {
|
||||
// clear expansion slots, if this village is an expansion of any other village
|
||||
$this->clearExpansionSlot($wref, 1);
|
||||
|
||||
// HOTFIX warning-uri t1..t11/wref/id: pe calea cu array + cache plin,
|
||||
// getPrisoners() intoarce INTREGUL cache (inclusiv intrari goale [] pentru
|
||||
// sate fara prizonieri), nu doar satele cerute - de aici cheile lipsa.
|
||||
// Gardam randurile incomplete; pentru randurile valide comportamentul e identic.
|
||||
// ANOMALIE de urmarit separat: "return self::$prisonersCache" din getPrisoners()
|
||||
// poate livra si prizonierii ALTOR sate decat cele cerute.
|
||||
$getprisoners = $this->getPrisoners($wref);
|
||||
foreach($getprisoners as $pris) {
|
||||
if (!is_array($pris) || !isset($pris['wref'], $pris['id'])) continue;
|
||||
$troops = 0;
|
||||
for($i = 1; $i < 12; $i++) $troops += $pris['t'.$i];
|
||||
for($i = 1; $i < 12; $i++) $troops += (int) ($pris['t'.$i] ?? 0);
|
||||
$this->modifyUnit($pris['wref'], ["99o"], [$troops], [0]);
|
||||
$this->deletePrisoners($pris['id']);
|
||||
}
|
||||
|
||||
$getprisoners = $this->getPrisoners($wref, 1);
|
||||
foreach($getprisoners as $pris) {
|
||||
if (!is_array($pris) || !isset($pris['wref'], $pris['id'])) continue;
|
||||
$troops = 0;
|
||||
for($i = 1; $i < 12; $i++) $troops += $pris['t'.$i];
|
||||
for($i = 1; $i < 12; $i++) $troops += (int) ($pris['t'.$i] ?? 0);
|
||||
$this->modifyUnit($pris['wref'], ["99o"], [$troops], [0]);
|
||||
$this->deletePrisoners($pris['id']);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user