mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-09-04 09:27:17 +00:00
Some hot fixes!!!
Some hot fixes!!!
This commit is contained in:
@@ -86,10 +86,6 @@ trait AutomationAccountMaintenance {
|
||||
|
||||
if(AUTO_DEL_INACTIVE) {
|
||||
$time = time() - UN_ACT_TIME;
|
||||
|
||||
// BUG REPARAT: lista era 1,2,3 - conturile inactive ale triburilor noi
|
||||
// (huni, egipteni, spartani, vikingi) nu se stergeau niciodata si
|
||||
// ramaneau pe harta la nesfarsit.
|
||||
$q = "INSERT INTO ".TB_PREFIX."deleting SELECT id, UNIX_TIMESTAMP() FROM ".TB_PREFIX."users WHERE timestamp < $time AND tribe IN(1, 2, 3, 6, 7, 8, 9)";
|
||||
$database->query($q);
|
||||
}
|
||||
@@ -324,9 +320,6 @@ 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++){
|
||||
|
||||
@@ -70,10 +70,10 @@ trait AutomationBattleResolution {
|
||||
|
||||
// update all that needs updating
|
||||
$database->setVillageLevel($data['to'], $fieldsToSet, $fieldValuesToSet);
|
||||
|
||||
$buildarray = $GLOBALS["bid".$tbgid];
|
||||
|
||||
$buildarray = $GLOBALS["bid".$tbgid] ?? null;
|
||||
|
||||
if ( isset( $buildarray[$newLevel] ) ) {
|
||||
if ( is_array($buildarray) && isset( $buildarray[$newLevel] ) ) {
|
||||
// (great) warehouse level was changed
|
||||
if ($tbgid == 10 || $tbgid == 38) {
|
||||
$database->setMaxStoreForVillage($data['to'], $buildarray[$newLevel]['attri']);
|
||||
@@ -317,13 +317,6 @@ trait AutomationBattleResolution {
|
||||
if ($i == 41) $i = 99;
|
||||
if ($bdo['f'.$i] > 0 && $i != 40) $list[] = $i;
|
||||
}
|
||||
// FIX (PHP log): daca $list e gol (niciun target alternativ
|
||||
// cu nivel>0), rand(0, count($list)-1) devine rand(0,-1).
|
||||
// PHP NU arunca eroare aici (verificat pe 8.3) - intoarce
|
||||
// pseudo-random 0 sau -1, ambele chei inexistente in $list,
|
||||
// deci "Undefined array key -1"/0 si $catapultTarget2=null.
|
||||
// Pastram fallback-ul 99 folosit deja mai sus (linia ~301)
|
||||
// pentru cazul "niciun target gasit".
|
||||
if (!empty($list)) {
|
||||
$catapultTarget2 = $list[ rand(0, count($list) - 1) ];
|
||||
} else {
|
||||
@@ -630,11 +623,6 @@ 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] ?? PHP_INT_MAX;
|
||||
@@ -672,11 +660,6 @@ trait AutomationBattleResolution {
|
||||
|
||||
$reducedLoyalty /= $battlepart['moralBonus'];
|
||||
|
||||
// Bug fix: Brewery (35) is capital-only but empire-wide — its effect
|
||||
// must be checked on the attacker's CAPITAL, not on $data['from'] (the
|
||||
// launching village, which may not be the capital at all), and only
|
||||
// while a Mead-Festival is actually active there, not just because
|
||||
// the Brewery has been built (it has no permanent effect).
|
||||
if ($owntribe == 2) {
|
||||
$attackerCapital = $database->getVillage($from['owner'], 3);
|
||||
if ($attackerCapital && (int)$attackerCapital['festival'] > $time && $this->getTypeLevel(35, $attackerCapital['wref']) > 0) {
|
||||
@@ -709,14 +692,6 @@ trait AutomationBattleResolution {
|
||||
|
||||
$database->setVillageFields($data['to'], ['loyalty', 'owner'], [0, $database->getVillageField($data['from'], 'owner')]);
|
||||
|
||||
// Milestones: first WW village ever conquered, and — separately —
|
||||
// first village ever conquered FROM ANOTHER PLAYER (not from
|
||||
// Natars). $to is this function's own parameter (not re-fetched),
|
||||
// so $to['natar']/$to['owner'] still reflect the village's state
|
||||
// from BEFORE this conquest, which is exactly what we need here.
|
||||
// natar==1 marks one of the 13 pre-built WW conquest targets (see
|
||||
// Artifacts::createWWVillages()) — Natars' capital and artifact/
|
||||
// plan villages are natar=0, so this check cannot misfire on those.
|
||||
if (defined('NEW_FUNCTIONS_MILESTONES') && NEW_FUNCTIONS_MILESTONES) {
|
||||
$newOwner = $database->getVillageField($data['from'], 'owner');
|
||||
if ((int)($to['natar'] ?? 0) === 1) {
|
||||
@@ -1241,25 +1216,6 @@ trait AutomationBattleResolution {
|
||||
|
||||
if ($unitlist) {
|
||||
$owndead['hero'] = (isset($battlepart['deadherodef']) ? $battlepart['deadherodef'] : '');
|
||||
|
||||
/**
|
||||
* BUG FIXED (issue #379): units.hero ended up at -1.
|
||||
*
|
||||
* The value is still reported (it feeds the battle report and the
|
||||
* points), but it must NOT be subtracted from units.hero here any
|
||||
* more. Battle::applyHeroBattleDamage() already clears the column
|
||||
* itself ("UPDATE units u JOIN vdata v SET u.hero = 0 WHERE
|
||||
* v.owner = <hero owner>") the moment the hero dies, and that runs
|
||||
* inside calculateBattle(), i.e. BEFORE this method.
|
||||
*
|
||||
* So the column went 1 -> 0 there and 0 - 1 -> -1 here: the
|
||||
* village kept showing "-1 Hero" in the troop list while the
|
||||
* Hero's Mansion correctly offered a revive.
|
||||
*
|
||||
* One writer only: the death is owned by applyHeroBattleDamage(),
|
||||
* which is also the only place that knows about the hero's other
|
||||
* possible locations (reinforcements, another village).
|
||||
*/
|
||||
}
|
||||
|
||||
// modify units in DB
|
||||
@@ -1356,21 +1312,6 @@ trait AutomationBattleResolution {
|
||||
}
|
||||
|
||||
if ($enforce['hero'] > 0) {
|
||||
/**
|
||||
* BUG FIXED (issue #379), same double subtraction as in
|
||||
* applyOwnDefenceCasualties(): a reinforcement hero who died
|
||||
* was already removed by Battle::applyHeroBattleDamage()
|
||||
* ("UPDATE enforcement e JOIN vdata v SET e.hero = 0"), so
|
||||
* subtracting him again here drove enforcement.hero to -1.
|
||||
*
|
||||
* $enforce still reads 1 because getEnforceVillage() answers
|
||||
* from the request cache filled before the battle, so the
|
||||
* stale row hid the problem instead of preventing it.
|
||||
*
|
||||
* The dead count below is kept: it is what the reinforcement
|
||||
* report and $wrong (which decides whether the wiped-out
|
||||
* reinforcement row is deleted) are built from.
|
||||
*/
|
||||
$dead['hero'] = $battlepart['deadheroref'][$enforce['id']];
|
||||
$alldead['hero'] += $dead['hero'];
|
||||
$wrong = $dead['hero'] != $enforce['hero'];
|
||||
@@ -1832,19 +1773,19 @@ trait AutomationBattleResolution {
|
||||
global $database, $units;
|
||||
|
||||
$DefenderUserData = $this->getCachedUser($database->getVillageField($data['to'],"owner"),1);
|
||||
$DefenderID = $DefenderUserData["id"];
|
||||
$targettribe = $DefenderUserData["tribe"];
|
||||
$targetally = $DefenderUserData["alliance"];
|
||||
$DefenderID = $DefenderUserData["id"] ?? null;
|
||||
$targettribe = $DefenderUserData["tribe"] ?? null;
|
||||
$targetally = $DefenderUserData["alliance"] ?? null;
|
||||
$to = $database->getMInfo($data['to']);
|
||||
$toF = $database->getVillage($data['to']);
|
||||
$conqureby = 0;
|
||||
$NatarCapital = ($toF['owner'] == 3 && $toF['capital'] == 1);
|
||||
$NatarCapital = (($toF['owner'] ?? null) == 3 && ($toF['capital'] ?? null) == 1);
|
||||
if(!isset($to['name']) || empty($to['name'])) $to['name'] = "[?]";
|
||||
|
||||
$DefenderUnit = $database->getUnit($data['to']);
|
||||
$evasion = $toF["evasion"];
|
||||
$maxevasion = $DefenderUserData["maxevasion"];
|
||||
$gold = $DefenderUserData["gold"];
|
||||
$evasion = $toF["evasion"] ?? null;
|
||||
$maxevasion = $DefenderUserData["maxevasion"] ?? null;
|
||||
$gold = $DefenderUserData["gold"] ?? null;
|
||||
$cannotsend = false;
|
||||
|
||||
$movements = $database->getMovement(34, $data['to'], 1);
|
||||
@@ -2126,10 +2067,10 @@ trait AutomationBattleResolution {
|
||||
$this->pruneResource();
|
||||
|
||||
$villageData = $database->getVillageFields($conqureby, 'clay, iron, wood, crop', false);
|
||||
$totclay = intval($villageData['clay'] / 10);
|
||||
$totiron = intval($villageData['iron'] / 10);
|
||||
$totwood = intval($villageData['wood'] / 10);
|
||||
$totcrop = intval($villageData['crop'] / 10);
|
||||
$totclay = intval(($villageData['clay'] ?? 0) / 10);
|
||||
$totiron = intval(($villageData['iron'] ?? 0) / 10);
|
||||
$totwood = intval(($villageData['wood'] ?? 0) / 10);
|
||||
$totcrop = intval(($villageData['crop'] ?? 0) / 10);
|
||||
}else{
|
||||
// work out available resources.
|
||||
$this->updateORes($data['to']);
|
||||
@@ -2205,8 +2146,6 @@ trait AutomationBattleResolution {
|
||||
if ($canqured == 3 && $troopcount == 0) {
|
||||
if ($type == 3) {
|
||||
$Oloyaltybefore = intval($to['loyalty']);
|
||||
//$database->modifyOasisLoyalty($data['to']);
|
||||
//$OasisInfo = $database->getOasisInfo($data['to']);
|
||||
$Oloyaltynow = intval($database->modifyOasisLoyalty($data['to']));//intval($OasisInfo['loyalty']);
|
||||
$info_hero = $hero_pic.",".rc_tok('RC_HERO_REDUCED_OASIS_LOYALTY', $Oloyaltynow, $Oloyaltybefore).$xp;
|
||||
}
|
||||
@@ -2397,7 +2336,7 @@ trait AutomationBattleResolution {
|
||||
$database->modifyPointsAlly($targetally, 'RR', $totalstolentaken);
|
||||
$database->modifyPointsAlly($ownally, 'RR', $totalstolengain);
|
||||
}
|
||||
}else{ //fix by ronix if only 1 chief left to conqured - don't add with zero enforces
|
||||
}else{
|
||||
if($totalsend_att - ($totaldead_att + (isset($totaltraped_att) ? $totaltraped_att : 0)) > 1){
|
||||
$database->addEnforce2($data, $owntribe, $troopsdead[1], $troopsdead[2], $troopsdead[3], $troopsdead[4], $troopsdead[5], $troopsdead[6], $troopsdead[7], $troopsdead[8], $troopsdead[9], $troopsdead[10], $troopsdead[11]);
|
||||
}
|
||||
@@ -2524,21 +2463,8 @@ trait AutomationBattleResolution {
|
||||
$tblevel = $vt['tblevel'];
|
||||
$stonemason = $vt['stonemason'];
|
||||
|
||||
// Issue #298: the target village no longer exists — it was razed
|
||||
// either earlier in this same batch ($razedTargets), or in an
|
||||
// earlier tick whose still-in-flight follow-up waves DelVillage()
|
||||
// failed to bounce. getMInfo() then returns NULL vdata columns
|
||||
// ($to['wref'] is NULL), so resolving a battle here would fight a
|
||||
// phantom village and compute the return trip from NULL coordinates
|
||||
// — a bogus arrival time that strands the troops in an endless loop
|
||||
// (report against "[?]"). Bounce the whole army straight home
|
||||
// instead, exactly like DelVillage() does for in-flight attacks,
|
||||
// and mark the movement processed so it stops being re-fetched.
|
||||
if (isset($razedTargets[$data['to']]) || empty($to['wref'])) {
|
||||
// only own the bounce if DelVillage() hasn't already handled it
|
||||
// (setMovementProc() returns true only when it flips proc 0->1),
|
||||
// so we never create a duplicate return movement
|
||||
if ($this->setMovementProc($data['moveid'])) {
|
||||
if ($database->setMovementProc($data['moveid'])) {
|
||||
$bounceTime = $units->getWalkingTroopsTime($from['wref'], $data['to'], $from['owner'], $owntribe, $data, 1, 't');
|
||||
$bounceEnd = $database->getArtifactsValueInfluence($from['owner'], $from['wref'], 2, $bounceTime) + $AttackArrivalTime;
|
||||
$database->addMovement(4, $data['to'], $from['wref'], $data['ref'], $AttackArrivalTime, $bounceEnd);
|
||||
@@ -2566,7 +2492,8 @@ trait AutomationBattleResolution {
|
||||
$spy_pic = $atkUnits['spy_pic'];
|
||||
$hero_pic = $atkUnits['hero_pic'];
|
||||
|
||||
}else{ //It's an oasis
|
||||
}else{
|
||||
//It's an oasis
|
||||
// target + battle environment — extracted to resolveOasisTarget() [#155]
|
||||
$ot = $this->resolveOasisTarget($data, $dataarray, $data_num, $owntribe);
|
||||
$DefenderID = $ot['DefenderID'];
|
||||
@@ -2754,6 +2681,7 @@ trait AutomationBattleResolution {
|
||||
$alldead = [];
|
||||
|
||||
for($i = 1; $i <= 90; $i++) $alldead[$i] = 0;
|
||||
$alldead['hero'] = 0;
|
||||
|
||||
//kill own defence — extracted to applyOwnDefenceCasualties() [#155]
|
||||
$owndead = $this->applyOwnDefenceCasualties($data, $targettribe, $battlepart);
|
||||
@@ -2776,8 +2704,6 @@ trait AutomationBattleResolution {
|
||||
|
||||
if (empty($alldead['hero'])) $alldead['hero'] = 0;
|
||||
if (empty($owndead['hero'])) $owndead['hero'] = 0;
|
||||
// sursa autoritativa: rezultatul luptei (owndead['hero'] se poate pierde
|
||||
// pe unele cai de executie, iar raportul afisa eroul aparator ca viu)
|
||||
$deadhero = (int)(isset($battlepart['deadherodef']) && $battlepart['deadherodef'] > 0
|
||||
? $battlepart['deadherodef']
|
||||
: $owndead['hero']);
|
||||
@@ -2907,12 +2833,6 @@ trait AutomationBattleResolution {
|
||||
// delete the target village if it was destroyed — extracted to handleVillageDestruction() [#155]
|
||||
$this->handleVillageDestruction($village_destroyed, $can_destroy, $data, $to, $varray);
|
||||
|
||||
// remember the razed tile so any follow-up wave still queued in
|
||||
// this same batch bounces home instead of fighting a phantom
|
||||
// (now-deleted) village. Needed on top of the $to['wref'] check
|
||||
// because getMInfo() is cached: a same-batch wave would still see
|
||||
// the stale "alive" village row — see the guard right after
|
||||
// resolveVillageTarget() (issue #298).
|
||||
if ($village_destroyed == 1 && $can_destroy == 1) {
|
||||
$razedTargets[$data['to']] = true;
|
||||
}
|
||||
@@ -3104,6 +3024,8 @@ trait AutomationBattleResolution {
|
||||
// the gold-club +25% crop bonus (b4) keyed on the village owner.
|
||||
private function bountyGetResourceProd($resArray, $oasisNumber, $resourceType) {
|
||||
global $bid1, $bid2, $bid3, $bid4, $bid5, $bid6, $bid7, $bid8, $bid9, $database;
|
||||
|
||||
if (!is_array($resArray)) $resArray = [];
|
||||
|
||||
$prodBid = [1 => $bid1, 2 => $bid2, 3 => $bid3, 4 => $bid4][$resourceType];
|
||||
$boosterBid = [5 => $bid5, 6 => $bid6, 7 => $bid7, 8 => $bid8, 9 => $bid9];
|
||||
@@ -3114,8 +3036,9 @@ trait AutomationBattleResolution {
|
||||
$holders = [];
|
||||
$boosterLevels = array_fill_keys($boosterTypes, 0);
|
||||
for($i = 1; $i <= 38; $i++) {
|
||||
if($resArray['f'.$i.'t'] == $resourceType) $holders[] = 'f'.$i;
|
||||
if(isset($boosterLevels[$resArray['f'.$i.'t']])) $boosterLevels[$resArray['f'.$i.'t']] = $resArray['f'.$i];
|
||||
$fieldType = $resArray['f'.$i.'t'] ?? null;
|
||||
if($fieldType == $resourceType) $holders[] = 'f'.$i;
|
||||
if($fieldType !== null && isset($boosterLevels[$fieldType])) $boosterLevels[$fieldType] = $resArray['f'.$i] ?? 0;
|
||||
}
|
||||
|
||||
foreach($holders as $holder) $prod += $prodBid[$resArray[$holder]]['prod'];
|
||||
|
||||
@@ -219,13 +219,6 @@ trait AutomationBuildQueue {
|
||||
|
||||
$buildarray = $GLOBALS["bid".$type];
|
||||
|
||||
// FIX: capacitatea de depozitare se RECALCULEAZA din cladirile
|
||||
// ramase, dupa ce nivelul nou e scris mai jos. Scaderea de
|
||||
// dinainte lua `attri` al nivelului, dar `attri` e capacitatea
|
||||
// TOTALA la acel nivel (1200, 1700, 2300...), nu incrementul -
|
||||
// deci taia prea mult. Ignora si STORAGE_MULTIPLIER. Efectul era
|
||||
// ascuns de pragul STORAGE_BASE si "reparat" abia la urmatoarea
|
||||
// rulare a lui updateStore().
|
||||
$needsStorageRecalc = in_array($type, [10, 11, 38, 39]);
|
||||
|
||||
if ($level == 1) $clear = ",f".$vil['buildnumber']."t=0";
|
||||
|
||||
@@ -261,7 +261,12 @@ trait AutomationStarvation {
|
||||
}
|
||||
break;
|
||||
case 2: // own units
|
||||
$database->modifyUnit($starv['wref'], array_keys($killedUnits), array_values($killedUnits), [0]);
|
||||
// BUG FIXED: modifyUnit() indexes $array_mode[$i] per unit (no scalar
|
||||
// broadcast), but only one mode element was passed here regardless of how
|
||||
// many unit types starved -> "Undefined array key 1"/"2" whenever more than
|
||||
// one troop type died of starvation in the same tick. All deaths use mode 0
|
||||
// (subtract), so fill one 0 per unit - identical resulting SQL, no warning.
|
||||
$database->modifyUnit($starv['wref'], array_keys($killedUnits), array_values($killedUnits), array_fill(0, count($killedUnits), 0));
|
||||
break;
|
||||
case 3: // moving attacks.
|
||||
if($totalKilledUnits < $totalUnits){
|
||||
|
||||
@@ -353,6 +353,17 @@ trait AutomationVillageUpkeep {
|
||||
|
||||
//Get village infos
|
||||
$villageInfoArray = $database->getVillage($bountywid);
|
||||
|
||||
// BUG FIXED: $bountywid can be a village razed earlier in the same batch
|
||||
// (either the attack target itself, or the conqureby owner of a captured
|
||||
// oasis - both call updateRes() from AutomationBattleResolution.php).
|
||||
// getVillage() then returns null and every read below ('natar', 'pop',
|
||||
// 'lastupdate') threw "Trying to access array offset on null", cascading
|
||||
// into bountyGetResourceProd() with a null $resArray too. There is
|
||||
// nothing meaningful to update for a village that no longer exists, so
|
||||
// skip entirely - modifyResource()/updateVillage() below would just be
|
||||
// a harmless no-op UPDATE matching zero rows anyway.
|
||||
if (!is_array($villageInfoArray)) return;
|
||||
|
||||
//Get building and resource fields array
|
||||
$resArray = $database->getResourceLevel($bountywid, false);
|
||||
|
||||
@@ -278,12 +278,31 @@ trait DatabaseConnectionCore {
|
||||
// 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.
|
||||
//
|
||||
// HOTFIX "MySQL server has gone away" (log 1-3 sep, cod 2006/CR_SERVER_GONE_ERROR
|
||||
// sau 2013/CR_SERVER_LOST): conexiunea poate cadea intre tick-urile ciclului intern
|
||||
// al cron.php (pana la CRON_LOOP_SECONDS=300s), la fel de fatal pe PHP 8.1+. Cod
|
||||
// separat de cel de deadlock (reconectam, nu doar reincercam): $this->reconnect()
|
||||
// (deja existent in acest trait) inchide si redeschide $this->dblink inainte de a
|
||||
// repeta interogarea. Maxim 2 reconectari, dupa care aruncam eroarea mai departe.
|
||||
$attempt = 0;
|
||||
$reconnectAttempt = 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) {
|
||||
$code = (int) $e->getCode();
|
||||
|
||||
if (in_array($code, [2006, 2013], true)) {
|
||||
if (++$reconnectAttempt > 2) {
|
||||
throw $e;
|
||||
}
|
||||
$this->reconnect();
|
||||
usleep(150000 * $reconnectAttempt);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($code, [1213, 1205], true) || ++$attempt >= 3) {
|
||||
throw $e;
|
||||
}
|
||||
usleep(150000 * $attempt); // 150ms, apoi 300ms
|
||||
|
||||
@@ -692,7 +692,11 @@ trait DatabaseTroopQueries {
|
||||
|
||||
// return a single value
|
||||
if (!$array_passed) {
|
||||
self::$villageFromReinforcementsCache[$vid[0].$from[0]] = $result[0];
|
||||
// BUG FIXED: $result is empty (no reinforcement row for this vid/from
|
||||
// pair - a normal, common outcome) -> $result[0] doesn't exist ->
|
||||
// "Undefined array key 0". Null-coalesce; the cached value stays null
|
||||
// exactly as before, just without the warning on every miss.
|
||||
self::$villageFromReinforcementsCache[$vid[0].$from[0]] = $result[0] ?? null;
|
||||
} else {
|
||||
if ($result && count($result)) {
|
||||
foreach ( $result as $record ) {
|
||||
@@ -762,7 +766,13 @@ trait DatabaseTroopQueries {
|
||||
} else if ($mode == 3) {
|
||||
$q = "SELECT e.*,o.conqured,o.wref,o.high, o.owner as ownero, v.owner as ownerv FROM ".TB_PREFIX."enforcement as e LEFT JOIN ".TB_PREFIX."odata as o ON e.vref=o.wref LEFT JOIN ".TB_PREFIX."vdata as v ON e.from=v.wref where o.conqured IN(".implode(', ', $ref).") AND o.owner=v.owner";
|
||||
}
|
||||
$result = $this->mysqli_fetch_all(mysqli_query($this->dblink,$q));
|
||||
// BUG FIXED (fatal, log 3 sep): raw mysqli_query() here bypassed $this->query(),
|
||||
// the only place with retry/reconnect logic - when the connection drops between
|
||||
// cron.php's internal ticks (cod 2006/2013, "MySQL server has gone away"), this
|
||||
// call threw an uncaught mysqli_sql_exception straight from Technology::getUpkeep(),
|
||||
// killing the whole automation tick. Routed through $this->query() (identical
|
||||
// return value) so it now benefits from the reconnect-and-retry added there.
|
||||
$result = $this->mysqli_fetch_all($this->query($q));
|
||||
|
||||
// return a single value
|
||||
if (!$array_passed) {
|
||||
@@ -897,6 +907,20 @@ trait DatabaseTroopQueries {
|
||||
$mode = [(int) $mode];
|
||||
}
|
||||
|
||||
// BUG FIXED: this only normalized $amt/$mode into arrays when $unit itself
|
||||
// wasn't one. AutomationStarvation.php calls this with $unit/$amt as arrays
|
||||
// (array_keys/array_values($killedUnits)) but $mode as a bare scalar (0,
|
||||
// meaning "subtract, for all of them") - $mode stayed an int, so
|
||||
// "(int) $mode[$index]" below tried to array-offset an int ("Trying to
|
||||
// access array offset on int"). Broadcast a scalar $amt/$mode to match
|
||||
// $unit's length; already-matching arrays are left untouched.
|
||||
if (!is_array($amt)) {
|
||||
$amt = array_fill(0, count($unit), (int) $amt);
|
||||
}
|
||||
if (!is_array($mode)) {
|
||||
$mode = array_fill(0, count($unit), (int) $mode);
|
||||
}
|
||||
|
||||
foreach ($unit as $index => $unitType) {
|
||||
$unitType = ($unitType != 'hero' ? 'u' . $this->escape($unitType) : $unitType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user